2940
2940
void MathPowStub::Generate(MacroAssembler* masm) {
2941
// Registers are used as follows:
2944
// ecx = temporary, result
2946
2941
CpuFeatures::Scope use_sse2(SSE2);
2947
Label allocate_return, call_runtime;
2949
// Load input parameters.
2950
__ mov(edx, Operand(esp, 2 * kPointerSize));
2951
__ mov(eax, Operand(esp, 1 * kPointerSize));
2953
// Save 1 in xmm3 - we need this several times later on.
2954
__ mov(ecx, Immediate(1));
2955
__ cvtsi2sd(xmm3, ecx);
2957
Label exponent_nonsmi;
2959
// If the exponent is a heap number go to that specific case.
2960
__ JumpIfNotSmi(eax, &exponent_nonsmi);
2961
__ JumpIfNotSmi(edx, &base_nonsmi);
2963
// Optimized version when both exponent and base are smis.
2966
__ cvtsi2sd(xmm0, edx);
2968
// exponent is smi and base is a heapnumber.
2969
__ bind(&base_nonsmi);
2970
2942
Factory* factory = masm->isolate()->factory();
2971
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2972
factory->heap_number_map());
2973
__ j(not_equal, &call_runtime);
2975
__ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2977
// Optimized version of pow if exponent is a smi.
2978
// xmm0 contains the base.
2982
// Save exponent in base as we need to check if exponent is negative later.
2983
// We know that base and exponent are in different registers.
2943
const Register exponent = eax;
2944
const Register base = edx;
2945
const Register scratch = ecx;
2946
const XMMRegister double_result = xmm3;
2947
const XMMRegister double_base = xmm2;
2948
const XMMRegister double_exponent = xmm1;
2949
const XMMRegister double_scratch = xmm4;
2951
Label call_runtime, done, exponent_not_smi, int_exponent;
2953
// Save 1 in double_result - we need this several times later on.
2954
__ mov(scratch, Immediate(1));
2955
__ cvtsi2sd(double_result, scratch);
2957
if (exponent_type_ == ON_STACK) {
2958
Label base_is_smi, unpack_exponent;
2959
// The exponent and base are supplied as arguments on the stack.
2960
// This can only happen if the stub is called from non-optimized code.
2961
// Load input parameters from stack.
2962
__ mov(base, Operand(esp, 2 * kPointerSize));
2963
__ mov(exponent, Operand(esp, 1 * kPointerSize));
2965
__ JumpIfSmi(base, &base_is_smi, Label::kNear);
2966
__ cmp(FieldOperand(base, HeapObject::kMapOffset),
2967
factory->heap_number_map());
2968
__ j(not_equal, &call_runtime);
2970
__ movdbl(double_base, FieldOperand(base, HeapNumber::kValueOffset));
2971
__ jmp(&unpack_exponent, Label::kNear);
2973
__ bind(&base_is_smi);
2975
__ cvtsi2sd(double_base, base);
2977
__ bind(&unpack_exponent);
2978
__ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
2979
__ SmiUntag(exponent);
2980
__ jmp(&int_exponent);
2982
__ bind(&exponent_not_smi);
2983
__ cmp(FieldOperand(exponent, HeapObject::kMapOffset),
2984
factory->heap_number_map());
2985
__ j(not_equal, &call_runtime);
2986
__ movdbl(double_exponent,
2987
FieldOperand(exponent, HeapNumber::kValueOffset));
2988
} else if (exponent_type_ == TAGGED) {
2989
__ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
2990
__ SmiUntag(exponent);
2991
__ jmp(&int_exponent);
2993
__ bind(&exponent_not_smi);
2994
__ movdbl(double_exponent,
2995
FieldOperand(exponent, HeapNumber::kValueOffset));
2998
if (exponent_type_ != INTEGER) {
3000
// Detect integer exponents stored as double.
3001
__ cvttsd2si(exponent, Operand(double_exponent));
3002
// Skip to runtime if possibly NaN (indicated by the indefinite integer).
3003
__ cmp(exponent, Immediate(0x80000000u));
3004
__ j(equal, &call_runtime);
3005
__ cvtsi2sd(double_scratch, exponent);
3006
// Already ruled out NaNs for exponent.
3007
__ ucomisd(double_exponent, double_scratch);
3008
__ j(equal, &int_exponent);
3010
if (exponent_type_ == ON_STACK) {
3011
// Detect square root case. Crankshaft detects constant +/-0.5 at
3012
// compile time and uses DoMathPowHalf instead. We then skip this check
3013
// for non-constant cases of +/-0.5 as these hardly occur.
3014
Label continue_sqrt, continue_rsqrt, not_plus_half;
3016
// Load double_scratch with 0.5.
3017
__ mov(scratch, Immediate(0x3F000000u));
3018
__ movd(double_scratch, scratch);
3019
__ cvtss2sd(double_scratch, double_scratch);
3020
// Already ruled out NaNs for exponent.
3021
__ ucomisd(double_scratch, double_exponent);
3022
__ j(not_equal, ¬_plus_half, Label::kNear);
3024
// Calculates square root of base. Check for the special case of
3025
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
3026
// According to IEEE-754, single-precision -Infinity has the highest
3027
// 9 bits set and the lowest 23 bits cleared.
3028
__ mov(scratch, 0xFF800000u);
3029
__ movd(double_scratch, scratch);
3030
__ cvtss2sd(double_scratch, double_scratch);
3031
__ ucomisd(double_base, double_scratch);
3032
// Comparing -Infinity with NaN results in "unordered", which sets the
3033
// zero flag as if both were equal. However, it also sets the carry flag.
3034
__ j(not_equal, &continue_sqrt, Label::kNear);
3035
__ j(carry, &continue_sqrt, Label::kNear);
3037
// Set result to Infinity in the special case.
3038
__ xorps(double_result, double_result);
3039
__ subsd(double_result, double_scratch);
3042
__ bind(&continue_sqrt);
3043
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3044
__ xorps(double_scratch, double_scratch);
3045
__ addsd(double_scratch, double_base); // Convert -0 to +0.
3046
__ sqrtsd(double_result, double_scratch);
3050
__ bind(¬_plus_half);
3051
// Load double_exponent with -0.5 by substracting 1.
3052
__ subsd(double_scratch, double_result);
3053
// Already ruled out NaNs for exponent.
3054
__ ucomisd(double_scratch, double_exponent);
3055
__ j(not_equal, &fast_power, Label::kNear);
3057
// Calculates reciprocal of square root of base. Check for the special
3058
// case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
3059
// According to IEEE-754, single-precision -Infinity has the highest
3060
// 9 bits set and the lowest 23 bits cleared.
3061
__ mov(scratch, 0xFF800000u);
3062
__ movd(double_scratch, scratch);
3063
__ cvtss2sd(double_scratch, double_scratch);
3064
__ ucomisd(double_base, double_scratch);
3065
// Comparing -Infinity with NaN results in "unordered", which sets the
3066
// zero flag as if both were equal. However, it also sets the carry flag.
3067
__ j(not_equal, &continue_rsqrt, Label::kNear);
3068
__ j(carry, &continue_rsqrt, Label::kNear);
3070
// Set result to 0 in the special case.
3071
__ xorps(double_result, double_result);
3074
__ bind(&continue_rsqrt);
3075
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3076
__ xorps(double_exponent, double_exponent);
3077
__ addsd(double_exponent, double_base); // Convert -0 to +0.
3078
__ sqrtsd(double_exponent, double_exponent);
3079
__ divsd(double_result, double_exponent);
3083
// Using FPU instructions to calculate power.
3084
Label fast_power_failed;
3085
__ bind(&fast_power);
3086
__ fnclex(); // Clear flags to catch exceptions later.
3087
// Transfer (B)ase and (E)xponent onto the FPU register stack.
3088
__ sub(esp, Immediate(kDoubleSize));
3089
__ movdbl(Operand(esp, 0), double_exponent);
3090
__ fld_d(Operand(esp, 0)); // E
3091
__ movdbl(Operand(esp, 0), double_base);
3092
__ fld_d(Operand(esp, 0)); // B, E
3094
// Exponent is in st(1) and base is in st(0)
3095
// B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
3096
// FYL2X calculates st(1) * log2(st(0))
3099
__ frndint(); // rnd(X), X
3100
__ fsub(1); // rnd(X), X-rnd(X)
3101
__ fxch(1); // X - rnd(X), rnd(X)
3102
// F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
3103
__ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
3104
__ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
3105
__ faddp(1); // 1, 2^(X-rnd(X)), rnd(X)
3106
// FSCALE calculates st(0) * 2^st(1)
3107
__ fscale(); // 2^X, rnd(X)
3109
// Bail out to runtime in case of exceptions in the status word.
3111
__ test_b(eax, 0x5F); // We check for all but precision exception.
3112
__ j(not_zero, &fast_power_failed, Label::kNear);
3113
__ fstp_d(Operand(esp, 0));
3114
__ movdbl(double_result, Operand(esp, 0));
3115
__ add(esp, Immediate(kDoubleSize));
3118
__ bind(&fast_power_failed);
3120
__ add(esp, Immediate(kDoubleSize));
3121
__ jmp(&call_runtime);
3124
// Calculate power with integer exponent.
3125
__ bind(&int_exponent);
3126
const XMMRegister double_scratch2 = double_exponent;
3127
__ mov(scratch, exponent); // Back up exponent.
3128
__ movsd(double_scratch, double_base); // Back up base.
3129
__ movsd(double_scratch2, double_result); // Load double_exponent with 1.
2986
3131
// Get absolute value of exponent.
2989
__ j(greater_equal, &no_neg, Label::kNear);
3132
Label no_neg, while_true, no_multiply;
3133
__ test(scratch, scratch);
3134
__ j(positive, &no_neg, Label::kNear);
2991
3136
__ bind(&no_neg);
2993
// Load xmm1 with 1.
2994
__ movsd(xmm1, xmm3);
2998
3138
__ bind(&while_true);
3000
3140
__ j(not_carry, &no_multiply, Label::kNear);
3001
__ mulsd(xmm1, xmm0);
3141
__ mulsd(double_result, double_scratch);
3002
3142
__ bind(&no_multiply);
3003
__ mulsd(xmm0, xmm0);
3144
__ mulsd(double_scratch, double_scratch);
3004
3145
__ j(not_zero, &while_true);
3006
// base has the original value of the exponent - if the exponent is
3007
// negative return 1/result.
3009
__ j(positive, &allocate_return);
3010
// Special case if xmm1 has reached infinity.
3011
__ mov(ecx, Immediate(0x7FB00000));
3013
__ cvtss2sd(xmm0, xmm0);
3014
__ ucomisd(xmm0, xmm1);
3015
__ j(equal, &call_runtime);
3016
__ divsd(xmm3, xmm1);
3017
__ movsd(xmm1, xmm3);
3018
__ jmp(&allocate_return);
3020
// exponent (or both) is a heapnumber - no matter what we should now work
3022
__ bind(&exponent_nonsmi);
3023
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3024
factory->heap_number_map());
3025
__ j(not_equal, &call_runtime);
3026
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
3027
// Test if exponent is nan.
3028
__ ucomisd(xmm1, xmm1);
3029
__ j(parity_even, &call_runtime);
3032
Label handle_special_cases;
3033
__ JumpIfNotSmi(edx, &base_not_smi, Label::kNear);
3035
__ cvtsi2sd(xmm0, edx);
3036
__ jmp(&handle_special_cases, Label::kNear);
3038
__ bind(&base_not_smi);
3039
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
3040
factory->heap_number_map());
3041
__ j(not_equal, &call_runtime);
3042
__ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
3043
__ and_(ecx, HeapNumber::kExponentMask);
3044
__ cmp(ecx, Immediate(HeapNumber::kExponentMask));
3045
// base is NaN or +/-Infinity
3046
__ j(greater_equal, &call_runtime);
3047
__ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
3049
// base is in xmm0 and exponent is in xmm1.
3050
__ bind(&handle_special_cases);
3051
Label not_minus_half;
3053
// Load xmm2 with -0.5.
3054
__ mov(ecx, Immediate(0xBF000000));
3056
__ cvtss2sd(xmm2, xmm2);
3057
// xmm2 now has -0.5.
3058
__ ucomisd(xmm2, xmm1);
3059
__ j(not_equal, ¬_minus_half, Label::kNear);
3061
// Calculates reciprocal of square root.
3062
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3063
__ xorps(xmm1, xmm1);
3064
__ addsd(xmm1, xmm0);
3065
__ sqrtsd(xmm1, xmm1);
3066
__ divsd(xmm3, xmm1);
3067
__ movsd(xmm1, xmm3);
3068
__ jmp(&allocate_return);
3071
__ bind(¬_minus_half);
3072
// Load xmm2 with 0.5.
3073
// Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
3074
__ addsd(xmm2, xmm3);
3075
// xmm2 now has 0.5.
3076
__ ucomisd(xmm2, xmm1);
3077
__ j(not_equal, &call_runtime);
3078
// Calculates square root.
3079
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3080
__ xorps(xmm1, xmm1);
3081
__ addsd(xmm1, xmm0);
3082
__ sqrtsd(xmm1, xmm1);
3084
__ bind(&allocate_return);
3085
__ AllocateHeapNumber(ecx, eax, edx, &call_runtime);
3086
__ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm1);
3088
__ ret(2 * kPointerSize);
3090
__ bind(&call_runtime);
3091
__ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3147
// scratch has the original value of the exponent - if the exponent is
3148
// negative, return 1/result.
3149
__ test(exponent, exponent);
3150
__ j(positive, &done);
3151
__ divsd(double_scratch2, double_result);
3152
__ movsd(double_result, double_scratch2);
3153
// Test whether result is zero. Bail out to check for subnormal result.
3154
// Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
3155
__ xorps(double_scratch2, double_scratch2);
3156
__ ucomisd(double_scratch2, double_result); // Result cannot be NaN.
3157
// double_exponent aliased as double_scratch2 has already been overwritten
3158
// and may not have contained the exponent value in the first place when the
3159
// exponent is a smi. We reset it with exponent value before bailing out.
3160
__ j(not_equal, &done);
3161
__ cvtsi2sd(double_exponent, exponent);
3163
// Returning or bailing out.
3164
Counters* counters = masm->isolate()->counters();
3165
if (exponent_type_ == ON_STACK) {
3166
// The arguments are still on the stack.
3167
__ bind(&call_runtime);
3168
__ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3170
// The stub is called from non-optimized code, which expects the result
3171
// as heap number in exponent.
3173
__ AllocateHeapNumber(eax, scratch, base, &call_runtime);
3174
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), double_result);
3175
__ IncrementCounter(counters->math_pow(), 1);
3176
__ ret(2 * kPointerSize);
3178
__ bind(&call_runtime);
3180
AllowExternalCallThatCantCauseGC scope(masm);
3181
__ PrepareCallCFunction(4, scratch);
3182
__ movdbl(Operand(esp, 0 * kDoubleSize), double_base);
3183
__ movdbl(Operand(esp, 1 * kDoubleSize), double_exponent);
3185
ExternalReference::power_double_double_function(masm->isolate()), 4);
3187
// Return value is in st(0) on ia32.
3188
// Store it into the (fixed) result register.
3189
__ sub(esp, Immediate(kDoubleSize));
3190
__ fstp_d(Operand(esp, 0));
3191
__ movdbl(double_result, Operand(esp, 0));
3192
__ add(esp, Immediate(kDoubleSize));
3195
__ IncrementCounter(counters->math_pow(), 1);
5528
5629
__ cmp(edi, kAsciiStringTag | kAsciiDataHintTag);
5529
5630
__ j(equal, &ascii_data);
5530
5631
// Allocate a two byte cons string.
5531
__ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime);
5632
__ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime);
5532
5633
__ jmp(&allocated);
5534
// Handle creating a flat result. First check that both strings are not
5535
// external strings.
5635
// We cannot encounter sliced strings or cons strings here since:
5636
STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
5637
// Handle creating a flat result from either external or sequential strings.
5638
// Locate the first characters' locations.
5536
5639
// eax: first string
5537
5640
// ebx: length of resulting flat string as a smi
5538
5641
// edx: second string
5642
Label first_prepared, second_prepared;
5643
Label first_is_sequential, second_is_sequential;
5539
5644
__ bind(&string_add_flat_result);
5540
5645
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
5541
5646
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
5542
__ and_(ecx, kStringRepresentationMask);
5543
__ cmp(ecx, kExternalStringTag);
5544
__ j(equal, &string_add_runtime);
5545
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
5546
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
5547
__ and_(ecx, kStringRepresentationMask);
5548
__ cmp(ecx, kExternalStringTag);
5549
__ j(equal, &string_add_runtime);
5550
// We cannot encounter sliced strings here since:
5551
STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength);
5552
// Now check if both strings are ascii strings.
5553
// eax: first string
5554
// ebx: length of resulting flat string as a smi
5555
// edx: second string
5556
Label non_ascii_string_add_flat_result;
5557
STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
5558
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
5559
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
5560
__ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
5647
// ecx: instance type of first string
5648
STATIC_ASSERT(kSeqStringTag == 0);
5649
__ test_b(ecx, kStringRepresentationMask);
5650
__ j(zero, &first_is_sequential, Label::kNear);
5651
// Rule out short external string and load string resource.
5652
STATIC_ASSERT(kShortExternalStringTag != 0);
5653
__ test_b(ecx, kShortExternalStringMask);
5654
__ j(not_zero, &call_runtime);
5655
__ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset));
5656
STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
5657
__ jmp(&first_prepared, Label::kNear);
5658
__ bind(&first_is_sequential);
5659
__ add(eax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5660
__ bind(&first_prepared);
5662
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
5663
__ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
5664
// Check whether both strings have same encoding.
5665
// edi: instance type of second string
5667
__ test_b(ecx, kStringEncodingMask);
5668
__ j(not_zero, &call_runtime);
5669
STATIC_ASSERT(kSeqStringTag == 0);
5670
__ test_b(edi, kStringRepresentationMask);
5671
__ j(zero, &second_is_sequential, Label::kNear);
5672
// Rule out short external string and load string resource.
5673
STATIC_ASSERT(kShortExternalStringTag != 0);
5674
__ test_b(edi, kShortExternalStringMask);
5675
__ j(not_zero, &call_runtime);
5676
__ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset));
5677
STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
5678
__ jmp(&second_prepared, Label::kNear);
5679
__ bind(&second_is_sequential);
5680
__ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5681
__ bind(&second_prepared);
5683
// Push the addresses of both strings' first characters onto the stack.
5687
Label non_ascii_string_add_flat_result, call_runtime_drop_two;
5688
// edi: instance type of second string
5689
// First string and second string have the same encoding.
5690
STATIC_ASSERT(kTwoByteStringTag == 0);
5691
__ test_b(edi, kStringEncodingMask);
5561
5692
__ j(zero, &non_ascii_string_add_flat_result);
5562
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
5563
__ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
5564
__ j(zero, &string_add_runtime);
5566
// Both strings are ascii strings. As they are short they are both flat.
5694
// Both strings are ASCII strings.
5567
5695
// ebx: length of resulting flat string as a smi
5568
5696
__ SmiUntag(ebx);
5569
__ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime);
5697
__ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two);
5570
5698
// eax: result string
5571
5699
__ mov(ecx, eax);
5572
5700
// Locate first character of result.
5573
5701
__ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5574
// Load first argument and locate first character.
5575
__ mov(edx, Operand(esp, 2 * kPointerSize));
5702
// Load first argument's length and first character location. Account for
5703
// values currently on the stack when fetching arguments from it.
5704
__ mov(edx, Operand(esp, 4 * kPointerSize));
5576
5705
__ mov(edi, FieldOperand(edx, String::kLengthOffset));
5577
5706
__ SmiUntag(edi);
5578
__ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5579
5708
// eax: result string
5580
5709
// ecx: first character of result
5581
5710
// edx: first char of first argument
5582
5711
// edi: length of first argument
5583
5712
StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
5584
// Load second argument and locate first character.
5585
__ mov(edx, Operand(esp, 1 * kPointerSize));
5713
// Load second argument's length and first character location. Account for
5714
// values currently on the stack when fetching arguments from it.
5715
__ mov(edx, Operand(esp, 2 * kPointerSize));
5586
5716
__ mov(edi, FieldOperand(edx, String::kLengthOffset));
5587
5717
__ SmiUntag(edi);
5588
__ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5589
5719
// eax: result string
5590
5720
// ecx: next character of result
5591
5721
// edx: first char of second argument
6012
6157
FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1));
6014
6159
// Try to lookup two character string in symbol table.
6015
Label make_two_character_string;
6160
Label combine_two_char, save_two_char;
6016
6161
StringHelper::GenerateTwoCharacterSymbolTableProbe(
6017
masm, ebx, ecx, eax, edx, edi,
6018
&make_two_character_string, &make_two_character_string);
6019
__ ret(3 * kPointerSize);
6021
__ bind(&make_two_character_string);
6022
// Setup registers for allocating the two character string.
6023
__ mov(eax, Operand(esp, 3 * kPointerSize));
6024
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
6025
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
6026
__ Set(ecx, Immediate(2));
6162
masm, ebx, ecx, eax, edx, edi, &combine_two_char, &save_two_char);
6163
__ IncrementCounter(counters->sub_string_native(), 1);
6164
__ ret(3 * kPointerSize);
6166
__ bind(&combine_two_char);
6167
__ shl(ecx, kBitsPerByte);
6169
__ bind(&save_two_char);
6170
__ AllocateAsciiString(eax, 2, ecx, edx, &runtime);
6171
__ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx);
6172
__ IncrementCounter(counters->sub_string_native(), 1);
6173
__ ret(3 * kPointerSize);
6175
__ bind(&result_longer_than_two);
6177
// ebx: instance type
6178
// ecx: sub string length (smi)
6179
// edx: from index (smi)
6180
// Deal with different string types: update the index if necessary
6181
// and put the underlying string into edi.
6182
Label underlying_unpacked, sliced_string, seq_or_external_string;
6183
// If the string is not indirect, it can only be sequential or external.
6184
STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
6185
STATIC_ASSERT(kIsIndirectStringMask != 0);
6186
__ test(ebx, Immediate(kIsIndirectStringMask));
6187
__ j(zero, &seq_or_external_string, Label::kNear);
6189
Factory* factory = masm->isolate()->factory();
6190
__ test(ebx, Immediate(kSlicedNotConsMask));
6191
__ j(not_zero, &sliced_string, Label::kNear);
6192
// Cons string. Check whether it is flat, then fetch first part.
6193
// Flat cons strings have an empty second part.
6194
__ cmp(FieldOperand(eax, ConsString::kSecondOffset),
6195
factory->empty_string());
6196
__ j(not_equal, &runtime);
6197
__ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
6198
// Update instance type.
6199
__ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
6200
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
6201
__ jmp(&underlying_unpacked, Label::kNear);
6203
__ bind(&sliced_string);
6204
// Sliced string. Fetch parent and adjust start index by offset.
6205
__ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
6206
__ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
6207
// Update instance type.
6208
__ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
6209
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
6210
__ jmp(&underlying_unpacked, Label::kNear);
6212
__ bind(&seq_or_external_string);
6213
// Sequential or external string. Just move string to the expected register.
6216
__ bind(&underlying_unpacked);
6028
6218
if (FLAG_string_slices) {
6029
6219
Label copy_routine;
6030
// If coming from the make_two_character_string path, the string
6031
// is too short to be sliced anyways.
6032
STATIC_ASSERT(2 < SlicedString::kMinLength);
6033
__ jmp(©_routine);
6034
__ bind(&result_longer_than_two);
6037
// ebx: instance type
6038
// ecx: sub string length
6039
// edx: from index (smi)
6040
Label allocate_slice, sliced_string, seq_or_external_string;
6041
__ cmp(ecx, SlicedString::kMinLength);
6220
// edi: underlying subject string
6221
// ebx: instance type of underlying subject string
6222
// edx: adjusted start index (smi)
6223
// ecx: length (smi)
6224
__ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength)));
6042
6225
// Short slice. Copy instead of slicing.
6043
6226
__ j(less, ©_routine);
6044
// If the string is not indirect, it can only be sequential or external.
6045
STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
6046
STATIC_ASSERT(kIsIndirectStringMask != 0);
6047
__ test(ebx, Immediate(kIsIndirectStringMask));
6048
__ j(zero, &seq_or_external_string, Label::kNear);
6050
Factory* factory = masm->isolate()->factory();
6051
__ test(ebx, Immediate(kSlicedNotConsMask));
6052
__ j(not_zero, &sliced_string, Label::kNear);
6053
// Cons string. Check whether it is flat, then fetch first part.
6054
__ cmp(FieldOperand(eax, ConsString::kSecondOffset),
6055
factory->empty_string());
6056
__ j(not_equal, &runtime);
6057
__ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
6058
__ jmp(&allocate_slice, Label::kNear);
6060
__ bind(&sliced_string);
6061
// Sliced string. Fetch parent and correct start index by offset.
6062
__ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
6063
__ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
6064
__ jmp(&allocate_slice, Label::kNear);
6066
__ bind(&seq_or_external_string);
6067
// Sequential or external string. Just move string to the correct register.
6070
__ bind(&allocate_slice);
6071
// edi: underlying subject string
6072
// ebx: instance type of original subject string
6075
6227
// Allocate new sliced string. At this point we do not reload the instance
6076
6228
// type including the string encoding because we simply rely on the info
6077
6229
// provided by the original string. It does not matter if the original