239
void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
240
// Stack layout on entry:
242
// [esp + (1 * kPointerSize)]: function
243
// [esp + (2 * kPointerSize)]: serialized scope info
245
// Try to allocate the context in new space.
247
int length = slots_ + Context::MIN_CONTEXT_SLOTS;
248
__ AllocateInNewSpace(FixedArray::SizeFor(length),
249
eax, ebx, ecx, &gc, TAG_OBJECT);
251
// Get the function or sentinel from the stack.
252
__ mov(ecx, Operand(esp, 1 * kPointerSize));
254
// Get the serialized scope info from the stack.
255
__ mov(ebx, Operand(esp, 2 * kPointerSize));
257
// Set up the object header.
258
Factory* factory = masm->isolate()->factory();
259
__ mov(FieldOperand(eax, HeapObject::kMapOffset),
260
factory->block_context_map());
261
__ mov(FieldOperand(eax, Context::kLengthOffset),
262
Immediate(Smi::FromInt(length)));
264
// If this block context is nested in the native context we get a smi
265
// sentinel instead of a function. The block context should get the
266
// canonical empty function of the native context as its closure which
267
// we still have to look up.
268
Label after_sentinel;
269
__ JumpIfNotSmi(ecx, &after_sentinel, Label::kNear);
270
if (FLAG_debug_code) {
271
const char* message = "Expected 0 as a Smi sentinel";
273
__ Assert(equal, message);
275
__ mov(ecx, GlobalObjectOperand());
276
__ mov(ecx, FieldOperand(ecx, GlobalObject::kNativeContextOffset));
277
__ mov(ecx, ContextOperand(ecx, Context::CLOSURE_INDEX));
278
__ bind(&after_sentinel);
280
// Set up the fixed slots.
281
__ mov(ContextOperand(eax, Context::CLOSURE_INDEX), ecx);
282
__ mov(ContextOperand(eax, Context::PREVIOUS_INDEX), esi);
283
__ mov(ContextOperand(eax, Context::EXTENSION_INDEX), ebx);
285
// Copy the global object from the previous context.
286
__ mov(ebx, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
287
__ mov(ContextOperand(eax, Context::GLOBAL_OBJECT_INDEX), ebx);
289
// Initialize the rest of the slots to the hole value.
291
__ mov(ContextOperand(eax, Context::MIN_CONTEXT_SLOTS),
292
factory->the_hole_value());
294
__ mov(ebx, factory->the_hole_value());
295
for (int i = 0; i < slots_; i++) {
296
__ mov(ContextOperand(eax, i + Context::MIN_CONTEXT_SLOTS), ebx);
300
// Return and remove the on-stack parameters.
302
__ ret(2 * kPointerSize);
304
// Need to collect. Call into runtime system.
306
__ TailCallRuntime(Runtime::kPushBlockContext, 2, 1);
310
static void GenerateFastCloneShallowArrayCommon(
311
MacroAssembler* masm,
313
FastCloneShallowArrayStub::Mode mode,
315
// Registers on entry:
317
// ecx: boilerplate literal array.
318
ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
320
// All sizes here are multiples of kPointerSize.
321
int elements_size = 0;
323
elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
324
? FixedDoubleArray::SizeFor(length)
325
: FixedArray::SizeFor(length);
327
int size = JSArray::kSize + elements_size;
329
// Allocate both the JS array and the elements array in one big
330
// allocation. This avoids multiple limit checks.
331
__ AllocateInNewSpace(size, eax, ebx, edx, fail, TAG_OBJECT);
333
// Copy the JS array part.
334
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
335
if ((i != JSArray::kElementsOffset) || (length == 0)) {
336
__ mov(ebx, FieldOperand(ecx, i));
337
__ mov(FieldOperand(eax, i), ebx);
342
// Get hold of the elements array of the boilerplate and setup the
343
// elements pointer in the resulting object.
344
__ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
345
__ lea(edx, Operand(eax, JSArray::kSize));
346
__ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
348
// Copy the elements array.
349
if (mode == FastCloneShallowArrayStub::CLONE_ELEMENTS) {
350
for (int i = 0; i < elements_size; i += kPointerSize) {
351
__ mov(ebx, FieldOperand(ecx, i));
352
__ mov(FieldOperand(edx, i), ebx);
355
ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS);
357
for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
358
__ mov(ebx, FieldOperand(ecx, i));
359
__ mov(FieldOperand(edx, i), ebx);
361
while (i < elements_size) {
362
__ fld_d(FieldOperand(ecx, i));
363
__ fstp_d(FieldOperand(edx, i));
366
ASSERT(i == elements_size);
162
372
void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
163
373
// Stack layout on entry:
205
// Allocate both the JS array and the elements array in one big
206
// allocation. This avoids multiple limit checks.
437
GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
438
// Return and remove the on-stack parameters.
439
__ ret(3 * kPointerSize);
442
__ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
446
void FastCloneShallowObjectStub::Generate(MacroAssembler* masm) {
447
// Stack layout on entry:
449
// [esp + kPointerSize]: object literal flags.
450
// [esp + (2 * kPointerSize)]: constant properties.
451
// [esp + (3 * kPointerSize)]: literal index.
452
// [esp + (4 * kPointerSize)]: literals array.
454
// Load boilerplate object into ecx and check if we need to create a
457
__ mov(ecx, Operand(esp, 4 * kPointerSize));
458
__ mov(eax, Operand(esp, 3 * kPointerSize));
459
STATIC_ASSERT(kPointerSize == 4);
460
STATIC_ASSERT(kSmiTagSize == 1);
461
STATIC_ASSERT(kSmiTag == 0);
462
__ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size,
463
FixedArray::kHeaderSize));
464
Factory* factory = masm->isolate()->factory();
465
__ cmp(ecx, factory->undefined_value());
466
__ j(equal, &slow_case);
468
// Check that the boilerplate contains only fast properties and we can
469
// statically determine the instance size.
470
int size = JSObject::kHeaderSize + length_ * kPointerSize;
471
__ mov(eax, FieldOperand(ecx, HeapObject::kMapOffset));
472
__ movzx_b(eax, FieldOperand(eax, Map::kInstanceSizeOffset));
473
__ cmp(eax, Immediate(size >> kPointerSizeLog2));
474
__ j(not_equal, &slow_case);
476
// Allocate the JS object and copy header together with all in-object
477
// properties from the boilerplate.
207
478
__ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT);
209
// Copy the JS array part.
210
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
211
if ((i != JSArray::kElementsOffset) || (length_ == 0)) {
212
__ mov(ebx, FieldOperand(ecx, i));
213
__ mov(FieldOperand(eax, i), ebx);
218
// Get hold of the elements array of the boilerplate and setup the
219
// elements pointer in the resulting object.
220
__ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
221
__ lea(edx, Operand(eax, JSArray::kSize));
222
__ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
224
// Copy the elements array.
225
for (int i = 0; i < elements_size; i += kPointerSize) {
226
__ mov(ebx, FieldOperand(ecx, i));
227
__ mov(FieldOperand(edx, i), ebx);
479
for (int i = 0; i < size; i += kPointerSize) {
480
__ mov(ebx, FieldOperand(ecx, i));
481
__ mov(FieldOperand(eax, i), ebx);
231
484
// Return and remove the on-stack parameters.
232
__ ret(3 * kPointerSize);
485
__ ret(4 * kPointerSize);
234
487
__ bind(&slow_case);
235
__ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
488
__ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1);
239
492
// The stub expects its argument on the stack and returns its result in tos_:
240
493
// zero for false, and a non-zero value for true.
241
494
void ToBooleanStub::Generate(MacroAssembler* masm) {
495
// This stub overrides SometimesSetsUpAFrame() to return false. That means
496
// we cannot call anything that could cause a GC from this stub.
243
498
Factory* factory = masm->isolate()->factory();
244
499
const Register argument = eax;
2705
3025
void MathPowStub::Generate(MacroAssembler* masm) {
2706
// Registers are used as follows:
2709
// ecx = temporary, result
2711
3026
CpuFeatures::Scope use_sse2(SSE2);
2712
Label allocate_return, call_runtime;
2714
// Load input parameters.
2715
__ mov(edx, Operand(esp, 2 * kPointerSize));
2716
__ mov(eax, Operand(esp, 1 * kPointerSize));
2718
// Save 1 in xmm3 - we need this several times later on.
2719
__ mov(ecx, Immediate(1));
2720
__ cvtsi2sd(xmm3, Operand(ecx));
2722
Label exponent_nonsmi;
2724
// If the exponent is a heap number go to that specific case.
2725
__ JumpIfNotSmi(eax, &exponent_nonsmi);
2726
__ JumpIfNotSmi(edx, &base_nonsmi);
2728
// Optimized version when both exponent and base are smis.
2731
__ cvtsi2sd(xmm0, Operand(edx));
2733
// exponent is smi and base is a heapnumber.
2734
__ bind(&base_nonsmi);
2735
3027
Factory* factory = masm->isolate()->factory();
2736
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2737
factory->heap_number_map());
2738
__ j(not_equal, &call_runtime);
2740
__ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2742
// Optimized version of pow if exponent is a smi.
2743
// xmm0 contains the base.
2747
// Save exponent in base as we need to check if exponent is negative later.
2748
// We know that base and exponent are in different registers.
3028
const Register exponent = eax;
3029
const Register base = edx;
3030
const Register scratch = ecx;
3031
const XMMRegister double_result = xmm3;
3032
const XMMRegister double_base = xmm2;
3033
const XMMRegister double_exponent = xmm1;
3034
const XMMRegister double_scratch = xmm4;
3036
Label call_runtime, done, exponent_not_smi, int_exponent;
3038
// Save 1 in double_result - we need this several times later on.
3039
__ mov(scratch, Immediate(1));
3040
__ cvtsi2sd(double_result, scratch);
3042
if (exponent_type_ == ON_STACK) {
3043
Label base_is_smi, unpack_exponent;
3044
// The exponent and base are supplied as arguments on the stack.
3045
// This can only happen if the stub is called from non-optimized code.
3046
// Load input parameters from stack.
3047
__ mov(base, Operand(esp, 2 * kPointerSize));
3048
__ mov(exponent, Operand(esp, 1 * kPointerSize));
3050
__ JumpIfSmi(base, &base_is_smi, Label::kNear);
3051
__ cmp(FieldOperand(base, HeapObject::kMapOffset),
3052
factory->heap_number_map());
3053
__ j(not_equal, &call_runtime);
3055
__ movdbl(double_base, FieldOperand(base, HeapNumber::kValueOffset));
3056
__ jmp(&unpack_exponent, Label::kNear);
3058
__ bind(&base_is_smi);
3060
__ cvtsi2sd(double_base, base);
3062
__ bind(&unpack_exponent);
3063
__ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
3064
__ SmiUntag(exponent);
3065
__ jmp(&int_exponent);
3067
__ bind(&exponent_not_smi);
3068
__ cmp(FieldOperand(exponent, HeapObject::kMapOffset),
3069
factory->heap_number_map());
3070
__ j(not_equal, &call_runtime);
3071
__ movdbl(double_exponent,
3072
FieldOperand(exponent, HeapNumber::kValueOffset));
3073
} else if (exponent_type_ == TAGGED) {
3074
__ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
3075
__ SmiUntag(exponent);
3076
__ jmp(&int_exponent);
3078
__ bind(&exponent_not_smi);
3079
__ movdbl(double_exponent,
3080
FieldOperand(exponent, HeapNumber::kValueOffset));
3083
if (exponent_type_ != INTEGER) {
3085
// Detect integer exponents stored as double.
3086
__ cvttsd2si(exponent, Operand(double_exponent));
3087
// Skip to runtime if possibly NaN (indicated by the indefinite integer).
3088
__ cmp(exponent, Immediate(0x80000000u));
3089
__ j(equal, &call_runtime);
3090
__ cvtsi2sd(double_scratch, exponent);
3091
// Already ruled out NaNs for exponent.
3092
__ ucomisd(double_exponent, double_scratch);
3093
__ j(equal, &int_exponent);
3095
if (exponent_type_ == ON_STACK) {
3096
// Detect square root case. Crankshaft detects constant +/-0.5 at
3097
// compile time and uses DoMathPowHalf instead. We then skip this check
3098
// for non-constant cases of +/-0.5 as these hardly occur.
3099
Label continue_sqrt, continue_rsqrt, not_plus_half;
3101
// Load double_scratch with 0.5.
3102
__ mov(scratch, Immediate(0x3F000000u));
3103
__ movd(double_scratch, scratch);
3104
__ cvtss2sd(double_scratch, double_scratch);
3105
// Already ruled out NaNs for exponent.
3106
__ ucomisd(double_scratch, double_exponent);
3107
__ j(not_equal, ¬_plus_half, Label::kNear);
3109
// Calculates square root of base. Check for the special case of
3110
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
3111
// According to IEEE-754, single-precision -Infinity has the highest
3112
// 9 bits set and the lowest 23 bits cleared.
3113
__ mov(scratch, 0xFF800000u);
3114
__ movd(double_scratch, scratch);
3115
__ cvtss2sd(double_scratch, double_scratch);
3116
__ ucomisd(double_base, double_scratch);
3117
// Comparing -Infinity with NaN results in "unordered", which sets the
3118
// zero flag as if both were equal. However, it also sets the carry flag.
3119
__ j(not_equal, &continue_sqrt, Label::kNear);
3120
__ j(carry, &continue_sqrt, Label::kNear);
3122
// Set result to Infinity in the special case.
3123
__ xorps(double_result, double_result);
3124
__ subsd(double_result, double_scratch);
3127
__ bind(&continue_sqrt);
3128
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3129
__ xorps(double_scratch, double_scratch);
3130
__ addsd(double_scratch, double_base); // Convert -0 to +0.
3131
__ sqrtsd(double_result, double_scratch);
3135
__ bind(¬_plus_half);
3136
// Load double_exponent with -0.5 by substracting 1.
3137
__ subsd(double_scratch, double_result);
3138
// Already ruled out NaNs for exponent.
3139
__ ucomisd(double_scratch, double_exponent);
3140
__ j(not_equal, &fast_power, Label::kNear);
3142
// Calculates reciprocal of square root of base. Check for the special
3143
// case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
3144
// According to IEEE-754, single-precision -Infinity has the highest
3145
// 9 bits set and the lowest 23 bits cleared.
3146
__ mov(scratch, 0xFF800000u);
3147
__ movd(double_scratch, scratch);
3148
__ cvtss2sd(double_scratch, double_scratch);
3149
__ ucomisd(double_base, double_scratch);
3150
// Comparing -Infinity with NaN results in "unordered", which sets the
3151
// zero flag as if both were equal. However, it also sets the carry flag.
3152
__ j(not_equal, &continue_rsqrt, Label::kNear);
3153
__ j(carry, &continue_rsqrt, Label::kNear);
3155
// Set result to 0 in the special case.
3156
__ xorps(double_result, double_result);
3159
__ bind(&continue_rsqrt);
3160
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3161
__ xorps(double_exponent, double_exponent);
3162
__ addsd(double_exponent, double_base); // Convert -0 to +0.
3163
__ sqrtsd(double_exponent, double_exponent);
3164
__ divsd(double_result, double_exponent);
3168
// Using FPU instructions to calculate power.
3169
Label fast_power_failed;
3170
__ bind(&fast_power);
3171
__ fnclex(); // Clear flags to catch exceptions later.
3172
// Transfer (B)ase and (E)xponent onto the FPU register stack.
3173
__ sub(esp, Immediate(kDoubleSize));
3174
__ movdbl(Operand(esp, 0), double_exponent);
3175
__ fld_d(Operand(esp, 0)); // E
3176
__ movdbl(Operand(esp, 0), double_base);
3177
__ fld_d(Operand(esp, 0)); // B, E
3179
// Exponent is in st(1) and base is in st(0)
3180
// B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
3181
// FYL2X calculates st(1) * log2(st(0))
3184
__ frndint(); // rnd(X), X
3185
__ fsub(1); // rnd(X), X-rnd(X)
3186
__ fxch(1); // X - rnd(X), rnd(X)
3187
// F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
3188
__ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
3189
__ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
3190
__ faddp(1); // 1, 2^(X-rnd(X)), rnd(X)
3191
// FSCALE calculates st(0) * 2^st(1)
3192
__ fscale(); // 2^X, rnd(X)
3194
// Bail out to runtime in case of exceptions in the status word.
3196
__ test_b(eax, 0x5F); // We check for all but precision exception.
3197
__ j(not_zero, &fast_power_failed, Label::kNear);
3198
__ fstp_d(Operand(esp, 0));
3199
__ movdbl(double_result, Operand(esp, 0));
3200
__ add(esp, Immediate(kDoubleSize));
3203
__ bind(&fast_power_failed);
3205
__ add(esp, Immediate(kDoubleSize));
3206
__ jmp(&call_runtime);
3209
// Calculate power with integer exponent.
3210
__ bind(&int_exponent);
3211
const XMMRegister double_scratch2 = double_exponent;
3212
__ mov(scratch, exponent); // Back up exponent.
3213
__ movsd(double_scratch, double_base); // Back up base.
3214
__ movsd(double_scratch2, double_result); // Load double_exponent with 1.
2751
3216
// Get absolute value of exponent.
2754
__ j(greater_equal, &no_neg, Label::kNear);
3217
Label no_neg, while_true, while_false;
3218
__ test(scratch, scratch);
3219
__ j(positive, &no_neg, Label::kNear);
2756
3221
__ bind(&no_neg);
2758
// Load xmm1 with 1.
2759
__ movsd(xmm1, xmm3);
3223
__ j(zero, &while_false, Label::kNear);
3225
// Above condition means CF==0 && ZF==0. This means that the
3226
// bit that has been shifted out is 0 and the result is not 0.
3227
__ j(above, &while_true, Label::kNear);
3228
__ movsd(double_result, double_scratch);
3229
__ j(zero, &while_false, Label::kNear);
2763
3231
__ bind(&while_true);
2765
__ j(not_carry, &no_multiply, Label::kNear);
2766
__ mulsd(xmm1, xmm0);
2767
__ bind(&no_multiply);
2768
__ mulsd(xmm0, xmm0);
3233
__ mulsd(double_scratch, double_scratch);
3234
__ j(above, &while_true, Label::kNear);
3235
__ mulsd(double_result, double_scratch);
2769
3236
__ j(not_zero, &while_true);
2771
// base has the original value of the exponent - if the exponent is
2772
// negative return 1/result.
2773
__ test(edx, Operand(edx));
2774
__ j(positive, &allocate_return);
2775
// Special case if xmm1 has reached infinity.
2776
__ mov(ecx, Immediate(0x7FB00000));
2777
__ movd(xmm0, Operand(ecx));
2778
__ cvtss2sd(xmm0, xmm0);
2779
__ ucomisd(xmm0, xmm1);
2780
__ j(equal, &call_runtime);
2781
__ divsd(xmm3, xmm1);
2782
__ movsd(xmm1, xmm3);
2783
__ jmp(&allocate_return);
2785
// exponent (or both) is a heapnumber - no matter what we should now work
2787
__ bind(&exponent_nonsmi);
2788
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
2789
factory->heap_number_map());
2790
__ j(not_equal, &call_runtime);
2791
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2792
// Test if exponent is nan.
2793
__ ucomisd(xmm1, xmm1);
2794
__ j(parity_even, &call_runtime);
2797
Label handle_special_cases;
2798
__ JumpIfNotSmi(edx, &base_not_smi, Label::kNear);
2800
__ cvtsi2sd(xmm0, Operand(edx));
2801
__ jmp(&handle_special_cases, Label::kNear);
2803
__ bind(&base_not_smi);
2804
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2805
factory->heap_number_map());
2806
__ j(not_equal, &call_runtime);
2807
__ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
2808
__ and_(ecx, HeapNumber::kExponentMask);
2809
__ cmp(Operand(ecx), Immediate(HeapNumber::kExponentMask));
2810
// base is NaN or +/-Infinity
2811
__ j(greater_equal, &call_runtime);
2812
__ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2814
// base is in xmm0 and exponent is in xmm1.
2815
__ bind(&handle_special_cases);
2816
Label not_minus_half;
2818
// Load xmm2 with -0.5.
2819
__ mov(ecx, Immediate(0xBF000000));
2820
__ movd(xmm2, Operand(ecx));
2821
__ cvtss2sd(xmm2, xmm2);
2822
// xmm2 now has -0.5.
2823
__ ucomisd(xmm2, xmm1);
2824
__ j(not_equal, ¬_minus_half, Label::kNear);
2826
// Calculates reciprocal of square root.
2827
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
2828
__ xorps(xmm1, xmm1);
2829
__ addsd(xmm1, xmm0);
2830
__ sqrtsd(xmm1, xmm1);
2831
__ divsd(xmm3, xmm1);
2832
__ movsd(xmm1, xmm3);
2833
__ jmp(&allocate_return);
2836
__ bind(¬_minus_half);
2837
// Load xmm2 with 0.5.
2838
// Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
2839
__ addsd(xmm2, xmm3);
2840
// xmm2 now has 0.5.
2841
__ ucomisd(xmm2, xmm1);
2842
__ j(not_equal, &call_runtime);
2843
// Calculates square root.
2844
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
2845
__ xorps(xmm1, xmm1);
2846
__ addsd(xmm1, xmm0);
2847
__ sqrtsd(xmm1, xmm1);
2849
__ bind(&allocate_return);
2850
__ AllocateHeapNumber(ecx, eax, edx, &call_runtime);
2851
__ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm1);
2853
__ ret(2 * kPointerSize);
2855
__ bind(&call_runtime);
2856
__ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3238
__ bind(&while_false);
3239
// scratch has the original value of the exponent - if the exponent is
3240
// negative, return 1/result.
3241
__ test(exponent, exponent);
3242
__ j(positive, &done);
3243
__ divsd(double_scratch2, double_result);
3244
__ movsd(double_result, double_scratch2);
3245
// Test whether result is zero. Bail out to check for subnormal result.
3246
// Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
3247
__ xorps(double_scratch2, double_scratch2);
3248
__ ucomisd(double_scratch2, double_result); // Result cannot be NaN.
3249
// double_exponent aliased as double_scratch2 has already been overwritten
3250
// and may not have contained the exponent value in the first place when the
3251
// exponent is a smi. We reset it with exponent value before bailing out.
3252
__ j(not_equal, &done);
3253
__ cvtsi2sd(double_exponent, exponent);
3255
// Returning or bailing out.
3256
Counters* counters = masm->isolate()->counters();
3257
if (exponent_type_ == ON_STACK) {
3258
// The arguments are still on the stack.
3259
__ bind(&call_runtime);
3260
__ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3262
// The stub is called from non-optimized code, which expects the result
3263
// as heap number in exponent.
3265
__ AllocateHeapNumber(eax, scratch, base, &call_runtime);
3266
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), double_result);
3267
__ IncrementCounter(counters->math_pow(), 1);
3268
__ ret(2 * kPointerSize);
3270
__ bind(&call_runtime);
3272
AllowExternalCallThatCantCauseGC scope(masm);
3273
__ PrepareCallCFunction(4, scratch);
3274
__ movdbl(Operand(esp, 0 * kDoubleSize), double_base);
3275
__ movdbl(Operand(esp, 1 * kDoubleSize), double_exponent);
3277
ExternalReference::power_double_double_function(masm->isolate()), 4);
3279
// Return value is in st(0) on ia32.
3280
// Store it into the (fixed) result register.
3281
__ sub(esp, Immediate(kDoubleSize));
3282
__ fstp_d(Operand(esp, 0));
3283
__ movdbl(double_result, Operand(esp, 0));
3284
__ add(esp, Immediate(kDoubleSize));
3287
__ IncrementCounter(counters->math_pow(), 1);
4674
void InterruptStub::Generate(MacroAssembler* masm) {
4675
__ TailCallRuntime(Runtime::kInterrupt, 0, 1);
4679
static void GenerateRecordCallTarget(MacroAssembler* masm) {
4680
// Cache the called function in a global property cell. Cache states
4681
// are uninitialized, monomorphic (indicated by a JSFunction), and
4683
// ebx : cache cell for call target
4684
// edi : the function to call
4685
Isolate* isolate = masm->isolate();
4686
Label initialize, done;
4688
// Load the cache state into ecx.
4689
__ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
4691
// A monomorphic cache hit or an already megamorphic state: invoke the
4692
// function without changing the state.
4694
__ j(equal, &done, Label::kNear);
4695
__ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
4696
__ j(equal, &done, Label::kNear);
4698
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
4700
__ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate)));
4701
__ j(equal, &initialize, Label::kNear);
4702
// MegamorphicSentinel is an immortal immovable object (undefined) so no
4703
// write-barrier is needed.
4704
__ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
4705
Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
4706
__ jmp(&done, Label::kNear);
4708
// An uninitialized cache is patched with the function.
4709
__ bind(&initialize);
4710
__ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi);
4711
// No need for a write barrier here - cells are rescanned.
4201
4717
void CallFunctionStub::Generate(MacroAssembler* masm) {
4718
// ebx : cache cell for call target
4719
// edi : the function to call
4720
Isolate* isolate = masm->isolate();
4202
4721
Label slow, non_function;
4204
4723
// The receiver might implicitly be the global object. This is
4205
4724
// indicated by passing the hole as the receiver to the call
4206
4725
// function stub.
4207
4726
if (ReceiverMightBeImplicit()) {
4209
4728
// Get the receiver from the stack.
4210
4729
// +1 ~ return address
4211
4730
__ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize));
4212
4731
// Call as function is indicated with the hole.
4213
__ cmp(eax, masm->isolate()->factory()->the_hole_value());
4214
__ j(not_equal, &call, Label::kNear);
4732
__ cmp(eax, isolate->factory()->the_hole_value());
4733
__ j(not_equal, &receiver_ok, Label::kNear);
4215
4734
// Patch the receiver on the stack with the global receiver object.
4216
__ mov(ebx, GlobalObjectOperand());
4217
__ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
4218
__ mov(Operand(esp, (argc_ + 1) * kPointerSize), ebx);
4735
__ mov(ecx, GlobalObjectOperand());
4736
__ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
4737
__ mov(Operand(esp, (argc_ + 1) * kPointerSize), ecx);
4738
__ bind(&receiver_ok);
4222
// Get the function to call from the stack.
4223
// +2 ~ receiver, return address
4224
__ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
4226
4741
// Check that the function really is a JavaScript function.
4227
4742
__ JumpIfSmi(edi, &non_function);
4228
4743
// Goto slow case if we do not have a function.
4229
4744
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
4230
4745
__ j(not_equal, &slow);
4747
if (RecordCallTarget()) {
4748
GenerateRecordCallTarget(masm);
4232
4751
// Fast-case: Just invoke the function.
4233
4752
ParameterCount actual(argc_);
4235
4754
if (ReceiverMightBeImplicit()) {
4236
4755
Label call_as_function;
4237
__ cmp(eax, masm->isolate()->factory()->the_hole_value());
4756
__ cmp(eax, isolate->factory()->the_hole_value());
4238
4757
__ j(equal, &call_as_function);
4239
4758
__ InvokeFunction(edi,
4873
5463
// If the index is non-smi trigger the non-smi case.
4874
5464
STATIC_ASSERT(kSmiTag == 0);
4875
5465
__ JumpIfNotSmi(index_, &index_not_smi_);
4877
// Put smi-tagged index into scratch register.
4878
__ mov(scratch_, index_);
4879
5466
__ bind(&got_smi_index_);
4881
5468
// Check for index out of range.
4882
__ cmp(scratch_, FieldOperand(object_, String::kLengthOffset));
5469
__ cmp(index_, FieldOperand(object_, String::kLengthOffset));
4883
5470
__ j(above_equal, index_out_of_range_);
4885
// We need special handling for non-flat strings.
4886
STATIC_ASSERT(kSeqStringTag == 0);
4887
__ test(result_, Immediate(kStringRepresentationMask));
4888
__ j(zero, &flat_string);
4890
// Handle non-flat strings.
4891
__ and_(result_, kStringRepresentationMask);
4892
STATIC_ASSERT(kConsStringTag < kExternalStringTag);
4893
STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
4894
__ cmp(result_, kExternalStringTag);
4895
__ j(greater, &sliced_string, Label::kNear);
4896
__ j(equal, &call_runtime_);
4899
// Check whether the right hand side is the empty string (i.e. if
4900
// this is really a flat string in a cons string). If that is not
4901
// the case we would rather go to the runtime system now to flatten
4903
Label assure_seq_string;
4904
__ cmp(FieldOperand(object_, ConsString::kSecondOffset),
4905
Immediate(masm->isolate()->factory()->empty_string()));
4906
__ j(not_equal, &call_runtime_);
4907
// Get the first of the two strings and load its instance type.
4908
__ mov(object_, FieldOperand(object_, ConsString::kFirstOffset));
4909
__ jmp(&assure_seq_string, Label::kNear);
4911
// SlicedString, unpack and add offset.
4912
__ bind(&sliced_string);
4913
__ add(scratch_, FieldOperand(object_, SlicedString::kOffsetOffset));
4914
__ mov(object_, FieldOperand(object_, SlicedString::kParentOffset));
4916
// Assure that we are dealing with a sequential string. Go to runtime if not.
4917
__ bind(&assure_seq_string);
4918
__ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
4919
__ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
4920
STATIC_ASSERT(kSeqStringTag == 0);
4921
__ test(result_, Immediate(kStringRepresentationMask));
4922
__ j(not_zero, &call_runtime_);
4923
__ jmp(&flat_string, Label::kNear);
4925
// Check for 1-byte or 2-byte string.
4926
__ bind(&flat_string);
4927
STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
4928
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
4929
__ test(result_, Immediate(kStringEncodingMask));
4930
__ j(not_zero, &ascii_string, Label::kNear);
4933
// Load the 2-byte character code into the result register.
4934
STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
4935
__ movzx_w(result_, FieldOperand(object_,
4936
scratch_, times_1, // Scratch is smi-tagged.
4937
SeqTwoByteString::kHeaderSize));
4938
__ jmp(&got_char_code, Label::kNear);
4941
// Load the byte into the result register.
4942
__ bind(&ascii_string);
4943
__ SmiUntag(scratch_);
4944
__ movzx_b(result_, FieldOperand(object_,
4946
SeqAsciiString::kHeaderSize));
4947
__ bind(&got_char_code);
5472
__ SmiUntag(index_);
5474
Factory* factory = masm->isolate()->factory();
5475
StringCharLoadGenerator::Generate(
5476
masm, factory, object_, index_, result_, &call_runtime_);
4948
5478
__ SmiTag(result_);
4949
5479
__ bind(&exit_);
4953
5483
void StringCharCodeAtGenerator::GenerateSlow(
4954
MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
5484
MacroAssembler* masm,
5485
const RuntimeCallHelper& call_helper) {
4955
5486
__ Abort("Unexpected fallthrough to CharCodeAt slow case");
4957
5488
// Index is not a smi.
5216
5743
__ ret(2 * kPointerSize);
5217
5744
__ bind(&non_ascii);
5218
5745
// At least one of the strings is two-byte. Check whether it happens
5219
// to contain only ascii characters.
5746
// to contain only ASCII characters.
5220
5747
// ecx: first instance type AND second instance type.
5221
5748
// edi: second instance type.
5222
5749
__ test(ecx, Immediate(kAsciiDataHintMask));
5223
5750
__ j(not_zero, &ascii_data);
5224
5751
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
5225
5752
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
5226
__ xor_(edi, Operand(ecx));
5227
5754
STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0);
5228
5755
__ and_(edi, kAsciiStringTag | kAsciiDataHintTag);
5229
5756
__ cmp(edi, kAsciiStringTag | kAsciiDataHintTag);
5230
5757
__ j(equal, &ascii_data);
5231
5758
// Allocate a two byte cons string.
5232
__ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime);
5759
__ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime);
5233
5760
__ jmp(&allocated);
5235
// Handle creating a flat result. First check that both strings are not
5236
// external strings.
5762
// We cannot encounter sliced strings or cons strings here since:
5763
STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
5764
// Handle creating a flat result from either external or sequential strings.
5765
// Locate the first characters' locations.
5237
5766
// eax: first string
5238
5767
// ebx: length of resulting flat string as a smi
5239
5768
// edx: second string
5769
Label first_prepared, second_prepared;
5770
Label first_is_sequential, second_is_sequential;
5240
5771
__ bind(&string_add_flat_result);
5241
5772
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
5242
5773
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
5243
__ and_(ecx, kStringRepresentationMask);
5244
__ cmp(ecx, kExternalStringTag);
5245
__ j(equal, &string_add_runtime);
5246
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
5247
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
5248
__ and_(ecx, kStringRepresentationMask);
5249
__ cmp(ecx, kExternalStringTag);
5250
__ j(equal, &string_add_runtime);
5251
// We cannot encounter sliced strings here since:
5252
STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength);
5253
// Now check if both strings are ascii strings.
5254
// eax: first string
5255
// ebx: length of resulting flat string as a smi
5256
// edx: second string
5257
Label non_ascii_string_add_flat_result;
5258
STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
5259
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
5260
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
5261
__ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
5774
// ecx: instance type of first string
5775
STATIC_ASSERT(kSeqStringTag == 0);
5776
__ test_b(ecx, kStringRepresentationMask);
5777
__ j(zero, &first_is_sequential, Label::kNear);
5778
// Rule out short external string and load string resource.
5779
STATIC_ASSERT(kShortExternalStringTag != 0);
5780
__ test_b(ecx, kShortExternalStringMask);
5781
__ j(not_zero, &call_runtime);
5782
__ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset));
5783
STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
5784
__ jmp(&first_prepared, Label::kNear);
5785
__ bind(&first_is_sequential);
5786
__ add(eax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5787
__ bind(&first_prepared);
5789
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
5790
__ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
5791
// Check whether both strings have same encoding.
5792
// edi: instance type of second string
5794
__ test_b(ecx, kStringEncodingMask);
5795
__ j(not_zero, &call_runtime);
5796
STATIC_ASSERT(kSeqStringTag == 0);
5797
__ test_b(edi, kStringRepresentationMask);
5798
__ j(zero, &second_is_sequential, Label::kNear);
5799
// Rule out short external string and load string resource.
5800
STATIC_ASSERT(kShortExternalStringTag != 0);
5801
__ test_b(edi, kShortExternalStringMask);
5802
__ j(not_zero, &call_runtime);
5803
__ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset));
5804
STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
5805
__ jmp(&second_prepared, Label::kNear);
5806
__ bind(&second_is_sequential);
5807
__ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5808
__ bind(&second_prepared);
5810
// Push the addresses of both strings' first characters onto the stack.
5814
Label non_ascii_string_add_flat_result, call_runtime_drop_two;
5815
// edi: instance type of second string
5816
// First string and second string have the same encoding.
5817
STATIC_ASSERT(kTwoByteStringTag == 0);
5818
__ test_b(edi, kStringEncodingMask);
5262
5819
__ j(zero, &non_ascii_string_add_flat_result);
5263
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
5264
__ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
5265
__ j(zero, &string_add_runtime);
5267
// Both strings are ascii strings. As they are short they are both flat.
5821
// Both strings are ASCII strings.
5268
5822
// ebx: length of resulting flat string as a smi
5269
5823
__ SmiUntag(ebx);
5270
__ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime);
5824
__ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two);
5271
5825
// eax: result string
5272
5826
__ mov(ecx, eax);
5273
5827
// Locate first character of result.
5274
__ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5275
// Load first argument and locate first character.
5276
__ mov(edx, Operand(esp, 2 * kPointerSize));
5828
__ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5829
// Load first argument's length and first character location. Account for
5830
// values currently on the stack when fetching arguments from it.
5831
__ mov(edx, Operand(esp, 4 * kPointerSize));
5277
5832
__ mov(edi, FieldOperand(edx, String::kLengthOffset));
5278
5833
__ SmiUntag(edi);
5279
__ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5280
5835
// eax: result string
5281
5836
// ecx: first character of result
5282
5837
// edx: first char of first argument
5283
5838
// edi: length of first argument
5284
5839
StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
5285
// Load second argument and locate first character.
5286
__ mov(edx, Operand(esp, 1 * kPointerSize));
5840
// Load second argument's length and first character location. Account for
5841
// values currently on the stack when fetching arguments from it.
5842
__ mov(edx, Operand(esp, 2 * kPointerSize));
5287
5843
__ mov(edi, FieldOperand(edx, String::kLengthOffset));
5288
5844
__ SmiUntag(edi);
5289
__ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5290
5846
// eax: result string
5291
5847
// ecx: next character of result
5292
5848
// edx: first char of second argument
5695
6250
// ebx: instance type
5697
6252
// Calculate length of sub string using the smi values.
5698
Label result_longer_than_two;
5699
6253
__ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index.
5700
6254
__ JumpIfNotSmi(ecx, &runtime);
5701
6255
__ mov(edx, Operand(esp, 2 * kPointerSize)); // From index.
5702
6256
__ JumpIfNotSmi(edx, &runtime);
5703
__ sub(ecx, Operand(edx));
5704
6258
__ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
5706
__ j(equal, &return_eax);
5707
// Special handling of sub-strings of length 1 and 2. One character strings
5708
// are handled in the runtime system (looked up in the single character
5709
// cache). Two character strings are looked for in the symbol cache.
5710
__ SmiUntag(ecx); // Result length is no longer smi.
5712
__ j(greater, &result_longer_than_two);
5713
__ j(less, &runtime);
6259
Label not_original_string;
6260
// Shorter than original string's length: an actual substring.
6261
__ j(below, ¬_original_string, Label::kNear);
6262
// Longer than original string's length or negative: unsafe arguments.
6263
__ j(above, &runtime);
6264
// Return original string.
6265
Counters* counters = masm->isolate()->counters();
6266
__ IncrementCounter(counters->sub_string_native(), 1);
6267
__ ret(3 * kPointerSize);
6268
__ bind(¬_original_string);
5715
// Sub string of length 2 requested.
5717
6271
// ebx: instance type
5718
// ecx: sub string length (value is 2)
6272
// ecx: sub string length (smi)
5719
6273
// edx: from index (smi)
5720
__ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &runtime);
5722
// Get the two characters forming the sub string.
5723
__ SmiUntag(edx); // From index is no longer smi.
5724
__ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize));
5726
FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1));
5728
// Try to lookup two character string in symbol table.
5729
Label make_two_character_string;
5730
StringHelper::GenerateTwoCharacterSymbolTableProbe(
5731
masm, ebx, ecx, eax, edx, edi,
5732
&make_two_character_string, &make_two_character_string);
5733
__ ret(3 * kPointerSize);
5735
__ bind(&make_two_character_string);
5736
// Setup registers for allocating the two character string.
5737
__ mov(eax, Operand(esp, 3 * kPointerSize));
5738
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
5739
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
5740
__ Set(ecx, Immediate(2));
6274
// Deal with different string types: update the index if necessary
6275
// and put the underlying string into edi.
6276
Label underlying_unpacked, sliced_string, seq_or_external_string;
6277
// If the string is not indirect, it can only be sequential or external.
6278
STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
6279
STATIC_ASSERT(kIsIndirectStringMask != 0);
6280
__ test(ebx, Immediate(kIsIndirectStringMask));
6281
__ j(zero, &seq_or_external_string, Label::kNear);
6283
Factory* factory = masm->isolate()->factory();
6284
__ test(ebx, Immediate(kSlicedNotConsMask));
6285
__ j(not_zero, &sliced_string, Label::kNear);
6286
// Cons string. Check whether it is flat, then fetch first part.
6287
// Flat cons strings have an empty second part.
6288
__ cmp(FieldOperand(eax, ConsString::kSecondOffset),
6289
factory->empty_string());
6290
__ j(not_equal, &runtime);
6291
__ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
6292
// Update instance type.
6293
__ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
6294
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
6295
__ jmp(&underlying_unpacked, Label::kNear);
6297
__ bind(&sliced_string);
6298
// Sliced string. Fetch parent and adjust start index by offset.
6299
__ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
6300
__ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
6301
// Update instance type.
6302
__ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
6303
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
6304
__ jmp(&underlying_unpacked, Label::kNear);
6306
__ bind(&seq_or_external_string);
6307
// Sequential or external string. Just move string to the expected register.
6310
__ bind(&underlying_unpacked);
5742
6312
if (FLAG_string_slices) {
5743
6313
Label copy_routine;
5744
// If coming from the make_two_character_string path, the string
5745
// is too short to be sliced anyways.
5746
STATIC_ASSERT(2 < SlicedString::kMinLength);
5747
__ jmp(©_routine);
5748
__ bind(&result_longer_than_two);
5751
// ebx: instance type
5752
// ecx: sub string length
5753
// edx: from index (smi)
5754
Label allocate_slice, sliced_string, seq_string;
5755
__ cmp(ecx, SlicedString::kMinLength);
6314
// edi: underlying subject string
6315
// ebx: instance type of underlying subject string
6316
// edx: adjusted start index (smi)
6317
// ecx: length (smi)
6318
__ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength)));
5756
6319
// Short slice. Copy instead of slicing.
5757
6320
__ j(less, ©_routine);
5758
STATIC_ASSERT(kSeqStringTag == 0);
5759
__ test(ebx, Immediate(kStringRepresentationMask));
5760
__ j(zero, &seq_string, Label::kNear);
5761
STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
5762
STATIC_ASSERT(kIsIndirectStringMask != 0);
5763
__ test(ebx, Immediate(kIsIndirectStringMask));
5764
// External string. Jump to runtime.
5765
__ j(zero, &runtime);
5767
Factory* factory = masm->isolate()->factory();
5768
__ test(ebx, Immediate(kSlicedNotConsMask));
5769
__ j(not_zero, &sliced_string, Label::kNear);
5770
// Cons string. Check whether it is flat, then fetch first part.
5771
__ cmp(FieldOperand(eax, ConsString::kSecondOffset),
5772
factory->empty_string());
5773
__ j(not_equal, &runtime);
5774
__ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
5775
__ jmp(&allocate_slice, Label::kNear);
5777
__ bind(&sliced_string);
5778
// Sliced string. Fetch parent and correct start index by offset.
5779
__ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
5780
__ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
5781
__ jmp(&allocate_slice, Label::kNear);
5783
__ bind(&seq_string);
5784
// Sequential string. Just move string to the right register.
5787
__ bind(&allocate_slice);
5788
// edi: underlying subject string
5789
// ebx: instance type of original subject string
5792
6321
// Allocate new sliced string. At this point we do not reload the instance
5793
6322
// type including the string encoding because we simply rely on the info
5794
6323
// provided by the original string. It does not matter if the original
5804
6333
__ bind(&two_byte_slice);
5805
6334
__ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime);
5806
6335
__ bind(&set_slice_header);
5807
__ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
5809
6336
__ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx);
5810
__ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
5811
6337
__ mov(FieldOperand(eax, SlicedString::kHashFieldOffset),
5812
6338
Immediate(String::kEmptyHashField));
5813
__ jmp(&return_eax);
6339
__ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
6340
__ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
6341
__ IncrementCounter(counters->sub_string_native(), 1);
6342
__ ret(3 * kPointerSize);
5815
6344
__ bind(©_routine);
5817
__ bind(&result_longer_than_two);
5821
// ebx: instance type
5822
// ecx: result string length
5823
// Check for flat ascii string
5824
Label non_ascii_flat;
5825
__ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat);
5827
// Allocate the result.
5828
__ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime);
6347
// edi: underlying subject string
6348
// ebx: instance type of underlying subject string
6349
// edx: adjusted start index (smi)
6350
// ecx: length (smi)
6351
// The subject string can only be external or sequential string of either
6352
// encoding at this point.
6353
Label two_byte_sequential, runtime_drop_two, sequential_string;
6354
STATIC_ASSERT(kExternalStringTag != 0);
6355
STATIC_ASSERT(kSeqStringTag == 0);
6356
__ test_b(ebx, kExternalStringTag);
6357
__ j(zero, &sequential_string);
6359
// Handle external string.
6360
// Rule out short external strings.
6361
STATIC_CHECK(kShortExternalStringTag != 0);
6362
__ test_b(ebx, kShortExternalStringMask);
6363
__ j(not_zero, &runtime);
6364
__ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset));
6365
// Move the pointer so that offset-wise, it looks like a sequential string.
6366
STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
6367
__ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6369
__ bind(&sequential_string);
6370
// Stash away (adjusted) index and (underlying) string.
6374
STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0);
6375
__ test_b(ebx, kStringEncodingMask);
6376
__ j(zero, &two_byte_sequential);
6378
// Sequential ASCII string. Allocate the result.
6379
__ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
5830
6381
// eax: result string
5831
6382
// ecx: result string length
5832
6383
__ mov(edx, esi); // esi used by following code.
5833
6384
// Locate first character of result.
5834
6385
__ mov(edi, eax);
5835
__ add(Operand(edi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
6386
__ add(edi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5836
6387
// Load string argument and locate character of sub string start.
5837
__ mov(esi, Operand(esp, 3 * kPointerSize));
5838
__ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5839
__ mov(ebx, Operand(esp, 2 * kPointerSize)); // from
5840
6390
__ SmiUntag(ebx);
5841
__ add(esi, Operand(ebx));
6391
__ lea(esi, FieldOperand(esi, ebx, times_1, SeqAsciiString::kHeaderSize));
5843
6393
// eax: result string
5844
6394
// ecx: result length
7119
struct AheadOfTimeWriteBarrierStubList {
7120
Register object, value, address;
7121
RememberedSetAction action;
7125
#define REG(Name) { kRegister_ ## Name ## _Code }
7127
static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
7128
// Used in RegExpExecStub.
7129
{ REG(ebx), REG(eax), REG(edi), EMIT_REMEMBERED_SET },
7130
// Used in CompileArrayPushCall.
7131
{ REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET },
7132
{ REG(ebx), REG(edi), REG(edx), OMIT_REMEMBERED_SET },
7133
// Used in CompileStoreGlobal and CallFunctionStub.
7134
{ REG(ebx), REG(ecx), REG(edx), OMIT_REMEMBERED_SET },
7135
// Used in StoreStubCompiler::CompileStoreField and
7136
// KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField.
7137
{ REG(edx), REG(ecx), REG(ebx), EMIT_REMEMBERED_SET },
7138
// GenerateStoreField calls the stub with two different permutations of
7139
// registers. This is the second.
7140
{ REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET },
7141
// StoreIC::GenerateNormal via GenerateDictionaryStore
7142
{ REG(ebx), REG(edi), REG(edx), EMIT_REMEMBERED_SET },
7143
// KeyedStoreIC::GenerateGeneric.
7144
{ REG(ebx), REG(edx), REG(ecx), EMIT_REMEMBERED_SET},
7145
// KeyedStoreStubCompiler::GenerateStoreFastElement.
7146
{ REG(edi), REG(ebx), REG(ecx), EMIT_REMEMBERED_SET},
7147
{ REG(edx), REG(edi), REG(ebx), EMIT_REMEMBERED_SET},
7148
// ElementsTransitionGenerator::GenerateMapChangeElementTransition
7149
// and ElementsTransitionGenerator::GenerateSmiToDouble
7150
// and ElementsTransitionGenerator::GenerateDoubleToObject
7151
{ REG(edx), REG(ebx), REG(edi), EMIT_REMEMBERED_SET},
7152
{ REG(edx), REG(ebx), REG(edi), OMIT_REMEMBERED_SET},
7153
// ElementsTransitionGenerator::GenerateDoubleToObject
7154
{ REG(eax), REG(edx), REG(esi), EMIT_REMEMBERED_SET},
7155
{ REG(edx), REG(eax), REG(edi), EMIT_REMEMBERED_SET},
7156
// StoreArrayLiteralElementStub::Generate
7157
{ REG(ebx), REG(eax), REG(ecx), EMIT_REMEMBERED_SET},
7158
// FastNewClosureStub
7159
{ REG(ecx), REG(edx), REG(ebx), EMIT_REMEMBERED_SET},
7160
// Null termination.
7161
{ REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET}
7166
bool RecordWriteStub::IsPregenerated() {
7167
for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
7168
!entry->object.is(no_reg);
7170
if (object_.is(entry->object) &&
7171
value_.is(entry->value) &&
7172
address_.is(entry->address) &&
7173
remembered_set_action_ == entry->action &&
7174
save_fp_regs_mode_ == kDontSaveFPRegs) {
7182
void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() {
7183
StoreBufferOverflowStub stub1(kDontSaveFPRegs);
7184
stub1.GetCode()->set_is_pregenerated(true);
7186
CpuFeatures::TryForceFeatureScope scope(SSE2);
7187
if (CpuFeatures::IsSupported(SSE2)) {
7188
StoreBufferOverflowStub stub2(kSaveFPRegs);
7189
stub2.GetCode()->set_is_pregenerated(true);
7194
void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() {
7195
for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
7196
!entry->object.is(no_reg);
7198
RecordWriteStub stub(entry->object,
7203
stub.GetCode()->set_is_pregenerated(true);
7208
bool CodeStub::CanUseFPRegisters() {
7209
return CpuFeatures::IsSupported(SSE2);
7213
// Takes the input in 3 registers: address_ value_ and object_. A pointer to
7214
// the value has just been written into the object, now this stub makes sure
7215
// we keep the GC informed. The word in the object where the value has been
7216
// written is in the address register.
7217
void RecordWriteStub::Generate(MacroAssembler* masm) {
7218
Label skip_to_incremental_noncompacting;
7219
Label skip_to_incremental_compacting;
7221
// The first two instructions are generated with labels so as to get the
7222
// offset fixed up correctly by the bind(Label*) call. We patch it back and
7223
// forth between a compare instructions (a nop in this position) and the
7224
// real branch when we start and stop incremental heap marking.
7225
__ jmp(&skip_to_incremental_noncompacting, Label::kNear);
7226
__ jmp(&skip_to_incremental_compacting, Label::kFar);
7228
if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
7229
__ RememberedSetHelper(object_,
7233
MacroAssembler::kReturnAtEnd);
7238
__ bind(&skip_to_incremental_noncompacting);
7239
GenerateIncremental(masm, INCREMENTAL);
7241
__ bind(&skip_to_incremental_compacting);
7242
GenerateIncremental(masm, INCREMENTAL_COMPACTION);
7244
// Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
7245
// Will be checked in IncrementalMarking::ActivateGeneratedStub.
7246
masm->set_byte_at(0, kTwoByteNopInstruction);
7247
masm->set_byte_at(2, kFiveByteNopInstruction);
7251
void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
7254
if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
7255
Label dont_need_remembered_set;
7257
__ mov(regs_.scratch0(), Operand(regs_.address(), 0));
7258
__ JumpIfNotInNewSpace(regs_.scratch0(), // Value.
7260
&dont_need_remembered_set);
7262
__ CheckPageFlag(regs_.object(),
7264
1 << MemoryChunk::SCAN_ON_SCAVENGE,
7266
&dont_need_remembered_set);
7268
// First notify the incremental marker if necessary, then update the
7270
CheckNeedsToInformIncrementalMarker(
7272
kUpdateRememberedSetOnNoNeedToInformIncrementalMarker,
7274
InformIncrementalMarker(masm, mode);
7275
regs_.Restore(masm);
7276
__ RememberedSetHelper(object_,
7280
MacroAssembler::kReturnAtEnd);
7282
__ bind(&dont_need_remembered_set);
7285
CheckNeedsToInformIncrementalMarker(
7287
kReturnOnNoNeedToInformIncrementalMarker,
7289
InformIncrementalMarker(masm, mode);
7290
regs_.Restore(masm);
7295
void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) {
7296
regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_);
7297
int argument_count = 3;
7298
__ PrepareCallCFunction(argument_count, regs_.scratch0());
7299
__ mov(Operand(esp, 0 * kPointerSize), regs_.object());
7300
if (mode == INCREMENTAL_COMPACTION) {
7301
__ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot.
7303
ASSERT(mode == INCREMENTAL);
7304
__ mov(regs_.scratch0(), Operand(regs_.address(), 0));
7305
__ mov(Operand(esp, 1 * kPointerSize), regs_.scratch0()); // Value.
7307
__ mov(Operand(esp, 2 * kPointerSize),
7308
Immediate(ExternalReference::isolate_address()));
7310
AllowExternalCallThatCantCauseGC scope(masm);
7311
if (mode == INCREMENTAL_COMPACTION) {
7313
ExternalReference::incremental_evacuation_record_write_function(
7317
ASSERT(mode == INCREMENTAL);
7319
ExternalReference::incremental_marking_record_write_function(
7323
regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
7327
void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
7328
MacroAssembler* masm,
7329
OnNoNeedToInformIncrementalMarker on_no_need,
7331
Label object_is_black, need_incremental, need_incremental_pop_object;
7333
__ mov(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask));
7334
__ and_(regs_.scratch0(), regs_.object());
7335
__ mov(regs_.scratch1(),
7336
Operand(regs_.scratch0(),
7337
MemoryChunk::kWriteBarrierCounterOffset));
7338
__ sub(regs_.scratch1(), Immediate(1));
7339
__ mov(Operand(regs_.scratch0(),
7340
MemoryChunk::kWriteBarrierCounterOffset),
7342
__ j(negative, &need_incremental);
7344
// Let's look at the color of the object: If it is not black we don't have
7345
// to inform the incremental marker.
7346
__ JumpIfBlack(regs_.object(),
7352
regs_.Restore(masm);
7353
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
7354
__ RememberedSetHelper(object_,
7358
MacroAssembler::kReturnAtEnd);
7363
__ bind(&object_is_black);
7365
// Get the value from the slot.
7366
__ mov(regs_.scratch0(), Operand(regs_.address(), 0));
7368
if (mode == INCREMENTAL_COMPACTION) {
7369
Label ensure_not_white;
7371
__ CheckPageFlag(regs_.scratch0(), // Contains value.
7372
regs_.scratch1(), // Scratch.
7373
MemoryChunk::kEvacuationCandidateMask,
7378
__ CheckPageFlag(regs_.object(),
7379
regs_.scratch1(), // Scratch.
7380
MemoryChunk::kSkipEvacuationSlotsRecordingMask,
7385
__ jmp(&need_incremental);
7387
__ bind(&ensure_not_white);
7390
// We need an extra register for this, so we push the object register
7392
__ push(regs_.object());
7393
__ EnsureNotWhite(regs_.scratch0(), // The value.
7394
regs_.scratch1(), // Scratch.
7395
regs_.object(), // Scratch.
7396
&need_incremental_pop_object,
7398
__ pop(regs_.object());
7400
regs_.Restore(masm);
7401
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
7402
__ RememberedSetHelper(object_,
7406
MacroAssembler::kReturnAtEnd);
7411
__ bind(&need_incremental_pop_object);
7412
__ pop(regs_.object());
7414
__ bind(&need_incremental);
7416
// Fall through when we need to inform the incremental marker.
7420
void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
7421
// ----------- S t a t e -------------
7422
// -- eax : element value to store
7423
// -- ebx : array literal
7424
// -- edi : map of array literal
7425
// -- ecx : element index as smi
7426
// -- edx : array literal index in function
7427
// -- esp[0] : return address
7428
// -----------------------------------
7431
Label double_elements;
7433
Label slow_elements;
7434
Label slow_elements_from_double;
7435
Label fast_elements;
7437
__ CheckFastElements(edi, &double_elements);
7439
// Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
7440
__ JumpIfSmi(eax, &smi_element);
7441
__ CheckFastSmiElements(edi, &fast_elements, Label::kNear);
7443
// Store into the array literal requires a elements transition. Call into
7446
__ bind(&slow_elements);
7447
__ pop(edi); // Pop return address and remember to put back later for tail
7452
__ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
7453
__ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
7455
__ push(edi); // Return return address so that tail call returns to right
7457
__ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
7459
__ bind(&slow_elements_from_double);
7461
__ jmp(&slow_elements);
7463
// Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
7464
__ bind(&fast_elements);
7465
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
7466
__ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size,
7467
FixedArrayBase::kHeaderSize));
7468
__ mov(Operand(ecx, 0), eax);
7469
// Update the write barrier for the array store.
7470
__ RecordWrite(ebx, ecx, eax,
7472
EMIT_REMEMBERED_SET,
7476
// Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
7477
// and value is Smi.
7478
__ bind(&smi_element);
7479
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
7480
__ mov(FieldOperand(ebx, ecx, times_half_pointer_size,
7481
FixedArrayBase::kHeaderSize), eax);
7484
// Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS.
7485
__ bind(&double_elements);
7488
__ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset));
7489
__ StoreNumberToDoubleElements(eax,
7494
&slow_elements_from_double,
7501
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
7502
if (entry_hook_ != NULL) {
7503
ProfileEntryHookStub stub;
7504
masm->CallStub(&stub);
7509
void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
7510
// Ecx is the only volatile register we must save.
7513
// Calculate and push the original stack pointer.
7514
__ lea(eax, Operand(esp, kPointerSize));
7517
// Calculate and push the function address.
7518
__ mov(eax, Operand(eax, 0));
7519
__ sub(eax, Immediate(Assembler::kCallInstructionLength));
7522
// Call the entry hook.
7523
int32_t hook_location = reinterpret_cast<int32_t>(&entry_hook_);
7524
__ call(Operand(hook_location, RelocInfo::NONE));
7525
__ add(esp, Immediate(2 * kPointerSize));
6531
7534
} } // namespace v8::internal