~yolanda.robla/ubuntu/trusty/nodejs/add_distribution

« back to all changes in this revision

Viewing changes to deps/v8/src/ia32/code-stubs-ia32.cc

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2013-08-14 00:16:46 UTC
  • mfrom: (7.1.40 sid)
  • Revision ID: package-import@ubuntu.com-20130814001646-bzlysfh8sd6mukbo
Tags: 0.10.15~dfsg1-4
* Update 2005 patch, adding a handful of tests that can fail on
  slow platforms.
* Add 1004 patch to fix test failures when writing NaN to buffer
  on mipsel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2011 the V8 project authors. All rights reserved.
 
1
// Copyright 2012 the V8 project authors. All rights reserved.
2
2
// Redistribution and use in source and binary forms, with or without
3
3
// modification, are permitted provided that the following conditions are
4
4
// met:
34
34
#include "isolate.h"
35
35
#include "jsregexp.h"
36
36
#include "regexp-macro-assembler.h"
 
37
#include "stub-cache.h"
 
38
#include "codegen.h"
37
39
 
38
40
namespace v8 {
39
41
namespace internal {
49
51
  __ bind(&check_heap_number);
50
52
  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
51
53
  Factory* factory = masm->isolate()->factory();
52
 
  __ cmp(Operand(ebx), Immediate(factory->heap_number_map()));
 
54
  __ cmp(ebx, Immediate(factory->heap_number_map()));
53
55
  __ j(not_equal, &call_builtin, Label::kNear);
54
56
  __ ret(0);
55
57
 
64
66
void FastNewClosureStub::Generate(MacroAssembler* masm) {
65
67
  // Create a new closure from the given function info in new
66
68
  // space. Set the context to the current context in esi.
 
69
  Counters* counters = masm->isolate()->counters();
 
70
 
67
71
  Label gc;
68
72
  __ AllocateInNewSpace(JSFunction::kSize, eax, ebx, ecx, &gc, TAG_OBJECT);
69
73
 
 
74
  __ IncrementCounter(counters->fast_new_closure_total(), 1);
 
75
 
70
76
  // Get the function info from the stack.
71
77
  __ mov(edx, Operand(esp, 1 * kPointerSize));
72
78
 
73
 
  int map_index = strict_mode_ == kStrictMode
74
 
      ? Context::STRICT_MODE_FUNCTION_MAP_INDEX
75
 
      : Context::FUNCTION_MAP_INDEX;
 
79
  int map_index = (language_mode_ == CLASSIC_MODE)
 
80
      ? Context::FUNCTION_MAP_INDEX
 
81
      : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
76
82
 
77
 
  // Compute the function map in the current global context and set that
 
83
  // Compute the function map in the current native context and set that
78
84
  // as the map of the allocated object.
79
 
  __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
80
 
  __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset));
81
 
  __ mov(ecx, Operand(ecx, Context::SlotOffset(map_index)));
82
 
  __ mov(FieldOperand(eax, JSObject::kMapOffset), ecx);
 
85
  __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
 
86
  __ mov(ecx, FieldOperand(ecx, GlobalObject::kNativeContextOffset));
 
87
  __ mov(ebx, Operand(ecx, Context::SlotOffset(map_index)));
 
88
  __ mov(FieldOperand(eax, JSObject::kMapOffset), ebx);
83
89
 
84
90
  // Initialize the rest of the function. We don't have to update the
85
91
  // write barrier because the allocated object is in new space.
92
98
  __ mov(FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset), edx);
93
99
  __ mov(FieldOperand(eax, JSFunction::kContextOffset), esi);
94
100
  __ mov(FieldOperand(eax, JSFunction::kLiteralsOffset), ebx);
 
101
 
 
102
  // Initialize the code pointer in the function to be the one
 
103
  // found in the shared function info object.
 
104
  // But first check if there is an optimized version for our context.
 
105
  Label check_optimized;
 
106
  Label install_unoptimized;
 
107
  if (FLAG_cache_optimized_code) {
 
108
    __ mov(ebx, FieldOperand(edx, SharedFunctionInfo::kOptimizedCodeMapOffset));
 
109
    __ test(ebx, ebx);
 
110
    __ j(not_zero, &check_optimized, Label::kNear);
 
111
  }
 
112
  __ bind(&install_unoptimized);
95
113
  __ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset),
96
114
         Immediate(factory->undefined_value()));
97
 
 
98
 
  // Initialize the code pointer in the function to be the one
99
 
  // found in the shared function info object.
100
115
  __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
101
116
  __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
102
117
  __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx);
104
119
  // Return and remove the on-stack parameter.
105
120
  __ ret(1 * kPointerSize);
106
121
 
 
122
  __ bind(&check_optimized);
 
123
 
 
124
  __ IncrementCounter(counters->fast_new_closure_try_optimized(), 1);
 
125
 
 
126
  // ecx holds native context, ebx points to fixed array of 3-element entries
 
127
  // (native context, optimized code, literals).
 
128
  // Map must never be empty, so check the first elements.
 
129
  Label install_optimized;
 
130
  // Speculatively move code object into edx.
 
131
  __ mov(edx, FieldOperand(ebx, FixedArray::kHeaderSize + kPointerSize));
 
132
  __ cmp(ecx, FieldOperand(ebx, FixedArray::kHeaderSize));
 
133
  __ j(equal, &install_optimized);
 
134
 
 
135
  // Iterate through the rest of map backwards.  edx holds an index as a Smi.
 
136
  Label loop;
 
137
  Label restore;
 
138
  __ mov(edx, FieldOperand(ebx, FixedArray::kLengthOffset));
 
139
  __ bind(&loop);
 
140
  // Do not double check first entry.
 
141
  __ cmp(edx, Immediate(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
 
142
  __ j(equal, &restore);
 
143
  __ sub(edx, Immediate(Smi::FromInt(
 
144
      SharedFunctionInfo::kEntryLength)));  // Skip an entry.
 
145
  __ cmp(ecx, CodeGenerator::FixedArrayElementOperand(ebx, edx, 0));
 
146
  __ j(not_equal, &loop, Label::kNear);
 
147
  // Hit: fetch the optimized code.
 
148
  __ mov(edx, CodeGenerator::FixedArrayElementOperand(ebx, edx, 1));
 
149
 
 
150
  __ bind(&install_optimized);
 
151
  __ IncrementCounter(counters->fast_new_closure_install_optimized(), 1);
 
152
 
 
153
  // TODO(fschneider): Idea: store proper code pointers in the optimized code
 
154
  // map and either unmangle them on marking or do nothing as the whole map is
 
155
  // discarded on major GC anyway.
 
156
  __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
 
157
  __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx);
 
158
 
 
159
  // Now link a function into a list of optimized functions.
 
160
  __ mov(edx, ContextOperand(ecx, Context::OPTIMIZED_FUNCTIONS_LIST));
 
161
 
 
162
  __ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset), edx);
 
163
  // No need for write barrier as JSFunction (eax) is in the new space.
 
164
 
 
165
  __ mov(ContextOperand(ecx, Context::OPTIMIZED_FUNCTIONS_LIST), eax);
 
166
  // Store JSFunction (eax) into edx before issuing write barrier as
 
167
  // it clobbers all the registers passed.
 
168
  __ mov(edx, eax);
 
169
  __ RecordWriteContextSlot(
 
170
      ecx,
 
171
      Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST),
 
172
      edx,
 
173
      ebx,
 
174
      kDontSaveFPRegs);
 
175
 
 
176
  // Return and remove the on-stack parameter.
 
177
  __ ret(1 * kPointerSize);
 
178
 
 
179
  __ bind(&restore);
 
180
  // Restore SharedFunctionInfo into edx.
 
181
  __ mov(edx, Operand(esp, 1 * kPointerSize));
 
182
  __ jmp(&install_unoptimized);
 
183
 
107
184
  // Create a new closure through the slower runtime call.
108
185
  __ bind(&gc);
109
186
  __ pop(ecx);  // Temporarily remove return address.
126
203
  // Get the function from the stack.
127
204
  __ mov(ecx, Operand(esp, 1 * kPointerSize));
128
205
 
129
 
  // Setup the object header.
 
206
  // Set up the object header.
130
207
  Factory* factory = masm->isolate()->factory();
131
208
  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
132
209
         factory->function_context_map());
133
210
  __ mov(FieldOperand(eax, Context::kLengthOffset),
134
211
         Immediate(Smi::FromInt(length)));
135
212
 
136
 
  // Setup the fixed slots.
 
213
  // Set up the fixed slots.
137
214
  __ Set(ebx, Immediate(0));  // Set to NULL.
138
215
  __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx);
139
216
  __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi);
140
217
  __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx);
141
218
 
142
219
  // Copy the global object from the previous context.
143
 
  __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
144
 
  __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx);
 
220
  __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
 
221
  __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)), ebx);
145
222
 
146
223
  // Initialize the rest of the slots to undefined.
147
224
  __ mov(ebx, factory->undefined_value());
150
227
  }
151
228
 
152
229
  // Return and remove the on-stack parameter.
153
 
  __ mov(esi, Operand(eax));
 
230
  __ mov(esi, eax);
154
231
  __ ret(1 * kPointerSize);
155
232
 
156
233
  // Need to collect. Call into runtime system.
159
236
}
160
237
 
161
238
 
 
239
void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
 
240
  // Stack layout on entry:
 
241
  //
 
242
  // [esp + (1 * kPointerSize)]: function
 
243
  // [esp + (2 * kPointerSize)]: serialized scope info
 
244
 
 
245
  // Try to allocate the context in new space.
 
246
  Label gc;
 
247
  int length = slots_ + Context::MIN_CONTEXT_SLOTS;
 
248
  __ AllocateInNewSpace(FixedArray::SizeFor(length),
 
249
                        eax, ebx, ecx, &gc, TAG_OBJECT);
 
250
 
 
251
  // Get the function or sentinel from the stack.
 
252
  __ mov(ecx, Operand(esp, 1 * kPointerSize));
 
253
 
 
254
  // Get the serialized scope info from the stack.
 
255
  __ mov(ebx, Operand(esp, 2 * kPointerSize));
 
256
 
 
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)));
 
263
 
 
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";
 
272
    __ cmp(ecx, 0);
 
273
    __ Assert(equal, message);
 
274
  }
 
275
  __ mov(ecx, GlobalObjectOperand());
 
276
  __ mov(ecx, FieldOperand(ecx, GlobalObject::kNativeContextOffset));
 
277
  __ mov(ecx, ContextOperand(ecx, Context::CLOSURE_INDEX));
 
278
  __ bind(&after_sentinel);
 
279
 
 
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);
 
284
 
 
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);
 
288
 
 
289
  // Initialize the rest of the slots to the hole value.
 
290
  if (slots_ == 1) {
 
291
    __ mov(ContextOperand(eax, Context::MIN_CONTEXT_SLOTS),
 
292
           factory->the_hole_value());
 
293
  } else {
 
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);
 
297
    }
 
298
  }
 
299
 
 
300
  // Return and remove the on-stack parameters.
 
301
  __ mov(esi, eax);
 
302
  __ ret(2 * kPointerSize);
 
303
 
 
304
  // Need to collect. Call into runtime system.
 
305
  __ bind(&gc);
 
306
  __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1);
 
307
}
 
308
 
 
309
 
 
310
static void GenerateFastCloneShallowArrayCommon(
 
311
    MacroAssembler* masm,
 
312
    int length,
 
313
    FastCloneShallowArrayStub::Mode mode,
 
314
    Label* fail) {
 
315
  // Registers on entry:
 
316
  //
 
317
  // ecx: boilerplate literal array.
 
318
  ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
 
319
 
 
320
  // All sizes here are multiples of kPointerSize.
 
321
  int elements_size = 0;
 
322
  if (length > 0) {
 
323
    elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
 
324
        ? FixedDoubleArray::SizeFor(length)
 
325
        : FixedArray::SizeFor(length);
 
326
  }
 
327
  int size = JSArray::kSize + elements_size;
 
328
 
 
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);
 
332
 
 
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);
 
338
    }
 
339
  }
 
340
 
 
341
  if (length > 0) {
 
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);
 
347
 
 
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);
 
353
      }
 
354
    } else {
 
355
      ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS);
 
356
      int i;
 
357
      for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
 
358
        __ mov(ebx, FieldOperand(ecx, i));
 
359
        __ mov(FieldOperand(edx, i), ebx);
 
360
      }
 
361
      while (i < elements_size) {
 
362
        __ fld_d(FieldOperand(ecx, i));
 
363
        __ fstp_d(FieldOperand(edx, i));
 
364
        i += kDoubleSize;
 
365
      }
 
366
      ASSERT(i == elements_size);
 
367
    }
 
368
  }
 
369
}
 
370
 
 
371
 
162
372
void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
163
373
  // Stack layout on entry:
164
374
  //
166
376
  // [esp + (2 * kPointerSize)]: literal index.
167
377
  // [esp + (3 * kPointerSize)]: literals array.
168
378
 
169
 
  // All sizes here are multiples of kPointerSize.
170
 
  int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0;
171
 
  int size = JSArray::kSize + elements_size;
172
 
 
173
379
  // Load boilerplate object into ecx and check if we need to create a
174
380
  // boilerplate.
175
 
  Label slow_case;
176
381
  __ mov(ecx, Operand(esp, 3 * kPointerSize));
177
382
  __ mov(eax, Operand(esp, 2 * kPointerSize));
178
383
  STATIC_ASSERT(kPointerSize == 4);
182
387
                           FixedArray::kHeaderSize));
183
388
  Factory* factory = masm->isolate()->factory();
184
389
  __ cmp(ecx, factory->undefined_value());
 
390
  Label slow_case;
185
391
  __ j(equal, &slow_case);
186
392
 
 
393
  FastCloneShallowArrayStub::Mode mode = mode_;
 
394
  // ecx is boilerplate object.
 
395
  if (mode == CLONE_ANY_ELEMENTS) {
 
396
    Label double_elements, check_fast_elements;
 
397
    __ mov(ebx, FieldOperand(ecx, JSArray::kElementsOffset));
 
398
    __ CheckMap(ebx, factory->fixed_cow_array_map(),
 
399
                &check_fast_elements, DONT_DO_SMI_CHECK);
 
400
    GenerateFastCloneShallowArrayCommon(masm, 0,
 
401
                                        COPY_ON_WRITE_ELEMENTS, &slow_case);
 
402
    __ ret(3 * kPointerSize);
 
403
 
 
404
    __ bind(&check_fast_elements);
 
405
    __ CheckMap(ebx, factory->fixed_array_map(),
 
406
                &double_elements, DONT_DO_SMI_CHECK);
 
407
    GenerateFastCloneShallowArrayCommon(masm, length_,
 
408
                                        CLONE_ELEMENTS, &slow_case);
 
409
    __ ret(3 * kPointerSize);
 
410
 
 
411
    __ bind(&double_elements);
 
412
    mode = CLONE_DOUBLE_ELEMENTS;
 
413
    // Fall through to generate the code to handle double elements.
 
414
  }
 
415
 
187
416
  if (FLAG_debug_code) {
188
417
    const char* message;
189
418
    Handle<Map> expected_map;
190
 
    if (mode_ == CLONE_ELEMENTS) {
 
419
    if (mode == CLONE_ELEMENTS) {
191
420
      message = "Expected (writable) fixed array";
192
421
      expected_map = factory->fixed_array_map();
 
422
    } else if (mode == CLONE_DOUBLE_ELEMENTS) {
 
423
      message = "Expected (writable) fixed double array";
 
424
      expected_map = factory->fixed_double_array_map();
193
425
    } else {
194
 
      ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS);
 
426
      ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
195
427
      message = "Expected copy-on-write fixed array";
196
428
      expected_map = factory->fixed_cow_array_map();
197
429
    }
202
434
    __ pop(ecx);
203
435
  }
204
436
 
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);
 
440
 
 
441
  __ bind(&slow_case);
 
442
  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
 
443
}
 
444
 
 
445
 
 
446
void FastCloneShallowObjectStub::Generate(MacroAssembler* masm) {
 
447
  // Stack layout on entry:
 
448
  //
 
449
  // [esp + kPointerSize]: object literal flags.
 
450
  // [esp + (2 * kPointerSize)]: constant properties.
 
451
  // [esp + (3 * kPointerSize)]: literal index.
 
452
  // [esp + (4 * kPointerSize)]: literals array.
 
453
 
 
454
  // Load boilerplate object into ecx and check if we need to create a
 
455
  // boilerplate.
 
456
  Label slow_case;
 
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);
 
467
 
 
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);
 
475
 
 
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);
208
 
 
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);
214
 
    }
215
 
  }
216
 
 
217
 
  if (length_ > 0) {
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);
223
 
 
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);
228
 
    }
 
479
  for (int i = 0; i < size; i += kPointerSize) {
 
480
    __ mov(ebx, FieldOperand(ecx, i));
 
481
    __ mov(FieldOperand(eax, i), ebx);
229
482
  }
230
483
 
231
484
  // Return and remove the on-stack parameters.
232
 
  __ ret(3 * kPointerSize);
 
485
  __ ret(4 * kPointerSize);
233
486
 
234
487
  __ bind(&slow_case);
235
 
  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
 
488
  __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1);
236
489
}
237
490
 
238
491
 
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.
242
497
  Label patch;
243
498
  Factory* factory = masm->isolate()->factory();
244
499
  const Register argument = eax;
336
591
}
337
592
 
338
593
 
 
594
void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
 
595
  // We don't allow a GC during a store buffer overflow so there is no need to
 
596
  // store the registers in any particular way, but we do have to store and
 
597
  // restore them.
 
598
  __ pushad();
 
599
  if (save_doubles_ == kSaveFPRegs) {
 
600
    CpuFeatures::Scope scope(SSE2);
 
601
    __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
 
602
    for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
 
603
      XMMRegister reg = XMMRegister::from_code(i);
 
604
      __ movdbl(Operand(esp, i * kDoubleSize), reg);
 
605
    }
 
606
  }
 
607
  const int argument_count = 1;
 
608
 
 
609
  AllowExternalCallThatCantCauseGC scope(masm);
 
610
  __ PrepareCallCFunction(argument_count, ecx);
 
611
  __ mov(Operand(esp, 0 * kPointerSize),
 
612
         Immediate(ExternalReference::isolate_address()));
 
613
  __ CallCFunction(
 
614
      ExternalReference::store_buffer_overflow_function(masm->isolate()),
 
615
      argument_count);
 
616
  if (save_doubles_ == kSaveFPRegs) {
 
617
    CpuFeatures::Scope scope(SSE2);
 
618
    for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
 
619
      XMMRegister reg = XMMRegister::from_code(i);
 
620
      __ movdbl(reg, Operand(esp, i * kDoubleSize));
 
621
    }
 
622
    __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
 
623
  }
 
624
  __ popad();
 
625
  __ ret(0);
 
626
}
 
627
 
 
628
 
339
629
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
340
630
                                 Type type,
341
631
                                 Heap::RootListIndex value,
470
760
    // Check whether the exponent is too big for a 64 bit signed integer.
471
761
    static const uint32_t kTooBigExponent =
472
762
        (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
473
 
    __ cmp(Operand(scratch2), Immediate(kTooBigExponent));
 
763
    __ cmp(scratch2, Immediate(kTooBigExponent));
474
764
    __ j(greater_equal, conversion_failure);
475
765
    // Load x87 register with heap number.
476
766
    __ fld_d(FieldOperand(source, HeapNumber::kValueOffset));
477
767
    // Reserve space for 64 bit answer.
478
 
    __ sub(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint.
 
768
    __ sub(esp, Immediate(sizeof(uint64_t)));  // Nolint.
479
769
    // Do conversion, which cannot fail because we checked the exponent.
480
770
    __ fisttp_d(Operand(esp, 0));
481
771
    __ mov(ecx, Operand(esp, 0));  // Load low word of answer into ecx.
482
 
    __ add(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint.
 
772
    __ add(esp, Immediate(sizeof(uint64_t)));  // Nolint.
483
773
  } else {
484
774
    // Load ecx with zero.  We use this either for the final shift or
485
775
    // for the answer.
486
 
    __ xor_(ecx, Operand(ecx));
 
776
    __ xor_(ecx, ecx);
487
777
    // Check whether the exponent matches a 32 bit signed int that cannot be
488
778
    // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so the
489
779
    // exponent is 30 (biased).  This is the exponent that we are fastest at and
490
780
    // also the highest exponent we can handle here.
491
781
    const uint32_t non_smi_exponent =
492
782
        (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
493
 
    __ cmp(Operand(scratch2), Immediate(non_smi_exponent));
 
783
    __ cmp(scratch2, Immediate(non_smi_exponent));
494
784
    // If we have a match of the int32-but-not-Smi exponent then skip some
495
785
    // logic.
496
786
    __ j(equal, &right_exponent, Label::kNear);
503
793
      // >>> operator has a tendency to generate numbers with an exponent of 31.
504
794
      const uint32_t big_non_smi_exponent =
505
795
          (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
506
 
      __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent));
 
796
      __ cmp(scratch2, Immediate(big_non_smi_exponent));
507
797
      __ j(not_equal, conversion_failure);
508
798
      // We have the big exponent, typically from >>>.  This means the number is
509
799
      // in the range 2^31 to 2^32 - 1.  Get the top bits of the mantissa.
522
812
      // Shift down 21 bits to get the most significant 11 bits or the low
523
813
      // mantissa word.
524
814
      __ shr(ecx, 32 - big_shift_distance);
525
 
      __ or_(ecx, Operand(scratch2));
 
815
      __ or_(ecx, scratch2);
526
816
      // We have the answer in ecx, but we may need to negate it.
527
 
      __ test(scratch, Operand(scratch));
 
817
      __ test(scratch, scratch);
528
818
      __ j(positive, &done, Label::kNear);
529
819
      __ neg(ecx);
530
820
      __ jmp(&done, Label::kNear);
534
824
    // Exponent word in scratch, exponent part of exponent word in scratch2.
535
825
    // Zero in ecx.
536
826
    // We know the exponent is smaller than 30 (biased).  If it is less than
537
 
    // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
 
827
    // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e.
538
828
    // it rounds to zero.
539
829
    const uint32_t zero_exponent =
540
830
        (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
541
 
    __ sub(Operand(scratch2), Immediate(zero_exponent));
 
831
    __ sub(scratch2, Immediate(zero_exponent));
542
832
    // ecx already has a Smi zero.
543
833
    __ j(less, &done, Label::kNear);
544
834
 
545
835
    // We have a shifted exponent between 0 and 30 in scratch2.
546
836
    __ shr(scratch2, HeapNumber::kExponentShift);
547
837
    __ mov(ecx, Immediate(30));
548
 
    __ sub(ecx, Operand(scratch2));
 
838
    __ sub(ecx, scratch2);
549
839
 
550
840
    __ bind(&right_exponent);
551
841
    // Here ecx is the shift, scratch is the exponent word.
565
855
    // Shift down 22 bits to get the most significant 10 bits or the low
566
856
    // mantissa word.
567
857
    __ shr(scratch2, 32 - shift_distance);
568
 
    __ or_(scratch2, Operand(scratch));
 
858
    __ or_(scratch2, scratch);
569
859
    // Move down according to the exponent.
570
860
    __ shr_cl(scratch2);
571
861
    // Now the unsigned answer is in scratch2.  We need to move it to ecx and
572
862
    // we may need to fix the sign.
573
863
    Label negative;
574
 
    __ xor_(ecx, Operand(ecx));
 
864
    __ xor_(ecx, ecx);
575
865
    __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset));
576
866
    __ j(greater, &negative, Label::kNear);
577
867
    __ mov(ecx, scratch2);
578
868
    __ jmp(&done, Label::kNear);
579
869
    __ bind(&negative);
580
 
    __ sub(ecx, Operand(scratch2));
 
870
    __ sub(ecx, scratch2);
581
871
    __ bind(&done);
582
872
  }
583
873
}
679
969
  __ JumpIfNotSmi(eax, non_smi, non_smi_near);
680
970
 
681
971
  // We can't handle -0 with smis, so use a type transition for that case.
682
 
  __ test(eax, Operand(eax));
 
972
  __ test(eax, eax);
683
973
  __ j(zero, slow, slow_near);
684
974
 
685
975
  // Try optimistic subtraction '0 - value', saving operand in eax for undo.
686
 
  __ mov(edx, Operand(eax));
 
976
  __ mov(edx, eax);
687
977
  __ Set(eax, Immediate(0));
688
 
  __ sub(eax, Operand(edx));
 
978
  __ sub(eax, edx);
689
979
  __ j(overflow, undo, undo_near);
690
980
  __ ret(0);
691
981
}
706
996
 
707
997
 
708
998
void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) {
709
 
  __ mov(eax, Operand(edx));
 
999
  __ mov(eax, edx);
710
1000
}
711
1001
 
712
1002
 
760
1050
    __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset),
761
1051
            Immediate(HeapNumber::kSignMask));  // Flip sign.
762
1052
  } else {
763
 
    __ mov(edx, Operand(eax));
 
1053
    __ mov(edx, eax);
764
1054
    // edx: operand
765
1055
 
766
1056
    Label slow_allocate_heapnumber, heapnumber_allocated;
768
1058
    __ jmp(&heapnumber_allocated, Label::kNear);
769
1059
 
770
1060
    __ bind(&slow_allocate_heapnumber);
771
 
    __ EnterInternalFrame();
772
 
    __ push(edx);
773
 
    __ CallRuntime(Runtime::kNumberAlloc, 0);
774
 
    __ pop(edx);
775
 
    __ LeaveInternalFrame();
 
1061
    {
 
1062
      FrameScope scope(masm, StackFrame::INTERNAL);
 
1063
      __ push(edx);
 
1064
      __ CallRuntime(Runtime::kNumberAlloc, 0);
 
1065
      __ pop(edx);
 
1066
    }
776
1067
 
777
1068
    __ bind(&heapnumber_allocated);
778
1069
    // eax: allocated 'empty' number
815
1106
    __ jmp(&heapnumber_allocated);
816
1107
 
817
1108
    __ bind(&slow_allocate_heapnumber);
818
 
    __ EnterInternalFrame();
819
 
    // Push the original HeapNumber on the stack. The integer value can't
820
 
    // be stored since it's untagged and not in the smi range (so we can't
821
 
    // smi-tag it). We'll recalculate the value after the GC instead.
822
 
    __ push(ebx);
823
 
    __ CallRuntime(Runtime::kNumberAlloc, 0);
824
 
    // New HeapNumber is in eax.
825
 
    __ pop(edx);
826
 
    __ LeaveInternalFrame();
 
1109
    {
 
1110
      FrameScope scope(masm, StackFrame::INTERNAL);
 
1111
      // Push the original HeapNumber on the stack. The integer value can't
 
1112
      // be stored since it's untagged and not in the smi range (so we can't
 
1113
      // smi-tag it). We'll recalculate the value after the GC instead.
 
1114
      __ push(ebx);
 
1115
      __ CallRuntime(Runtime::kNumberAlloc, 0);
 
1116
      // New HeapNumber is in eax.
 
1117
      __ pop(edx);
 
1118
    }
827
1119
    // IntegerConvert uses ebx and edi as scratch registers.
828
1120
    // This conversion won't go slow-case.
829
1121
    IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow);
833
1125
  }
834
1126
  if (CpuFeatures::IsSupported(SSE2)) {
835
1127
    CpuFeatures::Scope use_sse2(SSE2);
836
 
    __ cvtsi2sd(xmm0, Operand(ecx));
 
1128
    __ cvtsi2sd(xmm0, ecx);
837
1129
    __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
838
1130
  } else {
839
1131
    __ push(ecx);
947
1239
 
948
1240
 
949
1241
void BinaryOpStub::Generate(MacroAssembler* masm) {
 
1242
  // Explicitly allow generation of nested stubs. It is safe here because
 
1243
  // generation code does not use any raw pointers.
 
1244
  AllowStubCallsScope allow_stub_calls(masm, true);
 
1245
 
950
1246
  switch (operands_type_) {
951
1247
    case BinaryOpIC::UNINITIALIZED:
952
1248
      GenerateTypeTransition(masm);
1022
1318
      // eax in case the result is not a smi.
1023
1319
      ASSERT(!left.is(ecx) && !right.is(ecx));
1024
1320
      __ mov(ecx, right);
1025
 
      __ or_(right, Operand(left));  // Bitwise or is commutative.
 
1321
      __ or_(right, left);  // Bitwise or is commutative.
1026
1322
      combined = right;
1027
1323
      break;
1028
1324
 
1034
1330
    case Token::DIV:
1035
1331
    case Token::MOD:
1036
1332
      __ mov(combined, right);
1037
 
      __ or_(combined, Operand(left));
 
1333
      __ or_(combined, left);
1038
1334
      break;
1039
1335
 
1040
1336
    case Token::SHL:
1044
1340
      // for the smi check register.
1045
1341
      ASSERT(!left.is(ecx) && !right.is(ecx));
1046
1342
      __ mov(ecx, right);
1047
 
      __ or_(right, Operand(left));
 
1343
      __ or_(right, left);
1048
1344
      combined = right;
1049
1345
      break;
1050
1346
 
1067
1363
 
1068
1364
    case Token::BIT_XOR:
1069
1365
      ASSERT(right.is(eax));
1070
 
      __ xor_(right, Operand(left));  // Bitwise xor is commutative.
 
1366
      __ xor_(right, left);  // Bitwise xor is commutative.
1071
1367
      break;
1072
1368
 
1073
1369
    case Token::BIT_AND:
1074
1370
      ASSERT(right.is(eax));
1075
 
      __ and_(right, Operand(left));  // Bitwise and is commutative.
 
1371
      __ and_(right, left);  // Bitwise and is commutative.
1076
1372
      break;
1077
1373
 
1078
1374
    case Token::SHL:
1121
1417
 
1122
1418
    case Token::ADD:
1123
1419
      ASSERT(right.is(eax));
1124
 
      __ add(right, Operand(left));  // Addition is commutative.
 
1420
      __ add(right, left);  // Addition is commutative.
1125
1421
      __ j(overflow, &use_fp_on_smis);
1126
1422
      break;
1127
1423
 
1128
1424
    case Token::SUB:
1129
 
      __ sub(left, Operand(right));
 
1425
      __ sub(left, right);
1130
1426
      __ j(overflow, &use_fp_on_smis);
1131
1427
      __ mov(eax, left);
1132
1428
      break;
1140
1436
      // Remove tag from one of the operands (but keep sign).
1141
1437
      __ SmiUntag(right);
1142
1438
      // Do multiplication.
1143
 
      __ imul(right, Operand(left));  // Multiplication is commutative.
 
1439
      __ imul(right, left);  // Multiplication is commutative.
1144
1440
      __ j(overflow, &use_fp_on_smis);
1145
1441
      // Check for negative zero result.  Use combined = left | right.
1146
1442
      __ NegativeZeroTest(right, combined, &use_fp_on_smis);
1151
1447
      // save the left operand.
1152
1448
      __ mov(edi, left);
1153
1449
      // Check for 0 divisor.
1154
 
      __ test(right, Operand(right));
 
1450
      __ test(right, right);
1155
1451
      __ j(zero, &use_fp_on_smis);
1156
1452
      // Sign extend left into edx:eax.
1157
1453
      ASSERT(left.is(eax));
1167
1463
      // Check for negative zero result.  Use combined = left | right.
1168
1464
      __ NegativeZeroTest(eax, combined, &use_fp_on_smis);
1169
1465
      // Check that the remainder is zero.
1170
 
      __ test(edx, Operand(edx));
 
1466
      __ test(edx, edx);
1171
1467
      __ j(not_zero, &use_fp_on_smis);
1172
1468
      // Tag the result and store it in register eax.
1173
1469
      __ SmiTag(eax);
1175
1471
 
1176
1472
    case Token::MOD:
1177
1473
      // Check for 0 divisor.
1178
 
      __ test(right, Operand(right));
 
1474
      __ test(right, right);
1179
1475
      __ j(zero, &not_smis);
1180
1476
 
1181
1477
      // Sign extend left into edx:eax.
1226
1522
        break;
1227
1523
      case Token::ADD:
1228
1524
        // Revert right = right + left.
1229
 
        __ sub(right, Operand(left));
 
1525
        __ sub(right, left);
1230
1526
        break;
1231
1527
      case Token::SUB:
1232
1528
        // Revert left = left - right.
1233
 
        __ add(left, Operand(right));
 
1529
        __ add(left, right);
1234
1530
        break;
1235
1531
      case Token::MUL:
1236
1532
        // Right was clobbered but a copy is in ebx.
1268
1564
          ASSERT_EQ(Token::SHL, op_);
1269
1565
          if (CpuFeatures::IsSupported(SSE2)) {
1270
1566
            CpuFeatures::Scope use_sse2(SSE2);
1271
 
            __ cvtsi2sd(xmm0, Operand(left));
 
1567
            __ cvtsi2sd(xmm0, left);
1272
1568
            __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1273
1569
          } else {
1274
1570
            __ mov(Operand(esp, 1 * kPointerSize), left);
1290
1586
        switch (op_) {
1291
1587
          case Token::ADD:
1292
1588
            // Revert right = right + left.
1293
 
            __ sub(right, Operand(left));
 
1589
            __ sub(right, left);
1294
1590
            break;
1295
1591
          case Token::SUB:
1296
1592
            // Revert left = left - right.
1297
 
            __ add(left, Operand(right));
 
1593
            __ add(left, right);
1298
1594
            break;
1299
1595
          case Token::MUL:
1300
1596
            // Right was clobbered but a copy is in ebx.
1460
1756
}
1461
1757
 
1462
1758
 
 
1759
// Input:
 
1760
//    edx: left operand (tagged)
 
1761
//    eax: right operand (tagged)
 
1762
// Output:
 
1763
//    eax: result (tagged)
1463
1764
void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
1464
1765
  Label call_runtime;
1465
1766
  ASSERT(operands_type_ == BinaryOpIC::INT32);
1469
1770
    case Token::ADD:
1470
1771
    case Token::SUB:
1471
1772
    case Token::MUL:
1472
 
    case Token::DIV: {
 
1773
    case Token::DIV:
 
1774
    case Token::MOD: {
1473
1775
      Label not_floats;
1474
1776
      Label not_int32;
1475
1777
      if (CpuFeatures::IsSupported(SSE2)) {
1476
1778
        CpuFeatures::Scope use_sse2(SSE2);
1477
1779
        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1478
1780
        FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
1479
 
        switch (op_) {
1480
 
          case Token::ADD: __ addsd(xmm0, xmm1); break;
1481
 
          case Token::SUB: __ subsd(xmm0, xmm1); break;
1482
 
          case Token::MUL: __ mulsd(xmm0, xmm1); break;
1483
 
          case Token::DIV: __ divsd(xmm0, xmm1); break;
1484
 
          default: UNREACHABLE();
1485
 
        }
1486
 
        // Check result type if it is currently Int32.
1487
 
        if (result_type_ <= BinaryOpIC::INT32) {
1488
 
          __ cvttsd2si(ecx, Operand(xmm0));
1489
 
          __ cvtsi2sd(xmm2, Operand(ecx));
1490
 
          __ ucomisd(xmm0, xmm2);
1491
 
          __ j(not_zero, &not_int32);
1492
 
          __ j(carry, &not_int32);
1493
 
        }
1494
 
        GenerateHeapResultAllocation(masm, &call_runtime);
1495
 
        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1496
 
        __ ret(0);
 
1781
        if (op_ == Token::MOD) {
 
1782
          GenerateRegisterArgsPush(masm);
 
1783
          __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
 
1784
        } else {
 
1785
          switch (op_) {
 
1786
            case Token::ADD: __ addsd(xmm0, xmm1); break;
 
1787
            case Token::SUB: __ subsd(xmm0, xmm1); break;
 
1788
            case Token::MUL: __ mulsd(xmm0, xmm1); break;
 
1789
            case Token::DIV: __ divsd(xmm0, xmm1); break;
 
1790
            default: UNREACHABLE();
 
1791
          }
 
1792
          // Check result type if it is currently Int32.
 
1793
          if (result_type_ <= BinaryOpIC::INT32) {
 
1794
            __ cvttsd2si(ecx, Operand(xmm0));
 
1795
            __ cvtsi2sd(xmm2, ecx);
 
1796
            __ pcmpeqd(xmm2, xmm0);
 
1797
            __ movmskpd(ecx, xmm2);
 
1798
            __ test(ecx, Immediate(1));
 
1799
            __ j(zero, &not_int32);
 
1800
          }
 
1801
          GenerateHeapResultAllocation(masm, &call_runtime);
 
1802
          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
 
1803
          __ ret(0);
 
1804
        }
1497
1805
      } else {  // SSE2 not available, use FPU.
1498
1806
        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1499
1807
        FloatingPointHelper::LoadFloatOperands(
1501
1809
            ecx,
1502
1810
            FloatingPointHelper::ARGS_IN_REGISTERS);
1503
1811
        FloatingPointHelper::CheckFloatOperandsAreInt32(masm, &not_int32);
1504
 
        switch (op_) {
1505
 
          case Token::ADD: __ faddp(1); break;
1506
 
          case Token::SUB: __ fsubp(1); break;
1507
 
          case Token::MUL: __ fmulp(1); break;
1508
 
          case Token::DIV: __ fdivp(1); break;
1509
 
          default: UNREACHABLE();
 
1812
        if (op_ == Token::MOD) {
 
1813
          // The operands are now on the FPU stack, but we don't need them.
 
1814
          __ fstp(0);
 
1815
          __ fstp(0);
 
1816
          GenerateRegisterArgsPush(masm);
 
1817
          __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
 
1818
        } else {
 
1819
          switch (op_) {
 
1820
            case Token::ADD: __ faddp(1); break;
 
1821
            case Token::SUB: __ fsubp(1); break;
 
1822
            case Token::MUL: __ fmulp(1); break;
 
1823
            case Token::DIV: __ fdivp(1); break;
 
1824
            default: UNREACHABLE();
 
1825
          }
 
1826
          Label after_alloc_failure;
 
1827
          GenerateHeapResultAllocation(masm, &after_alloc_failure);
 
1828
          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
 
1829
          __ ret(0);
 
1830
          __ bind(&after_alloc_failure);
 
1831
          __ fstp(0);  // Pop FPU stack before calling runtime.
 
1832
          __ jmp(&call_runtime);
1510
1833
        }
1511
 
        Label after_alloc_failure;
1512
 
        GenerateHeapResultAllocation(masm, &after_alloc_failure);
1513
 
        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1514
 
        __ ret(0);
1515
 
        __ bind(&after_alloc_failure);
1516
 
        __ ffree();
1517
 
        __ jmp(&call_runtime);
1518
1834
      }
1519
1835
 
1520
1836
      __ bind(&not_floats);
1523
1839
      break;
1524
1840
    }
1525
1841
 
1526
 
    case Token::MOD: {
1527
 
      // For MOD we go directly to runtime in the non-smi case.
1528
 
      break;
1529
 
    }
1530
1842
    case Token::BIT_OR:
1531
1843
    case Token::BIT_AND:
1532
1844
    case Token::BIT_XOR:
1537
1849
      Label not_floats;
1538
1850
      Label not_int32;
1539
1851
      Label non_smi_result;
1540
 
      /*  {
1541
 
        CpuFeatures::Scope use_sse2(SSE2);
1542
 
        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1543
 
        FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
1544
 
        }*/
1545
1852
      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1546
1853
                                                  use_sse3_,
1547
1854
                                                  &not_floats);
1548
1855
      FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_,
1549
1856
                                                        &not_int32);
1550
1857
      switch (op_) {
1551
 
        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
1552
 
        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
1553
 
        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
 
1858
        case Token::BIT_OR:  __ or_(eax, ecx); break;
 
1859
        case Token::BIT_AND: __ and_(eax, ecx); break;
 
1860
        case Token::BIT_XOR: __ xor_(eax, ecx); break;
1554
1861
        case Token::SAR: __ sar_cl(eax); break;
1555
1862
        case Token::SHL: __ shl_cl(eax); break;
1556
1863
        case Token::SHR: __ shr_cl(eax); break;
1574
1881
      if (op_ != Token::SHR) {
1575
1882
        __ bind(&non_smi_result);
1576
1883
        // Allocate a heap number if needed.
1577
 
        __ mov(ebx, Operand(eax));  // ebx: result
 
1884
        __ mov(ebx, eax);  // ebx: result
1578
1885
        Label skip_allocation;
1579
1886
        switch (mode_) {
1580
1887
          case OVERWRITE_LEFT:
1594
1901
        // Store the result in the HeapNumber and return.
1595
1902
        if (CpuFeatures::IsSupported(SSE2)) {
1596
1903
          CpuFeatures::Scope use_sse2(SSE2);
1597
 
          __ cvtsi2sd(xmm0, Operand(ebx));
 
1904
          __ cvtsi2sd(xmm0, ebx);
1598
1905
          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1599
1906
        } else {
1600
1907
          __ mov(Operand(esp, 1 * kPointerSize), ebx);
1612
1919
    default: UNREACHABLE(); break;
1613
1920
  }
1614
1921
 
1615
 
  // If an allocation fails, or SHR or MOD hit a hard case,
1616
 
  // use the runtime system to get the correct result.
 
1922
  // If an allocation fails, or SHR hits a hard case, use the runtime system to
 
1923
  // get the correct result.
1617
1924
  __ bind(&call_runtime);
1618
1925
 
1619
1926
  switch (op_) {
1634
1941
      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
1635
1942
      break;
1636
1943
    case Token::MOD:
1637
 
      GenerateRegisterArgsPush(masm);
1638
 
      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
1639
1944
      break;
1640
1945
    case Token::BIT_OR:
1641
1946
      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
1675
1980
  __ cmp(edx, factory->undefined_value());
1676
1981
  __ j(not_equal, &check, Label::kNear);
1677
1982
  if (Token::IsBitOp(op_)) {
1678
 
    __ xor_(edx, Operand(edx));
 
1983
    __ xor_(edx, edx);
1679
1984
  } else {
1680
1985
    __ mov(edx, Immediate(factory->nan_value()));
1681
1986
  }
1684
1989
  __ cmp(eax, factory->undefined_value());
1685
1990
  __ j(not_equal, &done, Label::kNear);
1686
1991
  if (Token::IsBitOp(op_)) {
1687
 
    __ xor_(eax, Operand(eax));
 
1992
    __ xor_(eax, eax);
1688
1993
  } else {
1689
1994
    __ mov(eax, Immediate(factory->nan_value()));
1690
1995
  }
1736
2041
        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1737
2042
        __ ret(0);
1738
2043
        __ bind(&after_alloc_failure);
1739
 
        __ ffree();
 
2044
        __ fstp(0);  // Pop FPU stack before calling runtime.
1740
2045
        __ jmp(&call_runtime);
1741
2046
      }
1742
2047
 
1762
2067
                                                  use_sse3_,
1763
2068
                                                  &not_floats);
1764
2069
      switch (op_) {
1765
 
        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
1766
 
        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
1767
 
        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
 
2070
        case Token::BIT_OR:  __ or_(eax, ecx); break;
 
2071
        case Token::BIT_AND: __ and_(eax, ecx); break;
 
2072
        case Token::BIT_XOR: __ xor_(eax, ecx); break;
1768
2073
        case Token::SAR: __ sar_cl(eax); break;
1769
2074
        case Token::SHL: __ shl_cl(eax); break;
1770
2075
        case Token::SHR: __ shr_cl(eax); break;
1788
2093
      if (op_ != Token::SHR) {
1789
2094
        __ bind(&non_smi_result);
1790
2095
        // Allocate a heap number if needed.
1791
 
        __ mov(ebx, Operand(eax));  // ebx: result
 
2096
        __ mov(ebx, eax);  // ebx: result
1792
2097
        Label skip_allocation;
1793
2098
        switch (mode_) {
1794
2099
          case OVERWRITE_LEFT:
1808
2113
        // Store the result in the HeapNumber and return.
1809
2114
        if (CpuFeatures::IsSupported(SSE2)) {
1810
2115
          CpuFeatures::Scope use_sse2(SSE2);
1811
 
          __ cvtsi2sd(xmm0, Operand(ebx));
 
2116
          __ cvtsi2sd(xmm0, ebx);
1812
2117
          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1813
2118
        } else {
1814
2119
          __ mov(Operand(esp, 1 * kPointerSize), ebx);
1940
2245
        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1941
2246
        __ ret(0);
1942
2247
        __ bind(&after_alloc_failure);
1943
 
          __ ffree();
1944
 
          __ jmp(&call_runtime);
 
2248
        __ fstp(0);  // Pop FPU stack before calling runtime.
 
2249
        __ jmp(&call_runtime);
1945
2250
      }
1946
2251
        __ bind(&not_floats);
1947
2252
        break;
1961
2266
                                                  use_sse3_,
1962
2267
                                                  &call_runtime);
1963
2268
      switch (op_) {
1964
 
        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
1965
 
        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
1966
 
        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
 
2269
        case Token::BIT_OR:  __ or_(eax, ecx); break;
 
2270
        case Token::BIT_AND: __ and_(eax, ecx); break;
 
2271
        case Token::BIT_XOR: __ xor_(eax, ecx); break;
1967
2272
        case Token::SAR: __ sar_cl(eax); break;
1968
2273
        case Token::SHL: __ shl_cl(eax); break;
1969
2274
        case Token::SHR: __ shr_cl(eax); break;
1987
2292
      if (op_ != Token::SHR) {
1988
2293
        __ bind(&non_smi_result);
1989
2294
        // Allocate a heap number if needed.
1990
 
        __ mov(ebx, Operand(eax));  // ebx: result
 
2295
        __ mov(ebx, eax);  // ebx: result
1991
2296
        Label skip_allocation;
1992
2297
        switch (mode_) {
1993
2298
          case OVERWRITE_LEFT:
2007
2312
        // Store the result in the HeapNumber and return.
2008
2313
        if (CpuFeatures::IsSupported(SSE2)) {
2009
2314
          CpuFeatures::Scope use_sse2(SSE2);
2010
 
          __ cvtsi2sd(xmm0, Operand(ebx));
 
2315
          __ cvtsi2sd(xmm0, ebx);
2011
2316
          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2012
2317
        } else {
2013
2318
          __ mov(Operand(esp, 1 * kPointerSize), ebx);
2117
2422
      __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure);
2118
2423
      // Now edx can be overwritten losing one of the arguments as we are
2119
2424
      // now done and will not need it any more.
2120
 
      __ mov(edx, Operand(ebx));
 
2425
      __ mov(edx, ebx);
2121
2426
      __ bind(&skip_allocation);
2122
2427
      // Use object in edx as a result holder
2123
 
      __ mov(eax, Operand(edx));
 
2428
      __ mov(eax, edx);
2124
2429
      break;
2125
2430
    }
2126
2431
    case OVERWRITE_RIGHT:
2178
2483
    // Then load the low and high words of the double into ebx, edx.
2179
2484
    STATIC_ASSERT(kSmiTagSize == 1);
2180
2485
    __ sar(eax, 1);
2181
 
    __ sub(Operand(esp), Immediate(2 * kPointerSize));
 
2486
    __ sub(esp, Immediate(2 * kPointerSize));
2182
2487
    __ mov(Operand(esp, 0), eax);
2183
2488
    __ fild_s(Operand(esp, 0));
2184
2489
    __ fst_d(Operand(esp, 0));
2189
2494
    // Check if input is a HeapNumber.
2190
2495
    __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2191
2496
    Factory* factory = masm->isolate()->factory();
2192
 
    __ cmp(Operand(ebx), Immediate(factory->heap_number_map()));
 
2497
    __ cmp(ebx, Immediate(factory->heap_number_map()));
2193
2498
    __ j(not_equal, &runtime_call);
2194
2499
    // Input is a HeapNumber. Push it on the FPU stack and load its
2195
2500
    // low and high words into ebx, edx.
2201
2506
  } else {  // UNTAGGED.
2202
2507
    if (CpuFeatures::IsSupported(SSE4_1)) {
2203
2508
      CpuFeatures::Scope sse4_scope(SSE4_1);
2204
 
      __ pextrd(Operand(edx), xmm1, 0x1);  // copy xmm1[63..32] to edx.
 
2509
      __ pextrd(edx, xmm1, 0x1);  // copy xmm1[63..32] to edx.
2205
2510
    } else {
2206
2511
      __ pshufd(xmm0, xmm1, 0x1);
2207
 
      __ movd(Operand(edx), xmm0);
 
2512
      __ movd(edx, xmm0);
2208
2513
    }
2209
 
    __ movd(Operand(ebx), xmm1);
 
2514
    __ movd(ebx, xmm1);
2210
2515
  }
2211
2516
 
2212
2517
  // ST[0] or xmm1  == double value
2215
2520
  // Compute hash (the shifts are arithmetic):
2216
2521
  //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
2217
2522
  __ mov(ecx, ebx);
2218
 
  __ xor_(ecx, Operand(edx));
 
2523
  __ xor_(ecx, edx);
2219
2524
  __ mov(eax, ecx);
2220
2525
  __ sar(eax, 16);
2221
 
  __ xor_(ecx, Operand(eax));
 
2526
  __ xor_(ecx, eax);
2222
2527
  __ mov(eax, ecx);
2223
2528
  __ sar(eax, 8);
2224
 
  __ xor_(ecx, Operand(eax));
 
2529
  __ xor_(ecx, eax);
2225
2530
  ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
2226
 
  __ and_(Operand(ecx),
 
2531
  __ and_(ecx,
2227
2532
          Immediate(TranscendentalCache::SubCache::kCacheSize - 1));
2228
2533
 
2229
2534
  // ST[0] or xmm1 == double value.
2238
2543
  __ mov(eax, Operand(eax, cache_array_index));
2239
2544
  // Eax points to the cache for the type type_.
2240
2545
  // If NULL, the cache hasn't been initialized yet, so go through runtime.
2241
 
  __ test(eax, Operand(eax));
 
2546
  __ test(eax, eax);
2242
2547
  __ j(zero, &runtime_call_clear_stack);
2243
2548
#ifdef DEBUG
2244
2549
  // Check that the layout of cache elements match expectations.
2264
2569
  __ cmp(edx, Operand(ecx, kIntSize));
2265
2570
  __ j(not_equal, &cache_miss, Label::kNear);
2266
2571
  // Cache hit!
 
2572
  Counters* counters = masm->isolate()->counters();
 
2573
  __ IncrementCounter(counters->transcendental_cache_hit(), 1);
2267
2574
  __ mov(eax, Operand(ecx, 2 * kIntSize));
2268
2575
  if (tagged) {
2269
2576
    __ fstp(0);
2274
2581
  }
2275
2582
 
2276
2583
  __ bind(&cache_miss);
 
2584
  __ IncrementCounter(counters->transcendental_cache_miss(), 1);
2277
2585
  // Update cache with new value.
2278
2586
  // We are short on registers, so use no_reg as scratch.
2279
2587
  // This gives slightly larger code.
2281
2589
    __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
2282
2590
  } else {  // UNTAGGED.
2283
2591
    __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
2284
 
    __ sub(Operand(esp), Immediate(kDoubleSize));
 
2592
    __ sub(esp, Immediate(kDoubleSize));
2285
2593
    __ movdbl(Operand(esp, 0), xmm1);
2286
2594
    __ fld_d(Operand(esp, 0));
2287
 
    __ add(Operand(esp), Immediate(kDoubleSize));
 
2595
    __ add(esp, Immediate(kDoubleSize));
2288
2596
  }
2289
 
  GenerateOperation(masm);
 
2597
  GenerateOperation(masm, type_);
2290
2598
  __ mov(Operand(ecx, 0), ebx);
2291
2599
  __ mov(Operand(ecx, kIntSize), edx);
2292
2600
  __ mov(Operand(ecx, 2 * kIntSize), eax);
2299
2607
 
2300
2608
    // Skip cache and return answer directly, only in untagged case.
2301
2609
    __ bind(&skip_cache);
2302
 
    __ sub(Operand(esp), Immediate(kDoubleSize));
 
2610
    __ sub(esp, Immediate(kDoubleSize));
2303
2611
    __ movdbl(Operand(esp, 0), xmm1);
2304
2612
    __ fld_d(Operand(esp, 0));
2305
 
    GenerateOperation(masm);
 
2613
    GenerateOperation(masm, type_);
2306
2614
    __ fstp_d(Operand(esp, 0));
2307
2615
    __ movdbl(xmm1, Operand(esp, 0));
2308
 
    __ add(Operand(esp), Immediate(kDoubleSize));
 
2616
    __ add(esp, Immediate(kDoubleSize));
2309
2617
    // We return the value in xmm1 without adding it to the cache, but
2310
2618
    // we cause a scavenging GC so that future allocations will succeed.
2311
 
    __ EnterInternalFrame();
2312
 
    // Allocate an unused object bigger than a HeapNumber.
2313
 
    __ push(Immediate(Smi::FromInt(2 * kDoubleSize)));
2314
 
    __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
2315
 
    __ LeaveInternalFrame();
 
2619
    {
 
2620
      FrameScope scope(masm, StackFrame::INTERNAL);
 
2621
      // Allocate an unused object bigger than a HeapNumber.
 
2622
      __ push(Immediate(Smi::FromInt(2 * kDoubleSize)));
 
2623
      __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
 
2624
    }
2316
2625
    __ Ret();
2317
2626
  }
2318
2627
 
2329
2638
    __ bind(&runtime_call);
2330
2639
    __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
2331
2640
    __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
2332
 
    __ EnterInternalFrame();
2333
 
    __ push(eax);
2334
 
    __ CallRuntime(RuntimeFunction(), 1);
2335
 
    __ LeaveInternalFrame();
 
2641
    {
 
2642
      FrameScope scope(masm, StackFrame::INTERNAL);
 
2643
      __ push(eax);
 
2644
      __ CallRuntime(RuntimeFunction(), 1);
 
2645
    }
2336
2646
    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2337
2647
    __ Ret();
2338
2648
  }
2343
2653
  switch (type_) {
2344
2654
    case TranscendentalCache::SIN: return Runtime::kMath_sin;
2345
2655
    case TranscendentalCache::COS: return Runtime::kMath_cos;
 
2656
    case TranscendentalCache::TAN: return Runtime::kMath_tan;
2346
2657
    case TranscendentalCache::LOG: return Runtime::kMath_log;
2347
2658
    default:
2348
2659
      UNIMPLEMENTED();
2351
2662
}
2352
2663
 
2353
2664
 
2354
 
void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
 
2665
void TranscendentalCacheStub::GenerateOperation(
 
2666
    MacroAssembler* masm, TranscendentalCache::Type type) {
2355
2667
  // Only free register is edi.
2356
2668
  // Input value is on FP stack, and also in ebx/edx.
2357
2669
  // Input value is possibly in xmm1.
2358
2670
  // Address of result (a newly allocated HeapNumber) may be in eax.
2359
 
  if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) {
 
2671
  if (type == TranscendentalCache::SIN ||
 
2672
      type == TranscendentalCache::COS ||
 
2673
      type == TranscendentalCache::TAN) {
2360
2674
    // Both fsin and fcos require arguments in the range +/-2^63 and
2361
2675
    // return NaN for infinities and NaN. They can share all code except
2362
2676
    // the actual fsin/fcos operation.
2364
2678
    // If argument is outside the range -2^63..2^63, fsin/cos doesn't
2365
2679
    // work. We must reduce it to the appropriate range.
2366
2680
    __ mov(edi, edx);
2367
 
    __ and_(Operand(edi), Immediate(0x7ff00000));  // Exponent only.
 
2681
    __ and_(edi, Immediate(0x7ff00000));  // Exponent only.
2368
2682
    int supported_exponent_limit =
2369
2683
        (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift;
2370
 
    __ cmp(Operand(edi), Immediate(supported_exponent_limit));
 
2684
    __ cmp(edi, Immediate(supported_exponent_limit));
2371
2685
    __ j(below, &in_range, Label::kNear);
2372
2686
    // Check for infinity and NaN. Both return NaN for sin.
2373
 
    __ cmp(Operand(edi), Immediate(0x7ff00000));
 
2687
    __ cmp(edi, Immediate(0x7ff00000));
2374
2688
    Label non_nan_result;
2375
2689
    __ j(not_equal, &non_nan_result, Label::kNear);
2376
2690
    // Input is +/-Infinity or NaN. Result is NaN.
2379
2693
    __ push(Immediate(0x7ff80000));
2380
2694
    __ push(Immediate(0));
2381
2695
    __ fld_d(Operand(esp, 0));
2382
 
    __ add(Operand(esp), Immediate(2 * kPointerSize));
 
2696
    __ add(esp, Immediate(2 * kPointerSize));
2383
2697
    __ jmp(&done, Label::kNear);
2384
2698
 
2385
2699
    __ bind(&non_nan_result);
2395
2709
      __ fwait();
2396
2710
      __ fnstsw_ax();
2397
2711
      // Clear if Illegal Operand or Zero Division exceptions are set.
2398
 
      __ test(Operand(eax), Immediate(5));
 
2712
      __ test(eax, Immediate(5));
2399
2713
      __ j(zero, &no_exceptions, Label::kNear);
2400
2714
      __ fnclex();
2401
2715
      __ bind(&no_exceptions);
2408
2722
      __ fprem1();
2409
2723
      __ fwait();
2410
2724
      __ fnstsw_ax();
2411
 
      __ test(Operand(eax), Immediate(0x400 /* C2 */));
 
2725
      __ test(eax, Immediate(0x400 /* C2 */));
2412
2726
      // If C2 is set, computation only has partial result. Loop to
2413
2727
      // continue computation.
2414
2728
      __ j(not_zero, &partial_remainder_loop);
2420
2734
 
2421
2735
    // FPU Stack: input % 2*pi
2422
2736
    __ bind(&in_range);
2423
 
    switch (type_) {
 
2737
    switch (type) {
2424
2738
      case TranscendentalCache::SIN:
2425
2739
        __ fsin();
2426
2740
        break;
2427
2741
      case TranscendentalCache::COS:
2428
2742
        __ fcos();
2429
2743
        break;
 
2744
      case TranscendentalCache::TAN:
 
2745
        // FPTAN calculates tangent onto st(0) and pushes 1.0 onto the
 
2746
        // FP register stack.
 
2747
        __ fptan();
 
2748
        __ fstp(0);  // Pop FP register stack.
 
2749
        break;
2430
2750
      default:
2431
2751
        UNREACHABLE();
2432
2752
    }
2433
2753
    __ bind(&done);
2434
2754
  } else {
2435
 
    ASSERT(type_ == TranscendentalCache::LOG);
 
2755
    ASSERT(type == TranscendentalCache::LOG);
2436
2756
    __ fldln2();
2437
2757
    __ fxch();
2438
2758
    __ fyl2x();
2541
2861
 
2542
2862
  __ bind(&load_smi_edx);
2543
2863
  __ SmiUntag(edx);  // Untag smi before converting to float.
2544
 
  __ cvtsi2sd(xmm0, Operand(edx));
 
2864
  __ cvtsi2sd(xmm0, edx);
2545
2865
  __ SmiTag(edx);  // Retag smi for heap number overwriting test.
2546
2866
  __ jmp(&load_eax);
2547
2867
 
2548
2868
  __ bind(&load_smi_eax);
2549
2869
  __ SmiUntag(eax);  // Untag smi before converting to float.
2550
 
  __ cvtsi2sd(xmm1, Operand(eax));
 
2870
  __ cvtsi2sd(xmm1, eax);
2551
2871
  __ SmiTag(eax);  // Retag smi for heap number overwriting test.
2552
2872
 
2553
2873
  __ bind(&done);
2571
2891
  __ jmp(not_numbers);  // Argument in eax is not a number.
2572
2892
  __ bind(&load_smi_edx);
2573
2893
  __ SmiUntag(edx);  // Untag smi before converting to float.
2574
 
  __ cvtsi2sd(xmm0, Operand(edx));
 
2894
  __ cvtsi2sd(xmm0, edx);
2575
2895
  __ SmiTag(edx);  // Retag smi for heap number overwriting test.
2576
2896
  __ jmp(&load_eax);
2577
2897
  __ bind(&load_smi_eax);
2578
2898
  __ SmiUntag(eax);  // Untag smi before converting to float.
2579
 
  __ cvtsi2sd(xmm1, Operand(eax));
 
2899
  __ cvtsi2sd(xmm1, eax);
2580
2900
  __ SmiTag(eax);  // Retag smi for heap number overwriting test.
2581
2901
  __ jmp(&done, Label::kNear);
2582
2902
  __ bind(&load_float_eax);
2592
2912
  __ mov(scratch, left);
2593
2913
  ASSERT(!scratch.is(right));  // We're about to clobber scratch.
2594
2914
  __ SmiUntag(scratch);
2595
 
  __ cvtsi2sd(xmm0, Operand(scratch));
 
2915
  __ cvtsi2sd(xmm0, scratch);
2596
2916
 
2597
2917
  __ mov(scratch, right);
2598
2918
  __ SmiUntag(scratch);
2599
 
  __ cvtsi2sd(xmm1, Operand(scratch));
 
2919
  __ cvtsi2sd(xmm1, scratch);
2600
2920
}
2601
2921
 
2602
2922
 
2604
2924
                                                    Label* non_int32,
2605
2925
                                                    Register scratch) {
2606
2926
  __ cvttsd2si(scratch, Operand(xmm0));
2607
 
  __ cvtsi2sd(xmm2, Operand(scratch));
 
2927
  __ cvtsi2sd(xmm2, scratch);
2608
2928
  __ ucomisd(xmm0, xmm2);
2609
2929
  __ j(not_zero, non_int32);
2610
2930
  __ j(carry, non_int32);
2611
2931
  __ cvttsd2si(scratch, Operand(xmm1));
2612
 
  __ cvtsi2sd(xmm2, Operand(scratch));
 
2932
  __ cvtsi2sd(xmm2, scratch);
2613
2933
  __ ucomisd(xmm1, xmm2);
2614
2934
  __ j(not_zero, non_int32);
2615
2935
  __ j(carry, non_int32);
2703
3023
 
2704
3024
 
2705
3025
void MathPowStub::Generate(MacroAssembler* masm) {
2706
 
  // Registers are used as follows:
2707
 
  // edx = base
2708
 
  // eax = exponent
2709
 
  // ecx = temporary, result
2710
 
 
2711
3026
  CpuFeatures::Scope use_sse2(SSE2);
2712
 
  Label allocate_return, call_runtime;
2713
 
 
2714
 
  // Load input parameters.
2715
 
  __ mov(edx, Operand(esp, 2 * kPointerSize));
2716
 
  __ mov(eax, Operand(esp, 1 * kPointerSize));
2717
 
 
2718
 
  // Save 1 in xmm3 - we need this several times later on.
2719
 
  __ mov(ecx, Immediate(1));
2720
 
  __ cvtsi2sd(xmm3, Operand(ecx));
2721
 
 
2722
 
  Label exponent_nonsmi;
2723
 
  Label base_nonsmi;
2724
 
  // If the exponent is a heap number go to that specific case.
2725
 
  __ JumpIfNotSmi(eax, &exponent_nonsmi);
2726
 
  __ JumpIfNotSmi(edx, &base_nonsmi);
2727
 
 
2728
 
  // Optimized version when both exponent and base are smis.
2729
 
  Label powi;
2730
 
  __ SmiUntag(edx);
2731
 
  __ cvtsi2sd(xmm0, Operand(edx));
2732
 
  __ jmp(&powi);
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);
2739
 
 
2740
 
  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2741
 
 
2742
 
  // Optimized version of pow if exponent is a smi.
2743
 
  // xmm0 contains the base.
2744
 
  __ bind(&powi);
2745
 
  __ SmiUntag(eax);
2746
 
 
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.
2749
 
  __ mov(edx, eax);
 
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;
 
3035
 
 
3036
  Label call_runtime, done, exponent_not_smi, int_exponent;
 
3037
 
 
3038
  // Save 1 in double_result - we need this several times later on.
 
3039
  __ mov(scratch, Immediate(1));
 
3040
  __ cvtsi2sd(double_result, scratch);
 
3041
 
 
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));
 
3049
 
 
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);
 
3054
 
 
3055
    __ movdbl(double_base, FieldOperand(base, HeapNumber::kValueOffset));
 
3056
    __ jmp(&unpack_exponent, Label::kNear);
 
3057
 
 
3058
    __ bind(&base_is_smi);
 
3059
    __ SmiUntag(base);
 
3060
    __ cvtsi2sd(double_base, base);
 
3061
 
 
3062
    __ bind(&unpack_exponent);
 
3063
    __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
 
3064
    __ SmiUntag(exponent);
 
3065
    __ jmp(&int_exponent);
 
3066
 
 
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);
 
3077
 
 
3078
    __ bind(&exponent_not_smi);
 
3079
    __ movdbl(double_exponent,
 
3080
              FieldOperand(exponent, HeapNumber::kValueOffset));
 
3081
  }
 
3082
 
 
3083
  if (exponent_type_ != INTEGER) {
 
3084
    Label fast_power;
 
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);
 
3094
 
 
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;
 
3100
      // Test for 0.5.
 
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, &not_plus_half, Label::kNear);
 
3108
 
 
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);
 
3121
 
 
3122
      // Set result to Infinity in the special case.
 
3123
      __ xorps(double_result, double_result);
 
3124
      __ subsd(double_result, double_scratch);
 
3125
      __ jmp(&done);
 
3126
 
 
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);
 
3132
      __ jmp(&done);
 
3133
 
 
3134
      // Test for -0.5.
 
3135
      __ bind(&not_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);
 
3141
 
 
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);
 
3154
 
 
3155
      // Set result to 0 in the special case.
 
3156
      __ xorps(double_result, double_result);
 
3157
      __ jmp(&done);
 
3158
 
 
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);
 
3165
      __ jmp(&done);
 
3166
    }
 
3167
 
 
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
 
3178
 
 
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))
 
3182
    __ fyl2x();    // X
 
3183
    __ fld(0);     // X, X
 
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)
 
3193
    __ fstp(1);
 
3194
    // Bail out to runtime in case of exceptions in the status word.
 
3195
    __ fnstsw_ax();
 
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));
 
3201
    __ jmp(&done);
 
3202
 
 
3203
    __ bind(&fast_power_failed);
 
3204
    __ fninit();
 
3205
    __ add(esp, Immediate(kDoubleSize));
 
3206
    __ jmp(&call_runtime);
 
3207
  }
 
3208
 
 
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.
2750
3215
 
2751
3216
  // Get absolute value of exponent.
2752
 
  Label no_neg;
2753
 
  __ cmp(eax, 0);
2754
 
  __ j(greater_equal, &no_neg, Label::kNear);
2755
 
  __ neg(eax);
 
3217
  Label no_neg, while_true, while_false;
 
3218
  __ test(scratch, scratch);
 
3219
  __ j(positive, &no_neg, Label::kNear);
 
3220
  __ neg(scratch);
2756
3221
  __ bind(&no_neg);
2757
3222
 
2758
 
  // Load xmm1 with 1.
2759
 
  __ movsd(xmm1, xmm3);
2760
 
  Label while_true;
2761
 
  Label no_multiply;
 
3223
  __ j(zero, &while_false, Label::kNear);
 
3224
  __ shr(scratch, 1);
 
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);
2762
3230
 
2763
3231
  __ bind(&while_true);
2764
 
  __ shr(eax, 1);
2765
 
  __ j(not_carry, &no_multiply, Label::kNear);
2766
 
  __ mulsd(xmm1, xmm0);
2767
 
  __ bind(&no_multiply);
2768
 
  __ mulsd(xmm0, xmm0);
 
3232
  __ shr(scratch, 1);
 
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);
2770
3237
 
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);
2784
 
 
2785
 
  // exponent (or both) is a heapnumber - no matter what we should now work
2786
 
  // on doubles.
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);
2795
 
 
2796
 
  Label base_not_smi;
2797
 
  Label handle_special_cases;
2798
 
  __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear);
2799
 
  __ SmiUntag(edx);
2800
 
  __ cvtsi2sd(xmm0, Operand(edx));
2801
 
  __ jmp(&handle_special_cases, Label::kNear);
2802
 
 
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));
2813
 
 
2814
 
  // base is in xmm0 and exponent is in xmm1.
2815
 
  __ bind(&handle_special_cases);
2816
 
  Label not_minus_half;
2817
 
  // Test for -0.5.
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, &not_minus_half, Label::kNear);
2825
 
 
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);
2834
 
 
2835
 
  // Test for 0.5.
2836
 
  __ bind(&not_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);
2848
 
 
2849
 
  __ bind(&allocate_return);
2850
 
  __ AllocateHeapNumber(ecx, eax, edx, &call_runtime);
2851
 
  __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm1);
2852
 
  __ mov(eax, ecx);
2853
 
  __ ret(2 * kPointerSize);
2854
 
 
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);
 
3254
 
 
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);
 
3261
 
 
3262
    // The stub is called from non-optimized code, which expects the result
 
3263
    // as heap number in exponent.
 
3264
    __ bind(&done);
 
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);
 
3269
  } else {
 
3270
    __ bind(&call_runtime);
 
3271
    {
 
3272
      AllowExternalCallThatCantCauseGC scope(masm);
 
3273
      __ PrepareCallCFunction(4, scratch);
 
3274
      __ movdbl(Operand(esp, 0 * kDoubleSize), double_base);
 
3275
      __ movdbl(Operand(esp, 1 * kDoubleSize), double_exponent);
 
3276
      __ CallCFunction(
 
3277
          ExternalReference::power_double_double_function(masm->isolate()), 4);
 
3278
    }
 
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));
 
3285
 
 
3286
    __ bind(&done);
 
3287
    __ IncrementCounter(counters->math_pow(), 1);
 
3288
    __ ret(0);
 
3289
  }
2857
3290
}
2858
3291
 
2859
3292
 
2873
3306
  Label adaptor;
2874
3307
  __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2875
3308
  __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
2876
 
  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
 
3309
  __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2877
3310
  __ j(equal, &adaptor, Label::kNear);
2878
3311
 
2879
3312
  // Check index against formal parameters count limit passed in
2880
3313
  // through register eax. Use unsigned comparison to get negative
2881
3314
  // check for free.
2882
 
  __ cmp(edx, Operand(eax));
 
3315
  __ cmp(edx, eax);
2883
3316
  __ j(above_equal, &slow, Label::kNear);
2884
3317
 
2885
3318
  // Read the argument from the stack and return it.
2895
3328
  // comparison to get negative check for free.
2896
3329
  __ bind(&adaptor);
2897
3330
  __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2898
 
  __ cmp(edx, Operand(ecx));
 
3331
  __ cmp(edx, ecx);
2899
3332
  __ j(above_equal, &slow, Label::kNear);
2900
3333
 
2901
3334
  // Read the argument from the stack and return it.
2926
3359
  Label runtime;
2927
3360
  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2928
3361
  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
2929
 
  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
 
3362
  __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2930
3363
  __ j(not_equal, &runtime, Label::kNear);
2931
3364
 
2932
3365
  // Patch the arguments.length and the parameters pointer.
2957
3390
  Label adaptor_frame, try_allocate;
2958
3391
  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2959
3392
  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
2960
 
  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
 
3393
  __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2961
3394
  __ j(equal, &adaptor_frame, Label::kNear);
2962
3395
 
2963
3396
  // No adaptor, parameter count = argument count.
2976
3409
  // esp[4] = parameter count (tagged)
2977
3410
  // esp[8] = address of receiver argument
2978
3411
  // Compute the mapped parameter count = min(ebx, ecx) in ebx.
2979
 
  __ cmp(ebx, Operand(ecx));
 
3412
  __ cmp(ebx, ecx);
2980
3413
  __ j(less_equal, &try_allocate, Label::kNear);
2981
3414
  __ mov(ebx, ecx);
2982
3415
 
2990
3423
  const int kParameterMapHeaderSize =
2991
3424
      FixedArray::kHeaderSize + 2 * kPointerSize;
2992
3425
  Label no_parameter_map;
2993
 
  __ test(ebx, Operand(ebx));
 
3426
  __ test(ebx, ebx);
2994
3427
  __ j(zero, &no_parameter_map, Label::kNear);
2995
3428
  __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize));
2996
3429
  __ bind(&no_parameter_map);
2999
3432
  __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
3000
3433
 
3001
3434
  // 3. Arguments object.
3002
 
  __ add(Operand(ebx), Immediate(Heap::kArgumentsObjectSize));
 
3435
  __ add(ebx, Immediate(Heap::kArgumentsObjectSize));
3003
3436
 
3004
3437
  // Do the allocation of all three objects in one go.
3005
3438
  __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
3009
3442
  // esp[0] = mapped parameter count (tagged)
3010
3443
  // esp[8] = parameter count (tagged)
3011
3444
  // esp[12] = address of receiver argument
3012
 
  // Get the arguments boilerplate from the current (global) context into edi.
 
3445
  // Get the arguments boilerplate from the current native context into edi.
3013
3446
  Label has_mapped_parameters, copy;
3014
 
  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
3015
 
  __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
 
3447
  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
 
3448
  __ mov(edi, FieldOperand(edi, GlobalObject::kNativeContextOffset));
3016
3449
  __ mov(ebx, Operand(esp, 0 * kPointerSize));
3017
 
  __ test(ebx, Operand(ebx));
 
3450
  __ test(ebx, ebx);
3018
3451
  __ j(not_zero, &has_mapped_parameters, Label::kNear);
3019
3452
  __ mov(edi, Operand(edi,
3020
3453
         Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX)));
3038
3471
    __ mov(FieldOperand(eax, i), edx);
3039
3472
  }
3040
3473
 
3041
 
  // Setup the callee in-object property.
 
3474
  // Set up the callee in-object property.
3042
3475
  STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
3043
3476
  __ mov(edx, Operand(esp, 4 * kPointerSize));
3044
3477
  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
3051
3484
                      Heap::kArgumentsLengthIndex * kPointerSize),
3052
3485
         ecx);
3053
3486
 
3054
 
  // Setup the elements pointer in the allocated arguments object.
 
3487
  // Set up the elements pointer in the allocated arguments object.
3055
3488
  // If we allocated a parameter map, edi will point there, otherwise to the
3056
3489
  // backing store.
3057
3490
  __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize));
3069
3502
 
3070
3503
  // Initialize parameter map. If there are no mapped arguments, we're done.
3071
3504
  Label skip_parameter_map;
3072
 
  __ test(ebx, Operand(ebx));
 
3505
  __ test(ebx, ebx);
3073
3506
  __ j(zero, &skip_parameter_map);
3074
3507
 
3075
3508
  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
3093
3526
  __ mov(eax, Operand(esp, 2 * kPointerSize));
3094
3527
  __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
3095
3528
  __ add(ebx, Operand(esp, 4 * kPointerSize));
3096
 
  __ sub(ebx, Operand(eax));
 
3529
  __ sub(ebx, eax);
3097
3530
  __ mov(ecx, FACTORY->the_hole_value());
3098
3531
  __ mov(edx, edi);
3099
3532
  __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize));
3110
3543
  __ jmp(&parameters_test, Label::kNear);
3111
3544
 
3112
3545
  __ bind(&parameters_loop);
3113
 
  __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
 
3546
  __ sub(eax, Immediate(Smi::FromInt(1)));
3114
3547
  __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx);
3115
3548
  __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx);
3116
 
  __ add(Operand(ebx), Immediate(Smi::FromInt(1)));
 
3549
  __ add(ebx, Immediate(Smi::FromInt(1)));
3117
3550
  __ bind(&parameters_test);
3118
 
  __ test(eax, Operand(eax));
 
3551
  __ test(eax, eax);
3119
3552
  __ j(not_zero, &parameters_loop, Label::kNear);
3120
3553
  __ pop(ecx);
3121
3554
 
3135
3568
  Label arguments_loop, arguments_test;
3136
3569
  __ mov(ebx, Operand(esp, 1 * kPointerSize));
3137
3570
  __ mov(edx, Operand(esp, 4 * kPointerSize));
3138
 
  __ sub(Operand(edx), ebx);  // Is there a smarter way to do negative scaling?
3139
 
  __ sub(Operand(edx), ebx);
 
3571
  __ sub(edx, ebx);  // Is there a smarter way to do negative scaling?
 
3572
  __ sub(edx, ebx);
3140
3573
  __ jmp(&arguments_test, Label::kNear);
3141
3574
 
3142
3575
  __ bind(&arguments_loop);
3143
 
  __ sub(Operand(edx), Immediate(kPointerSize));
 
3576
  __ sub(edx, Immediate(kPointerSize));
3144
3577
  __ mov(eax, Operand(edx, 0));
3145
3578
  __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax);
3146
 
  __ add(Operand(ebx), Immediate(Smi::FromInt(1)));
 
3579
  __ add(ebx, Immediate(Smi::FromInt(1)));
3147
3580
 
3148
3581
  __ bind(&arguments_test);
3149
 
  __ cmp(ebx, Operand(ecx));
 
3582
  __ cmp(ebx, ecx);
3150
3583
  __ j(less, &arguments_loop, Label::kNear);
3151
3584
 
3152
3585
  // Restore.
3160
3593
  __ bind(&runtime);
3161
3594
  __ pop(eax);  // Remove saved parameter count.
3162
3595
  __ mov(Operand(esp, 1 * kPointerSize), ecx);  // Patch argument count.
3163
 
  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
 
3596
  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
3164
3597
}
3165
3598
 
3166
3599
 
3174
3607
  Label adaptor_frame, try_allocate, runtime;
3175
3608
  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3176
3609
  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
3177
 
  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
 
3610
  __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3178
3611
  __ j(equal, &adaptor_frame, Label::kNear);
3179
3612
 
3180
3613
  // Get the length from the frame.
3193
3626
  // the arguments object and the elements array.
3194
3627
  Label add_arguments_object;
3195
3628
  __ bind(&try_allocate);
3196
 
  __ test(ecx, Operand(ecx));
 
3629
  __ test(ecx, ecx);
3197
3630
  __ j(zero, &add_arguments_object, Label::kNear);
3198
3631
  __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
3199
3632
  __ bind(&add_arguments_object);
3200
 
  __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSizeStrict));
 
3633
  __ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict));
3201
3634
 
3202
3635
  // Do the allocation of both objects in one go.
3203
3636
  __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
3204
3637
 
3205
 
  // Get the arguments boilerplate from the current (global) context.
3206
 
  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
3207
 
  __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
 
3638
  // Get the arguments boilerplate from the current native context.
 
3639
  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
 
3640
  __ mov(edi, FieldOperand(edi, GlobalObject::kNativeContextOffset));
3208
3641
  const int offset =
3209
3642
      Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX);
3210
3643
  __ mov(edi, Operand(edi, offset));
3224
3657
 
3225
3658
  // If there are no actual arguments, we're done.
3226
3659
  Label done;
3227
 
  __ test(ecx, Operand(ecx));
 
3660
  __ test(ecx, ecx);
3228
3661
  __ j(zero, &done, Label::kNear);
3229
3662
 
3230
3663
  // Get the parameters pointer from the stack.
3231
3664
  __ mov(edx, Operand(esp, 2 * kPointerSize));
3232
3665
 
3233
 
  // Setup the elements pointer in the allocated arguments object and
 
3666
  // Set up the elements pointer in the allocated arguments object and
3234
3667
  // initialize the header in the elements fixed array.
3235
3668
  __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict));
3236
3669
  __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
3246
3679
  __ bind(&loop);
3247
3680
  __ mov(ebx, Operand(edx, -1 * kPointerSize));  // Skip receiver.
3248
3681
  __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx);
3249
 
  __ add(Operand(edi), Immediate(kPointerSize));
3250
 
  __ sub(Operand(edx), Immediate(kPointerSize));
 
3682
  __ add(edi, Immediate(kPointerSize));
 
3683
  __ sub(edx, Immediate(kPointerSize));
3251
3684
  __ dec(ecx);
3252
3685
  __ j(not_zero, &loop);
3253
3686
 
3268
3701
#ifdef V8_INTERPRETED_REGEXP
3269
3702
  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
3270
3703
#else  // V8_INTERPRETED_REGEXP
3271
 
  if (!FLAG_regexp_entry_native) {
3272
 
    __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
3273
 
    return;
3274
 
  }
3275
3704
 
3276
3705
  // Stack frame on entry.
3277
3706
  //  esp[0]: return address
3294
3723
  ExternalReference address_of_regexp_stack_memory_size =
3295
3724
      ExternalReference::address_of_regexp_stack_memory_size(masm->isolate());
3296
3725
  __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
3297
 
  __ test(ebx, Operand(ebx));
 
3726
  __ test(ebx, ebx);
3298
3727
  __ j(zero, &runtime);
3299
3728
 
3300
3729
  // Check that the first argument is a JSRegExp object.
3315
3744
  // ecx: RegExp data (FixedArray)
3316
3745
  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
3317
3746
  __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset));
3318
 
  __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
 
3747
  __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
3319
3748
  __ j(not_equal, &runtime);
3320
3749
 
3321
3750
  // ecx: RegExp data (FixedArray)
3325
3754
  // uses the asumption that smis are 2 * their untagged value.
3326
3755
  STATIC_ASSERT(kSmiTag == 0);
3327
3756
  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
3328
 
  __ add(Operand(edx), Immediate(2));  // edx was a smi.
 
3757
  __ add(edx, Immediate(2));  // edx was a smi.
3329
3758
  // Check that the static offsets vector buffer is large enough.
3330
 
  __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize);
 
3759
  __ cmp(edx, Isolate::kJSRegexpStaticOffsetsVectorSize);
3331
3760
  __ j(above, &runtime);
3332
3761
 
3333
3762
  // ecx: RegExp data (FixedArray)
3347
3776
  // string length. A negative value will be greater (unsigned comparison).
3348
3777
  __ mov(eax, Operand(esp, kPreviousIndexOffset));
3349
3778
  __ JumpIfNotSmi(eax, &runtime);
3350
 
  __ cmp(eax, Operand(ebx));
 
3779
  __ cmp(eax, ebx);
3351
3780
  __ j(above_equal, &runtime);
3352
3781
 
3353
3782
  // ecx: RegExp data (FixedArray)
3367
3796
  // additional information.
3368
3797
  __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset));
3369
3798
  __ SmiUntag(eax);
3370
 
  __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead));
3371
 
  __ cmp(edx, Operand(eax));
 
3799
  __ add(edx, Immediate(RegExpImpl::kLastMatchOverhead));
 
3800
  __ cmp(edx, eax);
3372
3801
  __ j(greater, &runtime);
3373
3802
 
3374
3803
  // Reset offset for possibly sliced string.
3380
3809
  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3381
3810
  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
3382
3811
  // First check for flat two byte string.
3383
 
  __ and_(ebx,
3384
 
          kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
 
3812
  __ and_(ebx, kIsNotStringMask |
 
3813
               kStringRepresentationMask |
 
3814
               kStringEncodingMask |
 
3815
               kShortExternalStringMask);
3385
3816
  STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
3386
3817
  __ j(zero, &seq_two_byte_string, Label::kNear);
3387
 
  // Any other flat string must be a flat ascii string.
3388
 
  __ and_(Operand(ebx),
3389
 
          Immediate(kIsNotStringMask | kStringRepresentationMask));
 
3818
  // Any other flat string must be a flat ASCII string.  None of the following
 
3819
  // string type tests will succeed if subject is not a string or a short
 
3820
  // external string.
 
3821
  __ and_(ebx, Immediate(kIsNotStringMask |
 
3822
                         kStringRepresentationMask |
 
3823
                         kShortExternalStringMask));
3390
3824
  __ j(zero, &seq_ascii_string, Label::kNear);
3391
3825
 
 
3826
  // ebx: whether subject is a string and if yes, its string representation
3392
3827
  // Check for flat cons string or sliced string.
3393
3828
  // A flat cons string is a cons string where the second part is the empty
3394
3829
  // string. In that case the subject string is just the first part of the cons
3395
3830
  // string. Also in this case the first part of the cons string is known to be
3396
3831
  // a sequential string or an external string.
3397
3832
  // In the case of a sliced string its offset has to be taken into account.
3398
 
  Label cons_string, check_encoding;
 
3833
  Label cons_string, external_string, check_encoding;
3399
3834
  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
3400
3835
  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
3401
 
  __ cmp(Operand(ebx), Immediate(kExternalStringTag));
 
3836
  STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
 
3837
  STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
 
3838
  __ cmp(ebx, Immediate(kExternalStringTag));
3402
3839
  __ j(less, &cons_string);
3403
 
  __ j(equal, &runtime);
 
3840
  __ j(equal, &external_string);
 
3841
 
 
3842
  // Catch non-string subject or short external string.
 
3843
  STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
 
3844
  __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag));
 
3845
  __ j(not_zero, &runtime);
3404
3846
 
3405
3847
  // String is sliced.
3406
3848
  __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset));
3422
3864
            kStringRepresentationMask | kStringEncodingMask);
3423
3865
  STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
3424
3866
  __ j(zero, &seq_two_byte_string, Label::kNear);
3425
 
  // Any other flat string must be ascii.
 
3867
  // Any other flat string must be sequential ASCII or external.
3426
3868
  __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset),
3427
3869
            kStringRepresentationMask);
3428
 
  __ j(not_zero, &runtime);
 
3870
  __ j(not_zero, &external_string);
3429
3871
 
3430
3872
  __ bind(&seq_ascii_string);
3431
 
  // eax: subject string (flat ascii)
 
3873
  // eax: subject string (flat ASCII)
3432
3874
  // ecx: RegExp data (FixedArray)
3433
3875
  __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset));
3434
 
  __ Set(ecx, Immediate(1));  // Type is ascii.
 
3876
  __ Set(ecx, Immediate(1));  // Type is ASCII.
3435
3877
  __ jmp(&check_code, Label::kNear);
3436
3878
 
3437
3879
  __ bind(&seq_two_byte_string);
3448
3890
 
3449
3891
  // eax: subject string
3450
3892
  // edx: code
3451
 
  // ecx: encoding of subject string (1 if ascii, 0 if two_byte);
 
3893
  // ecx: encoding of subject string (1 if ASCII, 0 if two_byte);
3452
3894
  // Load used arguments before starting to push arguments for call to native
3453
3895
  // RegExp code to avoid handling changing stack height.
3454
3896
  __ mov(ebx, Operand(esp, kPreviousIndexOffset));
3457
3899
  // eax: subject string
3458
3900
  // ebx: previous index
3459
3901
  // edx: code
3460
 
  // ecx: encoding of subject string (1 if ascii 0 if two_byte);
 
3902
  // ecx: encoding of subject string (1 if ASCII 0 if two_byte);
3461
3903
  // All checks done. Now push arguments for native regexp code.
3462
3904
  Counters* counters = masm->isolate()->counters();
3463
3905
  __ IncrementCounter(counters->regexp_entry_native(), 1);
3464
3906
 
3465
3907
  // Isolates: note we add an additional parameter here (isolate pointer).
3466
 
  static const int kRegExpExecuteArguments = 8;
 
3908
  static const int kRegExpExecuteArguments = 9;
3467
3909
  __ EnterApiExitFrame(kRegExpExecuteArguments);
3468
3910
 
3469
 
  // Argument 8: Pass current isolate address.
3470
 
  __ mov(Operand(esp, 7 * kPointerSize),
 
3911
  // Argument 9: Pass current isolate address.
 
3912
  __ mov(Operand(esp, 8 * kPointerSize),
3471
3913
      Immediate(ExternalReference::isolate_address()));
3472
3914
 
3473
 
  // Argument 7: Indicate that this is a direct call from JavaScript.
3474
 
  __ mov(Operand(esp, 6 * kPointerSize), Immediate(1));
 
3915
  // Argument 8: Indicate that this is a direct call from JavaScript.
 
3916
  __ mov(Operand(esp, 7 * kPointerSize), Immediate(1));
3475
3917
 
3476
 
  // Argument 6: Start (high end) of backtracking stack memory area.
 
3918
  // Argument 7: Start (high end) of backtracking stack memory area.
3477
3919
  __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address));
3478
3920
  __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size));
3479
 
  __ mov(Operand(esp, 5 * kPointerSize), esi);
 
3921
  __ mov(Operand(esp, 6 * kPointerSize), esi);
 
3922
 
 
3923
  // Argument 6: Set the number of capture registers to zero to force global
 
3924
  // regexps to behave as non-global.  This does not affect non-global regexps.
 
3925
  __ mov(Operand(esp, 5 * kPointerSize), Immediate(0));
3480
3926
 
3481
3927
  // Argument 5: static offsets vector buffer.
3482
3928
  __ mov(Operand(esp, 4 * kPointerSize),
3497
3943
  // esi: original subject string
3498
3944
  // eax: underlying subject string
3499
3945
  // ebx: previous index
3500
 
  // ecx: encoding of subject string (1 if ascii 0 if two_byte);
 
3946
  // ecx: encoding of subject string (1 if ASCII 0 if two_byte);
3501
3947
  // edx: code
3502
3948
  // Argument 4: End of string data
3503
3949
  // Argument 3: Start of string data
3504
3950
  // Prepare start and end index of the input.
3505
3951
  // Load the length from the original sliced string if that is the case.
3506
3952
  __ mov(esi, FieldOperand(esi, String::kLengthOffset));
3507
 
  __ add(esi, Operand(edi));  // Calculate input end wrt offset.
 
3953
  __ add(esi, edi);  // Calculate input end wrt offset.
3508
3954
  __ SmiUntag(edi);
3509
 
  __ add(ebx, Operand(edi));  // Calculate input start wrt offset.
 
3955
  __ add(ebx, edi);  // Calculate input start wrt offset.
3510
3956
 
3511
3957
  // ebx: start index of the input string
3512
3958
  // esi: end index of the input string
3513
3959
  Label setup_two_byte, setup_rest;
3514
 
  __ test(ecx, Operand(ecx));
 
3960
  __ test(ecx, ecx);
3515
3961
  __ j(zero, &setup_two_byte, Label::kNear);
3516
3962
  __ SmiUntag(esi);
3517
3963
  __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize));
3531
3977
  __ bind(&setup_rest);
3532
3978
 
3533
3979
  // Locate the code entry and call it.
3534
 
  __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
3535
 
  __ call(Operand(edx));
 
3980
  __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
 
3981
  __ call(edx);
3536
3982
 
3537
3983
  // Drop arguments and come back to JS mode.
3538
3984
  __ LeaveApiExitFrame();
3539
3985
 
3540
3986
  // Check the result.
3541
3987
  Label success;
3542
 
  __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS);
 
3988
  __ cmp(eax, 1);
 
3989
  // We expect exactly one result since we force the called regexp to behave
 
3990
  // as non-global.
3543
3991
  __ j(equal, &success);
3544
3992
  Label failure;
3545
3993
  __ cmp(eax, NativeRegExpMacroAssembler::FAILURE);
3553
4001
  // TODO(592): Rerunning the RegExp to get the stack overflow exception.
3554
4002
  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
3555
4003
                                      masm->isolate());
3556
 
  __ mov(edx,
3557
 
         Operand::StaticVariable(ExternalReference::the_hole_value_location(
3558
 
             masm->isolate())));
 
4004
  __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
3559
4005
  __ mov(eax, Operand::StaticVariable(pending_exception));
3560
 
  __ cmp(edx, Operand(eax));
 
4006
  __ cmp(edx, eax);
3561
4007
  __ j(equal, &runtime);
3562
4008
  // For exception, throw the exception again.
3563
4009
 
3574
4020
  __ Throw(eax);
3575
4021
 
3576
4022
  __ bind(&throw_termination_exception);
3577
 
  __ ThrowUncatchable(TERMINATION, eax);
 
4023
  __ ThrowUncatchable(eax);
3578
4024
 
3579
4025
  __ bind(&failure);
3580
4026
  // For failure to match, return null.
3581
 
  __ mov(Operand(eax), factory->null_value());
 
4027
  __ mov(eax, factory->null_value());
3582
4028
  __ ret(4 * kPointerSize);
3583
4029
 
3584
4030
  // Load RegExp data.
3589
4035
  // Calculate number of capture registers (number_of_captures + 1) * 2.
3590
4036
  STATIC_ASSERT(kSmiTag == 0);
3591
4037
  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
3592
 
  __ add(Operand(edx), Immediate(2));  // edx was a smi.
 
4038
  __ add(edx, Immediate(2));  // edx was a smi.
3593
4039
 
3594
4040
  // edx: Number of capture registers
3595
4041
  // Load last_match_info which is still known to be a fast case JSArray.
3605
4051
  // Store last subject and last input.
3606
4052
  __ mov(eax, Operand(esp, kSubjectOffset));
3607
4053
  __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
3608
 
  __ mov(ecx, ebx);
3609
 
  __ RecordWrite(ecx, RegExpImpl::kLastSubjectOffset, eax, edi);
 
4054
  __ RecordWriteField(ebx,
 
4055
                      RegExpImpl::kLastSubjectOffset,
 
4056
                      eax,
 
4057
                      edi,
 
4058
                      kDontSaveFPRegs);
3610
4059
  __ mov(eax, Operand(esp, kSubjectOffset));
3611
4060
  __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
3612
 
  __ mov(ecx, ebx);
3613
 
  __ RecordWrite(ecx, RegExpImpl::kLastInputOffset, eax, edi);
 
4061
  __ RecordWriteField(ebx,
 
4062
                      RegExpImpl::kLastInputOffset,
 
4063
                      eax,
 
4064
                      edi,
 
4065
                      kDontSaveFPRegs);
3614
4066
 
3615
4067
  // Get the static offsets vector filled by the native regexp code.
3616
4068
  ExternalReference address_of_static_offsets_vector =
3624
4076
  // Capture register counter starts from number of capture registers and
3625
4077
  // counts down until wraping after zero.
3626
4078
  __ bind(&next_capture);
3627
 
  __ sub(Operand(edx), Immediate(1));
 
4079
  __ sub(edx, Immediate(1));
3628
4080
  __ j(negative, &done, Label::kNear);
3629
4081
  // Read the value from the static offsets vector buffer.
3630
4082
  __ mov(edi, Operand(ecx, edx, times_int_size, 0));
3642
4094
  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
3643
4095
  __ ret(4 * kPointerSize);
3644
4096
 
 
4097
  // External string.  Short external strings have already been ruled out.
 
4098
  // eax: subject string (expected to be external)
 
4099
  // ebx: scratch
 
4100
  __ bind(&external_string);
 
4101
  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
 
4102
  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
 
4103
  if (FLAG_debug_code) {
 
4104
    // Assert that we do not have a cons or slice (indirect strings) here.
 
4105
    // Sequential strings have already been ruled out.
 
4106
    __ test_b(ebx, kIsIndirectStringMask);
 
4107
    __ Assert(zero, "external string expected, but not found");
 
4108
  }
 
4109
  __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset));
 
4110
  // Move the pointer so that offset-wise, it looks like a sequential string.
 
4111
  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
 
4112
  __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
 
4113
  STATIC_ASSERT(kTwoByteStringTag == 0);
 
4114
  __ test_b(ebx, kStringEncodingMask);
 
4115
  __ j(not_zero, &seq_ascii_string);
 
4116
  __ jmp(&seq_two_byte_string);
 
4117
 
3645
4118
  // Do the runtime call to execute the regexp.
3646
4119
  __ bind(&runtime);
3647
4120
  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
3655
4128
  Label done;
3656
4129
  __ mov(ebx, Operand(esp, kPointerSize * 3));
3657
4130
  __ JumpIfNotSmi(ebx, &slowcase);
3658
 
  __ cmp(Operand(ebx), Immediate(Smi::FromInt(kMaxInlineLength)));
 
4131
  __ cmp(ebx, Immediate(Smi::FromInt(kMaxInlineLength)));
3659
4132
  __ j(above, &slowcase);
3660
4133
  // Smi-tagging is equivalent to multiplying by 2.
3661
4134
  STATIC_ASSERT(kSmiTag == 0);
3677
4150
  // Set empty properties FixedArray.
3678
4151
  // Set elements to point to FixedArray allocated right after the JSArray.
3679
4152
  // Interleave operations for better latency.
3680
 
  __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX));
 
4153
  __ mov(edx, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
3681
4154
  Factory* factory = masm->isolate()->factory();
3682
4155
  __ mov(ecx, Immediate(factory->empty_fixed_array()));
3683
4156
  __ lea(ebx, Operand(eax, JSRegExpResult::kSize));
3684
 
  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset));
 
4157
  __ mov(edx, FieldOperand(edx, GlobalObject::kNativeContextOffset));
3685
4158
  __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx);
3686
4159
  __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
3687
4160
  __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX));
3705
4178
         Immediate(factory->fixed_array_map()));
3706
4179
  // Set length.
3707
4180
  __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx);
3708
 
  // Fill contents of fixed-array with the-hole.
 
4181
  // Fill contents of fixed-array with undefined.
3709
4182
  __ SmiUntag(ecx);
3710
 
  __ mov(edx, Immediate(factory->the_hole_value()));
 
4183
  __ mov(edx, Immediate(factory->undefined_value()));
3711
4184
  __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize));
3712
 
  // Fill fixed array elements with hole.
 
4185
  // Fill fixed array elements with undefined.
3713
4186
  // eax: JSArray.
3714
4187
  // ecx: Number of elements to fill.
3715
4188
  // ebx: Start of elements in FixedArray.
3716
 
  // edx: the hole.
 
4189
  // edx: undefined.
3717
4190
  Label loop;
3718
 
  __ test(ecx, Operand(ecx));
 
4191
  __ test(ecx, ecx);
3719
4192
  __ bind(&loop);
3720
4193
  __ j(less_equal, &done, Label::kNear);  // Jump if ecx is negative or zero.
3721
 
  __ sub(Operand(ecx), Immediate(1));
 
4194
  __ sub(ecx, Immediate(1));
3722
4195
  __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx);
3723
4196
  __ jmp(&loop);
3724
4197
 
3743
4216
  Register scratch = scratch2;
3744
4217
 
3745
4218
  // Load the number string cache.
3746
 
  ExternalReference roots_address =
3747
 
      ExternalReference::roots_address(masm->isolate());
 
4219
  ExternalReference roots_array_start =
 
4220
      ExternalReference::roots_array_start(masm->isolate());
3748
4221
  __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex));
3749
4222
  __ mov(number_string_cache,
3750
 
         Operand::StaticArray(scratch, times_pointer_size, roots_address));
 
4223
         Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
3751
4224
  // Make the hash mask from the length of the number string cache. It
3752
4225
  // contains two elements (number and string) for each cache entry.
3753
4226
  __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
3754
4227
  __ shr(mask, kSmiTagSize + 1);  // Untag length and divide it by two.
3755
 
  __ sub(Operand(mask), Immediate(1));  // Make mask.
 
4228
  __ sub(mask, Immediate(1));  // Make mask.
3756
4229
 
3757
4230
  // Calculate the entry in the number string cache. The hash value in the
3758
4231
  // number string cache for smis is just the smi value, and the hash for
3778
4251
    __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset));
3779
4252
    __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
3780
4253
    // Object is heap number and hash is now in scratch. Calculate cache index.
3781
 
    __ and_(scratch, Operand(mask));
 
4254
    __ and_(scratch, mask);
3782
4255
    Register index = scratch;
3783
4256
    Register probe = mask;
3784
4257
    __ mov(probe,
3804
4277
 
3805
4278
  __ bind(&smi_hash_calculated);
3806
4279
  // Object is smi and hash is now in scratch. Calculate cache index.
3807
 
  __ and_(scratch, Operand(mask));
 
4280
  __ and_(scratch, mask);
3808
4281
  Register index = scratch;
3809
4282
  // Check if the entry is the smi we are looking for.
3810
4283
  __ cmp(object,
3856
4329
  // Compare two smis if required.
3857
4330
  if (include_smi_compare_) {
3858
4331
    Label non_smi, smi_done;
3859
 
    __ mov(ecx, Operand(edx));
3860
 
    __ or_(ecx, Operand(eax));
 
4332
    __ mov(ecx, edx);
 
4333
    __ or_(ecx, eax);
3861
4334
    __ JumpIfNotSmi(ecx, &non_smi, Label::kNear);
3862
 
    __ sub(edx, Operand(eax));  // Return on the result of the subtraction.
 
4335
    __ sub(edx, eax);  // Return on the result of the subtraction.
3863
4336
    __ j(no_overflow, &smi_done, Label::kNear);
3864
4337
    __ not_(edx);  // Correct sign in case of overflow. edx is never 0 here.
3865
4338
    __ bind(&smi_done);
3867
4340
    __ ret(0);
3868
4341
    __ bind(&non_smi);
3869
4342
  } else if (FLAG_debug_code) {
3870
 
    __ mov(ecx, Operand(edx));
3871
 
    __ or_(ecx, Operand(eax));
 
4343
    __ mov(ecx, edx);
 
4344
    __ or_(ecx, eax);
3872
4345
    __ test(ecx, Immediate(kSmiTagMask));
3873
4346
    __ Assert(not_zero, "Unexpected smi operands.");
3874
4347
  }
3880
4353
  // for NaN and undefined.
3881
4354
  {
3882
4355
    Label not_identical;
3883
 
    __ cmp(eax, Operand(edx));
 
4356
    __ cmp(eax, edx);
3884
4357
    __ j(not_equal, &not_identical);
3885
4358
 
3886
4359
    if (cc_ != equal) {
3929
4402
      __ Set(eax, Immediate(0));
3930
4403
      // Shift value and mask so kQuietNaNHighBitsMask applies to topmost
3931
4404
      // bits.
3932
 
      __ add(edx, Operand(edx));
 
4405
      __ add(edx, edx);
3933
4406
      __ cmp(edx, kQuietNaNHighBitsMask << 1);
3934
4407
      if (cc_ == equal) {
3935
4408
        STATIC_ASSERT(EQUAL != 1);
3963
4436
    STATIC_ASSERT(kSmiTag == 0);
3964
4437
    ASSERT_EQ(0, Smi::FromInt(0));
3965
4438
    __ mov(ecx, Immediate(kSmiTagMask));
3966
 
    __ and_(ecx, Operand(eax));
3967
 
    __ test(ecx, Operand(edx));
 
4439
    __ and_(ecx, eax);
 
4440
    __ test(ecx, edx);
3968
4441
    __ j(not_zero, &not_smis, Label::kNear);
3969
4442
    // One operand is a smi.
3970
4443
 
3971
4444
    // Check whether the non-smi is a heap number.
3972
4445
    STATIC_ASSERT(kSmiTagMask == 1);
3973
4446
    // ecx still holds eax & kSmiTag, which is either zero or one.
3974
 
    __ sub(Operand(ecx), Immediate(0x01));
 
4447
    __ sub(ecx, Immediate(0x01));
3975
4448
    __ mov(ebx, edx);
3976
 
    __ xor_(ebx, Operand(eax));
3977
 
    __ and_(ebx, Operand(ecx));  // ebx holds either 0 or eax ^ edx.
3978
 
    __ xor_(ebx, Operand(eax));
 
4449
    __ xor_(ebx, eax);
 
4450
    __ and_(ebx, ecx);  // ebx holds either 0 or eax ^ edx.
 
4451
    __ xor_(ebx, eax);
3979
4452
    // if eax was smi, ebx is now edx, else eax.
3980
4453
 
3981
4454
    // Check if the non-smi operand is a heap number.
4037
4510
      // Return a result of -1, 0, or 1, based on EFLAGS.
4038
4511
      __ mov(eax, 0);  // equal
4039
4512
      __ mov(ecx, Immediate(Smi::FromInt(1)));
4040
 
      __ cmov(above, eax, Operand(ecx));
 
4513
      __ cmov(above, eax, ecx);
4041
4514
      __ mov(ecx, Immediate(Smi::FromInt(-1)));
4042
 
      __ cmov(below, eax, Operand(ecx));
 
4515
      __ cmov(below, eax, ecx);
4043
4516
      __ ret(0);
4044
4517
    } else {
4045
4518
      FloatingPointHelper::CheckFloatOperands(
4100
4573
  __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx,
4101
4574
                                         &check_unequal_objects);
4102
4575
 
4103
 
  // Inline comparison of ascii strings.
 
4576
  // Inline comparison of ASCII strings.
4104
4577
  if (cc_ == equal) {
4105
4578
    StringCompareStub::GenerateFlatAsciiStringEquals(masm,
4106
4579
                                                     edx,
4198
4671
}
4199
4672
 
4200
4673
 
 
4674
void InterruptStub::Generate(MacroAssembler* masm) {
 
4675
  __ TailCallRuntime(Runtime::kInterrupt, 0, 1);
 
4676
}
 
4677
 
 
4678
 
 
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
 
4682
  // megamorphic.
 
4683
  // ebx : cache cell for call target
 
4684
  // edi : the function to call
 
4685
  Isolate* isolate = masm->isolate();
 
4686
  Label initialize, done;
 
4687
 
 
4688
  // Load the cache state into ecx.
 
4689
  __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
 
4690
 
 
4691
  // A monomorphic cache hit or an already megamorphic state: invoke the
 
4692
  // function without changing the state.
 
4693
  __ cmp(ecx, edi);
 
4694
  __ j(equal, &done, Label::kNear);
 
4695
  __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
 
4696
  __ j(equal, &done, Label::kNear);
 
4697
 
 
4698
  // A monomorphic miss (i.e, here the cache is not uninitialized) goes
 
4699
  // megamorphic.
 
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);
 
4707
 
 
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.
 
4712
 
 
4713
  __ bind(&done);
 
4714
}
 
4715
 
 
4716
 
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;
4203
4722
 
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()) {
4208
 
    Label call;
 
4727
    Label receiver_ok;
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);
4219
 
    __ bind(&call);
 
4735
    __ mov(ecx, GlobalObjectOperand());
 
4736
    __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
 
4737
    __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ecx);
 
4738
    __ bind(&receiver_ok);
4220
4739
  }
4221
4740
 
4222
 
  // Get the function to call from the stack.
4223
 
  // +2 ~ receiver, return address
4224
 
  __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
4225
 
 
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);
4231
4746
 
 
4747
  if (RecordCallTarget()) {
 
4748
    GenerateRecordCallTarget(masm);
 
4749
  }
 
4750
 
4232
4751
  // Fast-case: Just invoke the function.
4233
4752
  ParameterCount actual(argc_);
4234
4753
 
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,
4240
4759
                      actual,
4251
4770
 
4252
4771
  // Slow-case: Non-function called.
4253
4772
  __ bind(&slow);
 
4773
  if (RecordCallTarget()) {
 
4774
    // If there is a call target cache, mark it megamorphic in the
 
4775
    // non-function case.  MegamorphicSentinel is an immortal immovable
 
4776
    // object (undefined) so no write barrier is needed.
 
4777
    __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
 
4778
           Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
 
4779
  }
4254
4780
  // Check for function proxy.
4255
4781
  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
4256
4782
  __ j(not_equal, &non_function);
4262
4788
  __ SetCallKind(ecx, CALL_AS_FUNCTION);
4263
4789
  __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
4264
4790
  {
4265
 
    Handle<Code> adaptor =
4266
 
      masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
 
4791
    Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
4267
4792
    __ jmp(adaptor, RelocInfo::CODE_TARGET);
4268
4793
  }
4269
4794
 
4275
4800
  __ Set(ebx, Immediate(0));
4276
4801
  __ SetCallKind(ecx, CALL_AS_METHOD);
4277
4802
  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
4278
 
  Handle<Code> adaptor =
4279
 
      masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
 
4803
  Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
4280
4804
  __ jmp(adaptor, RelocInfo::CODE_TARGET);
4281
4805
}
4282
4806
 
4283
4807
 
 
4808
void CallConstructStub::Generate(MacroAssembler* masm) {
 
4809
  // eax : number of arguments
 
4810
  // ebx : cache cell for call target
 
4811
  // edi : constructor function
 
4812
  Label slow, non_function_call;
 
4813
 
 
4814
  // Check that function is not a smi.
 
4815
  __ JumpIfSmi(edi, &non_function_call);
 
4816
  // Check that function is a JSFunction.
 
4817
  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
 
4818
  __ j(not_equal, &slow);
 
4819
 
 
4820
  if (RecordCallTarget()) {
 
4821
    GenerateRecordCallTarget(masm);
 
4822
  }
 
4823
 
 
4824
  // Jump to the function-specific construct stub.
 
4825
  __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
 
4826
  __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
 
4827
  __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
 
4828
  __ jmp(ebx);
 
4829
 
 
4830
  // edi: called object
 
4831
  // eax: number of arguments
 
4832
  // ecx: object map
 
4833
  Label do_call;
 
4834
  __ bind(&slow);
 
4835
  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
 
4836
  __ j(not_equal, &non_function_call);
 
4837
  __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
 
4838
  __ jmp(&do_call);
 
4839
 
 
4840
  __ bind(&non_function_call);
 
4841
  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
 
4842
  __ bind(&do_call);
 
4843
  // Set expected number of arguments to zero (not changing eax).
 
4844
  __ Set(ebx, Immediate(0));
 
4845
  Handle<Code> arguments_adaptor =
 
4846
      masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
 
4847
  __ SetCallKind(ecx, CALL_AS_METHOD);
 
4848
  __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
 
4849
}
 
4850
 
 
4851
 
4284
4852
bool CEntryStub::NeedsImmovableCode() {
4285
4853
  return false;
4286
4854
}
4287
4855
 
4288
4856
 
4289
 
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
4290
 
  __ Throw(eax);
 
4857
bool CEntryStub::IsPregenerated() {
 
4858
  return (!save_doubles_ || ISOLATE->fp_stubs_generated()) &&
 
4859
          result_size_ == 1;
 
4860
}
 
4861
 
 
4862
 
 
4863
void CodeStub::GenerateStubsAheadOfTime() {
 
4864
  CEntryStub::GenerateAheadOfTime();
 
4865
  StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime();
 
4866
  // It is important that the store buffer overflow stubs are generated first.
 
4867
  RecordWriteStub::GenerateFixedRegStubsAheadOfTime();
 
4868
}
 
4869
 
 
4870
 
 
4871
void CodeStub::GenerateFPStubs() {
 
4872
  CEntryStub save_doubles(1, kSaveFPRegs);
 
4873
  Handle<Code> code = save_doubles.GetCode();
 
4874
  code->set_is_pregenerated(true);
 
4875
  code->GetIsolate()->set_fp_stubs_generated(true);
 
4876
}
 
4877
 
 
4878
 
 
4879
void CEntryStub::GenerateAheadOfTime() {
 
4880
  CEntryStub stub(1, kDontSaveFPRegs);
 
4881
  Handle<Code> code = stub.GetCode();
 
4882
  code->set_is_pregenerated(true);
4291
4883
}
4292
4884
 
4293
4885
 
4332
4924
  __ mov(Operand(esp, 1 * kPointerSize), esi);  // argv.
4333
4925
  __ mov(Operand(esp, 2 * kPointerSize),
4334
4926
         Immediate(ExternalReference::isolate_address()));
4335
 
  __ call(Operand(ebx));
 
4927
  __ call(ebx);
4336
4928
  // Result is in eax or edx:eax - do not destroy these registers!
4337
4929
 
4338
4930
  if (always_allocate_scope) {
4364
4956
  // should have returned some failure value.
4365
4957
  if (FLAG_debug_code) {
4366
4958
    __ push(edx);
4367
 
    __ mov(edx, Operand::StaticVariable(
4368
 
        ExternalReference::the_hole_value_location(masm->isolate())));
 
4959
    __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
4369
4960
    Label okay;
4370
4961
    __ cmp(edx, Operand::StaticVariable(pending_exception_address));
4371
4962
    // Cannot use check here as it attempts to generate call into runtime.
4376
4967
  }
4377
4968
 
4378
4969
  // Exit the JavaScript to C++ exit frame.
4379
 
  __ LeaveExitFrame(save_doubles_);
 
4970
  __ LeaveExitFrame(save_doubles_ == kSaveFPRegs);
4380
4971
  __ ret(0);
4381
4972
 
4382
4973
  // Handling of failure.
4393
4984
  __ j(equal, throw_out_of_memory_exception);
4394
4985
 
4395
4986
  // Retrieve the pending exception and clear the variable.
4396
 
  ExternalReference the_hole_location =
4397
 
      ExternalReference::the_hole_value_location(masm->isolate());
4398
4987
  __ mov(eax, Operand::StaticVariable(pending_exception_address));
4399
 
  __ mov(edx, Operand::StaticVariable(the_hole_location));
 
4988
  __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
4400
4989
  __ mov(Operand::StaticVariable(pending_exception_address), edx);
4401
4990
 
4402
4991
  // Special handling of termination exceptions which are uncatchable
4412
5001
}
4413
5002
 
4414
5003
 
4415
 
void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
4416
 
                                          UncatchableExceptionType type) {
4417
 
  __ ThrowUncatchable(type, eax);
4418
 
}
4419
 
 
4420
 
 
4421
5004
void CEntryStub::Generate(MacroAssembler* masm) {
4422
5005
  // eax: number of arguments including receiver
4423
5006
  // ebx: pointer to C function  (C callee-saved)
4431
5014
  // a garbage collection and retrying the builtin (twice).
4432
5015
 
4433
5016
  // Enter the exit frame that transitions from JavaScript to C++.
4434
 
  __ EnterExitFrame(save_doubles_);
 
5017
  __ EnterExitFrame(save_doubles_ == kSaveFPRegs);
4435
5018
 
4436
5019
  // eax: result parameter for PerformGC, if any (setup below)
4437
5020
  // ebx: pointer to builtin function  (C callee-saved)
4471
5054
               true);
4472
5055
 
4473
5056
  __ bind(&throw_out_of_memory_exception);
4474
 
  GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
 
5057
  // Set external caught exception to false.
 
5058
  Isolate* isolate = masm->isolate();
 
5059
  ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
 
5060
                                    isolate);
 
5061
  __ mov(Operand::StaticVariable(external_caught), Immediate(false));
 
5062
 
 
5063
  // Set pending exception and eax to out of memory exception.
 
5064
  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
 
5065
                                      isolate);
 
5066
  __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
 
5067
  __ mov(Operand::StaticVariable(pending_exception), eax);
 
5068
  // Fall through to the next label.
4475
5069
 
4476
5070
  __ bind(&throw_termination_exception);
4477
 
  GenerateThrowUncatchable(masm, TERMINATION);
 
5071
  __ ThrowUncatchable(eax);
4478
5072
 
4479
5073
  __ bind(&throw_normal_exception);
4480
 
  GenerateThrowTOS(masm);
 
5074
  __ Throw(eax);
4481
5075
}
4482
5076
 
4483
5077
 
4484
5078
void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
4485
 
  Label invoke, exit;
 
5079
  Label invoke, handler_entry, exit;
4486
5080
  Label not_outermost_js, not_outermost_js_2;
4487
5081
 
4488
 
  // Setup frame.
 
5082
  // Set up frame.
4489
5083
  __ push(ebp);
4490
 
  __ mov(ebp, Operand(esp));
 
5084
  __ mov(ebp, esp);
4491
5085
 
4492
5086
  // Push marker in two places.
4493
5087
  int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
4509
5103
  __ j(not_equal, &not_outermost_js, Label::kNear);
4510
5104
  __ mov(Operand::StaticVariable(js_entry_sp), ebp);
4511
5105
  __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
4512
 
  Label cont;
4513
 
  __ jmp(&cont, Label::kNear);
 
5106
  __ jmp(&invoke, Label::kNear);
4514
5107
  __ bind(&not_outermost_js);
4515
5108
  __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
4516
 
  __ bind(&cont);
4517
 
 
4518
 
  // Call a faked try-block that does the invoke.
4519
 
  __ call(&invoke);
4520
 
 
4521
 
  // Caught exception: Store result (exception) in the pending
4522
 
  // exception field in the JSEnv and return a failure sentinel.
 
5109
 
 
5110
  // Jump to a faked try block that does the invoke, with a faked catch
 
5111
  // block that sets the pending exception.
 
5112
  __ jmp(&invoke);
 
5113
  __ bind(&handler_entry);
 
5114
  handler_offset_ = handler_entry.pos();
 
5115
  // Caught exception: Store result (exception) in the pending exception
 
5116
  // field in the JSEnv and return a failure sentinel.
4523
5117
  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
4524
5118
                                      masm->isolate());
4525
5119
  __ mov(Operand::StaticVariable(pending_exception), eax);
4526
5120
  __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
4527
5121
  __ jmp(&exit);
4528
5122
 
4529
 
  // Invoke: Link this frame into the handler chain.
 
5123
  // Invoke: Link this frame into the handler chain.  There's only one
 
5124
  // handler block in this code object, so its index is 0.
4530
5125
  __ bind(&invoke);
4531
 
  __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
 
5126
  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
4532
5127
 
4533
5128
  // Clear any pending exceptions.
4534
 
  ExternalReference the_hole_location =
4535
 
      ExternalReference::the_hole_value_location(masm->isolate());
4536
 
  __ mov(edx, Operand::StaticVariable(the_hole_location));
 
5129
  __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
4537
5130
  __ mov(Operand::StaticVariable(pending_exception), edx);
4538
5131
 
4539
5132
  // Fake a receiver (NULL).
4540
5133
  __ push(Immediate(0));  // receiver
4541
5134
 
4542
 
  // Invoke the function by calling through JS entry trampoline
4543
 
  // builtin and pop the faked function when we return. Notice that we
4544
 
  // cannot store a reference to the trampoline code directly in this
4545
 
  // stub, because the builtin stubs may not have been generated yet.
 
5135
  // Invoke the function by calling through JS entry trampoline builtin and
 
5136
  // pop the faked function when we return. Notice that we cannot store a
 
5137
  // reference to the trampoline code directly in this stub, because the
 
5138
  // builtin stubs may not have been generated yet.
4546
5139
  if (is_construct) {
4547
 
    ExternalReference construct_entry(
4548
 
        Builtins::kJSConstructEntryTrampoline,
4549
 
        masm->isolate());
 
5140
    ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
 
5141
                                      masm->isolate());
4550
5142
    __ mov(edx, Immediate(construct_entry));
4551
5143
  } else {
4552
5144
    ExternalReference entry(Builtins::kJSEntryTrampoline,
4555
5147
  }
4556
5148
  __ mov(edx, Operand(edx, 0));  // deref address
4557
5149
  __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
4558
 
  __ call(Operand(edx));
 
5150
  __ call(edx);
4559
5151
 
4560
5152
  // Unlink this frame from the handler chain.
4561
5153
  __ PopTryHandler();
4563
5155
  __ bind(&exit);
4564
5156
  // Check if the current stack frame is marked as the outermost JS frame.
4565
5157
  __ pop(ebx);
4566
 
  __ cmp(Operand(ebx),
4567
 
         Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
 
5158
  __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
4568
5159
  __ j(not_equal, &not_outermost_js_2);
4569
5160
  __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
4570
5161
  __ bind(&not_outermost_js_2);
4578
5169
  __ pop(ebx);
4579
5170
  __ pop(esi);
4580
5171
  __ pop(edi);
4581
 
  __ add(Operand(esp), Immediate(2 * kPointerSize));  // remove markers
 
5172
  __ add(esp, Immediate(2 * kPointerSize));  // remove markers
4582
5173
 
4583
5174
  // Restore frame pointer and return.
4584
5175
  __ pop(ebp);
4617
5208
  static const int kDeltaToCmpImmediate = 2;
4618
5209
  static const int kDeltaToMov = 8;
4619
5210
  static const int kDeltaToMovImmediate = 9;
4620
 
  static const int8_t kCmpEdiImmediateByte1 = BitCast<int8_t, uint8_t>(0x81);
4621
 
  static const int8_t kCmpEdiImmediateByte2 = BitCast<int8_t, uint8_t>(0xff);
 
5211
  static const int8_t kCmpEdiOperandByte1 = BitCast<int8_t, uint8_t>(0x3b);
 
5212
  static const int8_t kCmpEdiOperandByte2 = BitCast<int8_t, uint8_t>(0x3d);
4622
5213
  static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8);
4623
5214
 
4624
 
  ExternalReference roots_address =
4625
 
      ExternalReference::roots_address(masm->isolate());
 
5215
  ExternalReference roots_array_start =
 
5216
      ExternalReference::roots_array_start(masm->isolate());
4626
5217
 
4627
5218
  ASSERT_EQ(object.code(), InstanceofStub::left().code());
4628
5219
  ASSERT_EQ(function.code(), InstanceofStub::right().code());
4644
5235
    // Look up the function and the map in the instanceof cache.
4645
5236
    Label miss;
4646
5237
    __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
4647
 
    __ cmp(function,
4648
 
           Operand::StaticArray(scratch, times_pointer_size, roots_address));
 
5238
    __ cmp(function, Operand::StaticArray(scratch,
 
5239
                                          times_pointer_size,
 
5240
                                          roots_array_start));
4649
5241
    __ j(not_equal, &miss, Label::kNear);
4650
5242
    __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
4651
5243
    __ cmp(map, Operand::StaticArray(
4652
 
        scratch, times_pointer_size, roots_address));
 
5244
        scratch, times_pointer_size, roots_array_start));
4653
5245
    __ j(not_equal, &miss, Label::kNear);
4654
5246
    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4655
5247
    __ mov(eax, Operand::StaticArray(
4656
 
        scratch, times_pointer_size, roots_address));
 
5248
        scratch, times_pointer_size, roots_array_start));
4657
5249
    __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4658
5250
    __ bind(&miss);
4659
5251
  }
4660
5252
 
4661
5253
  // Get the prototype of the function.
4662
 
  __ TryGetFunctionPrototype(function, prototype, scratch, &slow);
 
5254
  __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
4663
5255
 
4664
5256
  // Check that the function prototype is a JS object.
4665
5257
  __ JumpIfSmi(prototype, &slow);
4669
5261
  // map and function. The cached answer will be set when it is known below.
4670
5262
  if (!HasCallSiteInlineCheck()) {
4671
5263
  __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
4672
 
  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map);
 
5264
  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
 
5265
         map);
4673
5266
  __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
4674
 
  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address),
 
5267
  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
4675
5268
         function);
4676
5269
  } else {
4677
5270
    // The constants for the code patching are based on no push instructions
4681
5274
    __ mov(scratch, Operand(esp, 0 * kPointerSize));
4682
5275
    __ sub(scratch, Operand(esp, 1 * kPointerSize));
4683
5276
    if (FLAG_debug_code) {
4684
 
      __ cmpb(Operand(scratch, 0), kCmpEdiImmediateByte1);
 
5277
      __ cmpb(Operand(scratch, 0), kCmpEdiOperandByte1);
4685
5278
      __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)");
4686
 
      __ cmpb(Operand(scratch, 1), kCmpEdiImmediateByte2);
 
5279
      __ cmpb(Operand(scratch, 1), kCmpEdiOperandByte2);
4687
5280
      __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)");
4688
5281
    }
4689
 
    __ mov(Operand(scratch, kDeltaToCmpImmediate), map);
 
5282
    __ mov(scratch, Operand(scratch, kDeltaToCmpImmediate));
 
5283
    __ mov(Operand(scratch, 0), map);
4690
5284
  }
4691
5285
 
4692
5286
  // Loop through the prototype chain of the object looking for the function
4694
5288
  __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset));
4695
5289
  Label loop, is_instance, is_not_instance;
4696
5290
  __ bind(&loop);
4697
 
  __ cmp(scratch, Operand(prototype));
 
5291
  __ cmp(scratch, prototype);
4698
5292
  __ j(equal, &is_instance, Label::kNear);
4699
5293
  Factory* factory = masm->isolate()->factory();
4700
 
  __ cmp(Operand(scratch), Immediate(factory->null_value()));
 
5294
  __ cmp(scratch, Immediate(factory->null_value()));
4701
5295
  __ j(equal, &is_not_instance, Label::kNear);
4702
5296
  __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
4703
5297
  __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
4708
5302
    __ Set(eax, Immediate(0));
4709
5303
    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4710
5304
    __ mov(Operand::StaticArray(scratch,
4711
 
                                times_pointer_size, roots_address), eax);
 
5305
                                times_pointer_size, roots_array_start), eax);
4712
5306
  } else {
4713
5307
    // Get return address and delta to inlined map check.
4714
5308
    __ mov(eax, factory->true_value());
4730
5324
    __ Set(eax, Immediate(Smi::FromInt(1)));
4731
5325
    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4732
5326
    __ mov(Operand::StaticArray(
4733
 
        scratch, times_pointer_size, roots_address), eax);
 
5327
        scratch, times_pointer_size, roots_array_start), eax);
4734
5328
  } else {
4735
5329
    // Get return address and delta to inlined map check.
4736
5330
    __ mov(eax, factory->false_value());
4788
5382
    __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
4789
5383
  } else {
4790
5384
    // Call the builtin and convert 0/1 to true/false.
4791
 
    __ EnterInternalFrame();
4792
 
    __ push(object);
4793
 
    __ push(function);
4794
 
    __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
4795
 
    __ LeaveInternalFrame();
 
5385
    {
 
5386
      FrameScope scope(masm, StackFrame::INTERNAL);
 
5387
      __ push(object);
 
5388
      __ push(function);
 
5389
      __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
 
5390
    }
4796
5391
    Label true_value, done;
4797
 
    __ test(eax, Operand(eax));
 
5392
    __ test(eax, eax);
4798
5393
    __ j(zero, &true_value, Label::kNear);
4799
5394
    __ mov(eax, factory->false_value());
4800
5395
    __ jmp(&done, Label::kNear);
4854
5449
// StringCharCodeAtGenerator
4855
5450
 
4856
5451
void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
4857
 
  Label flat_string;
4858
 
  Label ascii_string;
4859
 
  Label got_char_code;
4860
 
  Label sliced_string;
4861
 
 
4862
5452
  // If the receiver is a smi trigger the non-string case.
4863
5453
  STATIC_ASSERT(kSmiTag == 0);
4864
5454
  __ JumpIfSmi(object_, receiver_not_string_);
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_);
4876
 
 
4877
 
  // Put smi-tagged index into scratch register.
4878
 
  __ mov(scratch_, index_);
4879
5466
  __ bind(&got_smi_index_);
4880
5467
 
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_);
4884
5471
 
4885
 
  // We need special handling for non-flat strings.
4886
 
  STATIC_ASSERT(kSeqStringTag == 0);
4887
 
  __ test(result_, Immediate(kStringRepresentationMask));
4888
 
  __ j(zero, &flat_string);
4889
 
 
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_);
4897
 
 
4898
 
  // ConsString.
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
4902
 
  // the string.
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);
4910
 
 
4911
 
  // SlicedString, unpack and add offset.
4912
 
  __ bind(&sliced_string);
4913
 
  __ add(scratch_, FieldOperand(object_, SlicedString::kOffsetOffset));
4914
 
  __ mov(object_, FieldOperand(object_, SlicedString::kParentOffset));
4915
 
 
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);
4924
 
 
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);
4931
 
 
4932
 
  // 2-byte string.
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);
4939
 
 
4940
 
  // ASCII string.
4941
 
  // Load the byte into the result register.
4942
 
  __ bind(&ascii_string);
4943
 
  __ SmiUntag(scratch_);
4944
 
  __ movzx_b(result_, FieldOperand(object_,
4945
 
                                   scratch_, times_1,
4946
 
                                   SeqAsciiString::kHeaderSize));
4947
 
  __ bind(&got_char_code);
 
5472
  __ SmiUntag(index_);
 
5473
 
 
5474
  Factory* factory = masm->isolate()->factory();
 
5475
  StringCharLoadGenerator::Generate(
 
5476
      masm, factory, object_, index_, result_, &call_runtime_);
 
5477
 
4948
5478
  __ SmiTag(result_);
4949
5479
  __ bind(&exit_);
4950
5480
}
4951
5481
 
4952
5482
 
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");
4956
5487
 
4957
5488
  // Index is not a smi.
4963
5494
              DONT_DO_SMI_CHECK);
4964
5495
  call_helper.BeforeCall(masm);
4965
5496
  __ push(object_);
4966
 
  __ push(index_);
4967
5497
  __ push(index_);  // Consumed by runtime conversion function.
4968
5498
  if (index_flags_ == STRING_INDEX_IS_NUMBER) {
4969
5499
    __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
4972
5502
    // NumberToSmi discards numbers that are not exact integers.
4973
5503
    __ CallRuntime(Runtime::kNumberToSmi, 1);
4974
5504
  }
4975
 
  if (!scratch_.is(eax)) {
 
5505
  if (!index_.is(eax)) {
4976
5506
    // Save the conversion result before the pop instructions below
4977
5507
    // have a chance to overwrite it.
4978
 
    __ mov(scratch_, eax);
 
5508
    __ mov(index_, eax);
4979
5509
  }
4980
 
  __ pop(index_);
4981
5510
  __ pop(object_);
4982
5511
  // Reload the instance type.
4983
5512
  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
4985
5514
  call_helper.AfterCall(masm);
4986
5515
  // If index is still not a smi, it must be out of range.
4987
5516
  STATIC_ASSERT(kSmiTag == 0);
4988
 
  __ JumpIfNotSmi(scratch_, index_out_of_range_);
 
5517
  __ JumpIfNotSmi(index_, index_out_of_range_);
4989
5518
  // Otherwise, return to the fast path.
4990
5519
  __ jmp(&got_smi_index_);
4991
5520
 
4995
5524
  __ bind(&call_runtime_);
4996
5525
  call_helper.BeforeCall(masm);
4997
5526
  __ push(object_);
 
5527
  __ SmiTag(index_);
4998
5528
  __ push(index_);
4999
5529
  __ CallRuntime(Runtime::kStringCharCodeAt, 2);
5000
5530
  if (!result_.is(eax)) {
5025
5555
  STATIC_ASSERT(kSmiTag == 0);
5026
5556
  STATIC_ASSERT(kSmiTagSize == 1);
5027
5557
  STATIC_ASSERT(kSmiShiftSize == 0);
5028
 
  // At this point code register contains smi tagged ascii char code.
 
5558
  // At this point code register contains smi tagged ASCII char code.
5029
5559
  __ mov(result_, FieldOperand(result_,
5030
5560
                               code_, times_half_pointer_size,
5031
5561
                               FixedArray::kHeaderSize));
5036
5566
 
5037
5567
 
5038
5568
void StringCharFromCodeGenerator::GenerateSlow(
5039
 
    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
 
5569
    MacroAssembler* masm,
 
5570
    const RuntimeCallHelper& call_helper) {
5040
5571
  __ Abort("Unexpected fallthrough to CharFromCode slow case");
5041
5572
 
5042
5573
  __ bind(&slow_case_);
5063
5594
 
5064
5595
 
5065
5596
void StringCharAtGenerator::GenerateSlow(
5066
 
    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
 
5597
    MacroAssembler* masm,
 
5598
    const RuntimeCallHelper& call_helper) {
5067
5599
  char_code_at_generator_.GenerateSlow(masm, call_helper);
5068
5600
  char_from_code_generator_.GenerateSlow(masm, call_helper);
5069
5601
}
5070
5602
 
5071
5603
 
5072
5604
void StringAddStub::Generate(MacroAssembler* masm) {
5073
 
  Label string_add_runtime, call_builtin;
 
5605
  Label call_runtime, call_builtin;
5074
5606
  Builtins::JavaScript builtin_id = Builtins::ADD;
5075
5607
 
5076
5608
  // Load the two arguments.
5079
5611
 
5080
5612
  // Make sure that both arguments are strings if not known in advance.
5081
5613
  if (flags_ == NO_STRING_ADD_FLAGS) {
5082
 
    __ JumpIfSmi(eax, &string_add_runtime);
 
5614
    __ JumpIfSmi(eax, &call_runtime);
5083
5615
    __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx);
5084
 
    __ j(above_equal, &string_add_runtime);
 
5616
    __ j(above_equal, &call_runtime);
5085
5617
 
5086
5618
    // First argument is a a string, test second.
5087
 
    __ JumpIfSmi(edx, &string_add_runtime);
 
5619
    __ JumpIfSmi(edx, &call_runtime);
5088
5620
    __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx);
5089
 
    __ j(above_equal, &string_add_runtime);
 
5621
    __ j(above_equal, &call_runtime);
5090
5622
  } else {
5091
5623
    // Here at least one of the arguments is definitely a string.
5092
5624
    // We convert the one that is not known to be a string.
5110
5642
  Label second_not_zero_length, both_not_zero_length;
5111
5643
  __ mov(ecx, FieldOperand(edx, String::kLengthOffset));
5112
5644
  STATIC_ASSERT(kSmiTag == 0);
5113
 
  __ test(ecx, Operand(ecx));
 
5645
  __ test(ecx, ecx);
5114
5646
  __ j(not_zero, &second_not_zero_length, Label::kNear);
5115
5647
  // Second string is empty, result is first string which is already in eax.
5116
5648
  Counters* counters = masm->isolate()->counters();
5119
5651
  __ bind(&second_not_zero_length);
5120
5652
  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
5121
5653
  STATIC_ASSERT(kSmiTag == 0);
5122
 
  __ test(ebx, Operand(ebx));
 
5654
  __ test(ebx, ebx);
5123
5655
  __ j(not_zero, &both_not_zero_length, Label::kNear);
5124
5656
  // First string is empty, result is second string which is in edx.
5125
5657
  __ mov(eax, edx);
5134
5666
  // Look at the length of the result of adding the two strings.
5135
5667
  Label string_add_flat_result, longer_than_two;
5136
5668
  __ bind(&both_not_zero_length);
5137
 
  __ add(ebx, Operand(ecx));
 
5669
  __ add(ebx, ecx);
5138
5670
  STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength);
5139
5671
  // Handle exceptionally long strings in the runtime system.
5140
 
  __ j(overflow, &string_add_runtime);
 
5672
  __ j(overflow, &call_runtime);
5141
5673
  // Use the symbol table when adding two one character strings, as it
5142
5674
  // helps later optimizations to return a symbol here.
5143
 
  __ cmp(Operand(ebx), Immediate(Smi::FromInt(2)));
 
5675
  __ cmp(ebx, Immediate(Smi::FromInt(2)));
5144
5676
  __ j(not_equal, &longer_than_two);
5145
5677
 
5146
 
  // Check that both strings are non-external ascii strings.
5147
 
  __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx,
5148
 
                                         &string_add_runtime);
 
5678
  // Check that both strings are non-external ASCII strings.
 
5679
  __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime);
5149
5680
 
5150
5681
  // Get the two characters forming the new string.
5151
5682
  __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
5170
5701
  __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
5171
5702
  __ bind(&make_two_character_string_no_reload);
5172
5703
  __ IncrementCounter(counters->string_add_make_two_char(), 1);
5173
 
  __ AllocateAsciiString(eax,  // Result.
5174
 
                         2,    // Length.
5175
 
                         edi,  // Scratch 1.
5176
 
                         edx,  // Scratch 2.
5177
 
                         &string_add_runtime);
 
5704
  __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime);
5178
5705
  // Pack both characters in ebx.
5179
5706
  __ shl(ecx, kBitsPerByte);
5180
 
  __ or_(ebx, Operand(ecx));
 
5707
  __ or_(ebx, ecx);
5181
5708
  // Set the characters in the new string.
5182
5709
  __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx);
5183
5710
  __ IncrementCounter(counters->string_add_native(), 1);
5185
5712
 
5186
5713
  __ bind(&longer_than_two);
5187
5714
  // Check if resulting string will be flat.
5188
 
  __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength)));
 
5715
  __ cmp(ebx, Immediate(Smi::FromInt(ConsString::kMinLength)));
5189
5716
  __ j(below, &string_add_flat_result);
5190
5717
 
5191
5718
  // If result is not supposed to be flat allocate a cons string object. If both
5192
 
  // strings are ascii the result is an ascii cons string.
 
5719
  // strings are ASCII the result is an ASCII cons string.
5193
5720
  Label non_ascii, allocated, ascii_data;
5194
5721
  __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset));
5195
5722
  __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset));
5196
5723
  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
5197
5724
  __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
5198
 
  __ and_(ecx, Operand(edi));
 
5725
  __ and_(ecx, edi);
5199
5726
  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
5200
5727
  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
5201
5728
  __ test(ecx, Immediate(kStringEncodingMask));
5202
5729
  __ j(zero, &non_ascii);
5203
5730
  __ bind(&ascii_data);
5204
 
  // Allocate an acsii cons string.
5205
 
  __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime);
 
5731
  // Allocate an ASCII cons string.
 
5732
  __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime);
5206
5733
  __ bind(&allocated);
5207
5734
  // Fill the fields of the cons string.
5208
 
  if (FLAG_debug_code) __ AbortIfNotSmi(ebx);
 
5735
  __ AssertSmi(ebx);
5209
5736
  __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx);
5210
5737
  __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset),
5211
5738
         Immediate(String::kEmptyHashField));
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));
 
5753
  __ xor_(edi, 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);
5234
5761
 
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);
 
5788
 
 
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
 
5793
  __ xor_(ecx, edi);
 
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);
 
5809
 
 
5810
  // Push the addresses of both strings' first characters onto the stack.
 
5811
  __ push(edx);
 
5812
  __ push(eax);
 
5813
 
 
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);
5266
5820
 
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));
 
5834
  __ pop(edx);
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));
 
5845
  __ pop(edx);
5290
5846
  // eax: result string
5291
5847
  // ecx: next character of result
5292
5848
  // edx: first char of second argument
5300
5856
  // ebx: length of resulting flat string as a smi
5301
5857
  // edx: second string
5302
5858
  __ bind(&non_ascii_string_add_flat_result);
5303
 
  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
5304
 
  __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
5305
 
  __ j(not_zero, &string_add_runtime);
5306
 
  // Both strings are two byte strings. As they are short they are both
5307
 
  // flat.
 
5859
  // Both strings are two byte strings.
5308
5860
  __ SmiUntag(ebx);
5309
 
  __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime);
 
5861
  __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two);
5310
5862
  // eax: result string
5311
5863
  __ mov(ecx, eax);
5312
5864
  // Locate first character of result.
5313
 
  __ add(Operand(ecx),
5314
 
         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
5315
 
  // Load first argument and locate first character.
5316
 
  __ mov(edx, Operand(esp, 2 * kPointerSize));
 
5865
  __ add(ecx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
 
5866
  // Load second argument's length and first character location.  Account for
 
5867
  // values currently on the stack when fetching arguments from it.
 
5868
  __ mov(edx, Operand(esp, 4 * kPointerSize));
5317
5869
  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
5318
5870
  __ SmiUntag(edi);
5319
 
  __ add(Operand(edx),
5320
 
         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
 
5871
  __ pop(edx);
5321
5872
  // eax: result string
5322
5873
  // ecx: first character of result
5323
5874
  // edx: first char of first argument
5324
5875
  // edi: length of first argument
5325
5876
  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
5326
 
  // Load second argument and locate first character.
5327
 
  __ mov(edx, Operand(esp, 1 * kPointerSize));
 
5877
  // Load second argument's length and first character location.  Account for
 
5878
  // values currently on the stack when fetching arguments from it.
 
5879
  __ mov(edx, Operand(esp, 2 * kPointerSize));
5328
5880
  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
5329
5881
  __ SmiUntag(edi);
5330
 
  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
 
5882
  __ pop(edx);
5331
5883
  // eax: result string
5332
5884
  // ecx: next character of result
5333
5885
  // edx: first char of second argument
5336
5888
  __ IncrementCounter(counters->string_add_native(), 1);
5337
5889
  __ ret(2 * kPointerSize);
5338
5890
 
 
5891
  // Recover stack pointer before jumping to runtime.
 
5892
  __ bind(&call_runtime_drop_two);
 
5893
  __ Drop(2);
5339
5894
  // Just jump to runtime to add the two strings.
5340
 
  __ bind(&string_add_runtime);
 
5895
  __ bind(&call_runtime);
5341
5896
  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
5342
5897
 
5343
5898
  if (call_builtin.is_linked()) {
5403
5958
  if (ascii) {
5404
5959
    __ mov_b(scratch, Operand(src, 0));
5405
5960
    __ mov_b(Operand(dest, 0), scratch);
5406
 
    __ add(Operand(src), Immediate(1));
5407
 
    __ add(Operand(dest), Immediate(1));
 
5961
    __ add(src, Immediate(1));
 
5962
    __ add(dest, Immediate(1));
5408
5963
  } else {
5409
5964
    __ mov_w(scratch, Operand(src, 0));
5410
5965
    __ mov_w(Operand(dest, 0), scratch);
5411
 
    __ add(Operand(src), Immediate(2));
5412
 
    __ add(Operand(dest), Immediate(2));
 
5966
    __ add(src, Immediate(2));
 
5967
    __ add(dest, Immediate(2));
5413
5968
  }
5414
 
  __ sub(Operand(count), Immediate(1));
 
5969
  __ sub(count, Immediate(1));
5415
5970
  __ j(not_zero, &loop);
5416
5971
}
5417
5972
 
5434
5989
 
5435
5990
  // Nothing to do for zero characters.
5436
5991
  Label done;
5437
 
  __ test(count, Operand(count));
 
5992
  __ test(count, count);
5438
5993
  __ j(zero, &done);
5439
5994
 
5440
5995
  // Make count the number of bytes to copy.
5459
6014
 
5460
6015
  // Check if there are more bytes to copy.
5461
6016
  __ bind(&last_bytes);
5462
 
  __ test(count, Operand(count));
 
6017
  __ test(count, count);
5463
6018
  __ j(zero, &done);
5464
6019
 
5465
6020
  // Copy remaining characters.
5467
6022
  __ bind(&loop);
5468
6023
  __ mov_b(scratch, Operand(src, 0));
5469
6024
  __ mov_b(Operand(dest, 0), scratch);
5470
 
  __ add(Operand(src), Immediate(1));
5471
 
  __ add(Operand(dest), Immediate(1));
5472
 
  __ sub(Operand(count), Immediate(1));
 
6025
  __ add(src, Immediate(1));
 
6026
  __ add(dest, Immediate(1));
 
6027
  __ sub(count, Immediate(1));
5473
6028
  __ j(not_zero, &loop);
5474
6029
 
5475
6030
  __ bind(&done);
5491
6046
  // different hash algorithm. Don't try to look for these in the symbol table.
5492
6047
  Label not_array_index;
5493
6048
  __ mov(scratch, c1);
5494
 
  __ sub(Operand(scratch), Immediate(static_cast<int>('0')));
5495
 
  __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0')));
 
6049
  __ sub(scratch, Immediate(static_cast<int>('0')));
 
6050
  __ cmp(scratch, Immediate(static_cast<int>('9' - '0')));
5496
6051
  __ j(above, &not_array_index, Label::kNear);
5497
6052
  __ mov(scratch, c2);
5498
 
  __ sub(Operand(scratch), Immediate(static_cast<int>('0')));
5499
 
  __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0')));
 
6053
  __ sub(scratch, Immediate(static_cast<int>('0')));
 
6054
  __ cmp(scratch, Immediate(static_cast<int>('9' - '0')));
5500
6055
  __ j(below_equal, not_probed);
5501
6056
 
5502
6057
  __ bind(&not_array_index);
5509
6064
  // Collect the two characters in a register.
5510
6065
  Register chars = c1;
5511
6066
  __ shl(c2, kBitsPerByte);
5512
 
  __ or_(chars, Operand(c2));
 
6067
  __ or_(chars, c2);
5513
6068
 
5514
6069
  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
5515
6070
  // hash:  hash of two character string.
5516
6071
 
5517
6072
  // Load the symbol table.
5518
6073
  Register symbol_table = c2;
5519
 
  ExternalReference roots_address =
5520
 
      ExternalReference::roots_address(masm->isolate());
 
6074
  ExternalReference roots_array_start =
 
6075
      ExternalReference::roots_array_start(masm->isolate());
5521
6076
  __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex));
5522
6077
  __ mov(symbol_table,
5523
 
         Operand::StaticArray(scratch, times_pointer_size, roots_address));
 
6078
         Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
5524
6079
 
5525
6080
  // Calculate capacity mask from the symbol table capacity.
5526
6081
  Register mask = scratch2;
5527
6082
  __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
5528
6083
  __ SmiUntag(mask);
5529
 
  __ sub(Operand(mask), Immediate(1));
 
6084
  __ sub(mask, Immediate(1));
5530
6085
 
5531
6086
  // Registers
5532
6087
  // chars:        two character string, char 1 in byte 0 and char 2 in byte 1.
5544
6099
    // Calculate entry in symbol table.
5545
6100
    __ mov(scratch, hash);
5546
6101
    if (i > 0) {
5547
 
      __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i)));
 
6102
      __ add(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
5548
6103
    }
5549
 
    __ and_(scratch, Operand(mask));
 
6104
    __ and_(scratch, mask);
5550
6105
 
5551
6106
    // Load the entry from the symbol table.
5552
6107
    STATIC_ASSERT(SymbolTable::kEntrySize == 1);
5560
6115
    Factory* factory = masm->isolate()->factory();
5561
6116
    __ cmp(candidate, factory->undefined_value());
5562
6117
    __ j(equal, not_found);
5563
 
    __ cmp(candidate, factory->null_value());
 
6118
    __ cmp(candidate, factory->the_hole_value());
5564
6119
    __ j(equal, &next_probe[i]);
5565
6120
 
5566
6121
    // If length is not 2 the string is not a candidate.
5573
6128
    __ push(mask);
5574
6129
    Register temp = mask;
5575
6130
 
5576
 
    // Check that the candidate is a non-external ascii string.
 
6131
    // Check that the candidate is a non-external ASCII string.
5577
6132
    __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset));
5578
6133
    __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5579
6134
    __ JumpIfInstanceTypeIsNotSequentialAscii(
5582
6137
    // Check if the two characters match.
5583
6138
    __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
5584
6139
    __ and_(temp, 0x0000ffff);
5585
 
    __ cmp(chars, Operand(temp));
 
6140
    __ cmp(chars, temp);
5586
6141
    __ j(equal, &found_in_symbol_table);
5587
6142
    __ bind(&next_probe_pop_mask[i]);
5588
6143
    __ pop(mask);
5608
6163
                                    Register scratch) {
5609
6164
  // hash = (seed + character) + ((seed + character) << 10);
5610
6165
  if (Serializer::enabled()) {
5611
 
    ExternalReference roots_address =
5612
 
        ExternalReference::roots_address(masm->isolate());
 
6166
    ExternalReference roots_array_start =
 
6167
        ExternalReference::roots_array_start(masm->isolate());
5613
6168
    __ mov(scratch, Immediate(Heap::kHashSeedRootIndex));
5614
6169
    __ mov(scratch, Operand::StaticArray(scratch,
5615
6170
                                         times_pointer_size,
5616
 
                                         roots_address));
 
6171
                                         roots_array_start));
5617
6172
    __ SmiUntag(scratch);
5618
 
    __ add(scratch, Operand(character));
 
6173
    __ add(scratch, character);
5619
6174
    __ mov(hash, scratch);
5620
6175
    __ shl(scratch, 10);
5621
 
    __ add(hash, Operand(scratch));
 
6176
    __ add(hash, scratch);
5622
6177
  } else {
5623
6178
    int32_t seed = masm->isolate()->heap()->HashSeed();
5624
6179
    __ lea(scratch, Operand(character, seed));
5628
6183
  // hash ^= hash >> 6;
5629
6184
  __ mov(scratch, hash);
5630
6185
  __ shr(scratch, 6);
5631
 
  __ xor_(hash, Operand(scratch));
 
6186
  __ xor_(hash, scratch);
5632
6187
}
5633
6188
 
5634
6189
 
5637
6192
                                            Register character,
5638
6193
                                            Register scratch) {
5639
6194
  // hash += character;
5640
 
  __ add(hash, Operand(character));
 
6195
  __ add(hash, character);
5641
6196
  // hash += hash << 10;
5642
6197
  __ mov(scratch, hash);
5643
6198
  __ shl(scratch, 10);
5644
 
  __ add(hash, Operand(scratch));
 
6199
  __ add(hash, scratch);
5645
6200
  // hash ^= hash >> 6;
5646
6201
  __ mov(scratch, hash);
5647
6202
  __ shr(scratch, 6);
5648
 
  __ xor_(hash, Operand(scratch));
 
6203
  __ xor_(hash, scratch);
5649
6204
}
5650
6205
 
5651
6206
 
5655
6210
  // hash += hash << 3;
5656
6211
  __ mov(scratch, hash);
5657
6212
  __ shl(scratch, 3);
5658
 
  __ add(hash, Operand(scratch));
 
6213
  __ add(hash, scratch);
5659
6214
  // hash ^= hash >> 11;
5660
6215
  __ mov(scratch, hash);
5661
6216
  __ shr(scratch, 11);
5662
 
  __ xor_(hash, Operand(scratch));
 
6217
  __ xor_(hash, scratch);
5663
6218
  // hash += hash << 15;
5664
6219
  __ mov(scratch, hash);
5665
6220
  __ shl(scratch, 15);
5666
 
  __ add(hash, Operand(scratch));
 
6221
  __ add(hash, scratch);
5667
6222
 
5668
6223
  __ and_(hash, String::kHashBitMask);
5669
6224
 
5695
6250
  // ebx: instance type
5696
6251
 
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));
 
6257
  __ sub(ecx, edx);
5704
6258
  __ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
5705
 
  Label return_eax;
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.
5711
 
  __ cmp(ecx, 2);
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, &not_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(&not_original_string);
5714
6269
 
5715
 
  // Sub string of length 2 requested.
5716
6270
  // eax: string
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);
5721
 
 
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));
5725
 
  __ movzx_b(ecx,
5726
 
             FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1));
5727
 
 
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);
5734
 
 
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);
 
6282
 
 
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);
 
6296
 
 
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);
 
6305
 
 
6306
  __ bind(&seq_or_external_string);
 
6307
  // Sequential or external string.  Just move string to the expected register.
 
6308
  __ mov(edi, eax);
 
6309
 
 
6310
  __ bind(&underlying_unpacked);
5741
6311
 
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(&copy_routine);
5748
 
    __ bind(&result_longer_than_two);
5749
 
 
5750
 
    // eax: string
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, &copy_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);
5766
 
 
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);
5776
 
 
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);
5782
 
 
5783
 
    __ bind(&seq_string);
5784
 
    // Sequential string.  Just move string to the right register.
5785
 
    __ mov(edi, eax);
5786
 
 
5787
 
    __ bind(&allocate_slice);
5788
 
    // edi: underlying subject string
5789
 
    // ebx: instance type of original subject string
5790
 
    // edx: offset
5791
 
    // ecx: length
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);
5808
 
    __ SmiTag(ecx);
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);
5814
6343
 
5815
6344
    __ bind(&copy_routine);
5816
 
  } else {
5817
 
    __ bind(&result_longer_than_two);
5818
6345
  }
5819
6346
 
5820
 
  // eax: string
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);
5826
 
 
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);
 
6358
 
 
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));
 
6368
 
 
6369
  __ bind(&sequential_string);
 
6370
  // Stash away (adjusted) index and (underlying) string.
 
6371
  __ push(edx);
 
6372
  __ push(edi);
 
6373
  __ SmiUntag(ecx);
 
6374
  STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0);
 
6375
  __ test_b(ebx, kStringEncodingMask);
 
6376
  __ j(zero, &two_byte_sequential);
 
6377
 
 
6378
  // Sequential ASCII string.  Allocate the result.
 
6379
  __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
5829
6380
 
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
 
6388
  __ pop(esi);
 
6389
  __ pop(ebx);
5840
6390
  __ SmiUntag(ebx);
5841
 
  __ add(esi, Operand(ebx));
 
6391
  __ lea(esi, FieldOperand(esi, ebx, times_1, SeqAsciiString::kHeaderSize));
5842
6392
 
5843
6393
  // eax: result string
5844
6394
  // ecx: result length
5847
6397
  // esi: character of sub string start
5848
6398
  StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true);
5849
6399
  __ mov(esi, edx);  // Restore esi.
5850
 
  Counters* counters = masm->isolate()->counters();
5851
6400
  __ IncrementCounter(counters->sub_string_native(), 1);
5852
6401
  __ ret(3 * kPointerSize);
5853
6402
 
5854
 
  __ bind(&non_ascii_flat);
5855
 
  // eax: string
5856
 
  // ebx: instance type & kStringRepresentationMask | kStringEncodingMask
5857
 
  // ecx: result string length
5858
 
  // Check for flat two byte string
5859
 
  __ cmp(ebx, kSeqStringTag | kTwoByteStringTag);
5860
 
  __ j(not_equal, &runtime);
5861
 
 
5862
 
  // Allocate the result.
5863
 
  __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime);
 
6403
  __ bind(&two_byte_sequential);
 
6404
  // Sequential two-byte string.  Allocate the result.
 
6405
  __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
5864
6406
 
5865
6407
  // eax: result string
5866
6408
  // ecx: result string length
5867
6409
  __ mov(edx, esi);  // esi used by following code.
5868
6410
  // Locate first character of result.
5869
6411
  __ mov(edi, eax);
5870
 
  __ add(Operand(edi),
 
6412
  __ add(edi,
5871
6413
         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
5872
6414
  // Load string argument and locate character of sub string start.
5873
 
  __ mov(esi, Operand(esp, 3 * kPointerSize));
5874
 
  __ add(Operand(esi),
5875
 
         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
5876
 
  __ mov(ebx, Operand(esp, 2 * kPointerSize));  // from
 
6415
  __ pop(esi);
 
6416
  __ pop(ebx);
5877
6417
  // As from is a smi it is 2 times the value which matches the size of a two
5878
6418
  // byte character.
5879
6419
  STATIC_ASSERT(kSmiTag == 0);
5880
6420
  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
5881
 
  __ add(esi, Operand(ebx));
 
6421
  __ lea(esi, FieldOperand(esi, ebx, times_1, SeqTwoByteString::kHeaderSize));
5882
6422
 
5883
6423
  // eax: result string
5884
6424
  // ecx: result length
5887
6427
  // esi: character of sub string start
5888
6428
  StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false);
5889
6429
  __ mov(esi, edx);  // Restore esi.
5890
 
 
5891
 
  __ bind(&return_eax);
5892
6430
  __ IncrementCounter(counters->sub_string_native(), 1);
5893
6431
  __ ret(3 * kPointerSize);
5894
6432
 
 
6433
  // Drop pushed values on the stack before tail call.
 
6434
  __ bind(&runtime_drop_two);
 
6435
  __ Drop(2);
 
6436
 
5895
6437
  // Just jump to runtime to create the sub string.
5896
6438
  __ bind(&runtime);
5897
6439
  __ TailCallRuntime(Runtime::kSubString, 3, 1);
5918
6460
  Label compare_chars;
5919
6461
  __ bind(&check_zero_length);
5920
6462
  STATIC_ASSERT(kSmiTag == 0);
5921
 
  __ test(length, Operand(length));
 
6463
  __ test(length, length);
5922
6464
  __ j(not_zero, &compare_chars, Label::kNear);
5923
6465
  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
5924
6466
  __ ret(0);
5953
6495
 
5954
6496
  __ j(less_equal, &left_shorter, Label::kNear);
5955
6497
  // Right string is shorter. Change scratch1 to be length of right string.
5956
 
  __ sub(scratch1, Operand(length_delta));
 
6498
  __ sub(scratch1, length_delta);
5957
6499
  __ bind(&left_shorter);
5958
6500
 
5959
6501
  Register min_length = scratch1;
5960
6502
 
5961
6503
  // If either length is zero, just compare lengths.
5962
6504
  Label compare_lengths;
5963
 
  __ test(min_length, Operand(min_length));
 
6505
  __ test(min_length, min_length);
5964
6506
  __ j(zero, &compare_lengths, Label::kNear);
5965
6507
 
5966
6508
  // Compare characters.
5970
6512
 
5971
6513
  // Compare lengths -  strings up to min-length are equal.
5972
6514
  __ bind(&compare_lengths);
5973
 
  __ test(length_delta, Operand(length_delta));
 
6515
  __ test(length_delta, length_delta);
5974
6516
  __ j(not_zero, &result_not_equal, Label::kNear);
5975
6517
 
5976
6518
  // Result is EQUAL.
6019
6561
  __ mov_b(scratch, Operand(left, index, times_1, 0));
6020
6562
  __ cmpb(scratch, Operand(right, index, times_1, 0));
6021
6563
  __ j(not_equal, chars_not_equal, chars_not_equal_near);
6022
 
  __ add(Operand(index), Immediate(1));
 
6564
  __ inc(index);
6023
6565
  __ j(not_zero, &loop);
6024
6566
}
6025
6567
 
6036
6578
  __ mov(eax, Operand(esp, 1 * kPointerSize));  // right
6037
6579
 
6038
6580
  Label not_same;
6039
 
  __ cmp(edx, Operand(eax));
 
6581
  __ cmp(edx, eax);
6040
6582
  __ j(not_equal, &not_same, Label::kNear);
6041
6583
  STATIC_ASSERT(EQUAL == 0);
6042
6584
  STATIC_ASSERT(kSmiTag == 0);
6046
6588
 
6047
6589
  __ bind(&not_same);
6048
6590
 
6049
 
  // Check that both objects are sequential ascii strings.
 
6591
  // Check that both objects are sequential ASCII strings.
6050
6592
  __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
6051
6593
 
6052
 
  // Compare flat ascii strings.
 
6594
  // Compare flat ASCII strings.
6053
6595
  // Drop arguments from the stack.
6054
6596
  __ pop(ecx);
6055
 
  __ add(Operand(esp), Immediate(2 * kPointerSize));
 
6597
  __ add(esp, Immediate(2 * kPointerSize));
6056
6598
  __ push(ecx);
6057
6599
  GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
6058
6600
 
6066
6608
void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
6067
6609
  ASSERT(state_ == CompareIC::SMIS);
6068
6610
  Label miss;
6069
 
  __ mov(ecx, Operand(edx));
6070
 
  __ or_(ecx, Operand(eax));
 
6611
  __ mov(ecx, edx);
 
6612
  __ or_(ecx, eax);
6071
6613
  __ JumpIfNotSmi(ecx, &miss, Label::kNear);
6072
6614
 
6073
6615
  if (GetCondition() == equal) {
6074
6616
    // For equality we do not care about the sign of the result.
6075
 
    __ sub(eax, Operand(edx));
 
6617
    __ sub(eax, edx);
6076
6618
  } else {
6077
6619
    Label done;
6078
 
    __ sub(edx, Operand(eax));
 
6620
    __ sub(edx, eax);
6079
6621
    __ j(no_overflow, &done, Label::kNear);
6080
6622
    // Correct sign of result in case of overflow.
6081
6623
    __ not_(edx);
6093
6635
  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
6094
6636
 
6095
6637
  Label generic_stub;
6096
 
  Label unordered;
 
6638
  Label unordered, maybe_undefined1, maybe_undefined2;
6097
6639
  Label miss;
6098
 
  __ mov(ecx, Operand(edx));
6099
 
  __ and_(ecx, Operand(eax));
 
6640
  __ mov(ecx, edx);
 
6641
  __ and_(ecx, eax);
6100
6642
  __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
6101
6643
 
6102
6644
  __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
6103
 
  __ j(not_equal, &miss, Label::kNear);
 
6645
  __ j(not_equal, &maybe_undefined1, Label::kNear);
6104
6646
  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
6105
 
  __ j(not_equal, &miss, Label::kNear);
 
6647
  __ j(not_equal, &maybe_undefined2, Label::kNear);
6106
6648
 
6107
6649
  // Inlining the double comparison and falling back to the general compare
6108
6650
  // stub if NaN is involved or SS2 or CMOV is unsupported.
6124
6666
    // Performing mov, because xor would destroy the flag register.
6125
6667
    __ mov(eax, 0);  // equal
6126
6668
    __ mov(ecx, Immediate(Smi::FromInt(1)));
6127
 
    __ cmov(above, eax, Operand(ecx));
 
6669
    __ cmov(above, eax, ecx);
6128
6670
    __ mov(ecx, Immediate(Smi::FromInt(-1)));
6129
 
    __ cmov(below, eax, Operand(ecx));
 
6671
    __ cmov(below, eax, ecx);
6130
6672
    __ ret(0);
6131
 
 
6132
 
    __ bind(&unordered);
6133
6673
  }
6134
6674
 
 
6675
  __ bind(&unordered);
6135
6676
  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
6136
6677
  __ bind(&generic_stub);
6137
6678
  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
6138
6679
 
 
6680
  __ bind(&maybe_undefined1);
 
6681
  if (Token::IsOrderedRelationalCompareOp(op_)) {
 
6682
    __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value()));
 
6683
    __ j(not_equal, &miss);
 
6684
    __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
 
6685
    __ j(not_equal, &maybe_undefined2, Label::kNear);
 
6686
    __ jmp(&unordered);
 
6687
  }
 
6688
 
 
6689
  __ bind(&maybe_undefined2);
 
6690
  if (Token::IsOrderedRelationalCompareOp(op_)) {
 
6691
    __ cmp(edx, Immediate(masm->isolate()->factory()->undefined_value()));
 
6692
    __ j(equal, &unordered);
 
6693
  }
 
6694
 
6139
6695
  __ bind(&miss);
6140
6696
  GenerateMiss(masm);
6141
6697
}
6153
6709
 
6154
6710
  // Check that both operands are heap objects.
6155
6711
  Label miss;
6156
 
  __ mov(tmp1, Operand(left));
 
6712
  __ mov(tmp1, left);
6157
6713
  STATIC_ASSERT(kSmiTag == 0);
6158
 
  __ and_(tmp1, Operand(right));
 
6714
  __ and_(tmp1, right);
6159
6715
  __ JumpIfSmi(tmp1, &miss, Label::kNear);
6160
6716
 
6161
6717
  // Check that both operands are symbols.
6164
6720
  __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
6165
6721
  __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
6166
6722
  STATIC_ASSERT(kSymbolTag != 0);
6167
 
  __ and_(tmp1, Operand(tmp2));
 
6723
  __ and_(tmp1, tmp2);
6168
6724
  __ test(tmp1, Immediate(kIsSymbolMask));
6169
6725
  __ j(zero, &miss, Label::kNear);
6170
6726
 
6171
6727
  // Symbols are compared by identity.
6172
6728
  Label done;
6173
 
  __ cmp(left, Operand(right));
 
6729
  __ cmp(left, right);
6174
6730
  // Make sure eax is non-zero. At this point input operands are
6175
6731
  // guaranteed to be non-zero.
6176
6732
  ASSERT(right.is(eax));
6188
6744
 
6189
6745
void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
6190
6746
  ASSERT(state_ == CompareIC::STRINGS);
6191
 
  ASSERT(GetCondition() == equal);
6192
6747
  Label miss;
6193
6748
 
 
6749
  bool equality = Token::IsEqualityOp(op_);
 
6750
 
6194
6751
  // Registers containing left and right operands respectively.
6195
6752
  Register left = edx;
6196
6753
  Register right = eax;
6199
6756
  Register tmp3 = edi;
6200
6757
 
6201
6758
  // Check that both operands are heap objects.
6202
 
  __ mov(tmp1, Operand(left));
 
6759
  __ mov(tmp1, left);
6203
6760
  STATIC_ASSERT(kSmiTag == 0);
6204
 
  __ and_(tmp1, Operand(right));
 
6761
  __ and_(tmp1, right);
6205
6762
  __ JumpIfSmi(tmp1, &miss);
6206
6763
 
6207
6764
  // Check that both operands are strings. This leaves the instance
6212
6769
  __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
6213
6770
  __ mov(tmp3, tmp1);
6214
6771
  STATIC_ASSERT(kNotStringTag != 0);
6215
 
  __ or_(tmp3, Operand(tmp2));
 
6772
  __ or_(tmp3, tmp2);
6216
6773
  __ test(tmp3, Immediate(kIsNotStringMask));
6217
6774
  __ j(not_zero, &miss);
6218
6775
 
6219
6776
  // Fast check for identical strings.
6220
6777
  Label not_same;
6221
 
  __ cmp(left, Operand(right));
 
6778
  __ cmp(left, right);
6222
6779
  __ j(not_equal, &not_same, Label::kNear);
6223
6780
  STATIC_ASSERT(EQUAL == 0);
6224
6781
  STATIC_ASSERT(kSmiTag == 0);
6229
6786
  __ bind(&not_same);
6230
6787
 
6231
6788
  // Check that both strings are symbols. If they are, we're done
6232
 
  // because we already know they are not identical.
6233
 
  Label do_compare;
6234
 
  STATIC_ASSERT(kSymbolTag != 0);
6235
 
  __ and_(tmp1, Operand(tmp2));
6236
 
  __ test(tmp1, Immediate(kIsSymbolMask));
6237
 
  __ j(zero, &do_compare, Label::kNear);
6238
 
  // Make sure eax is non-zero. At this point input operands are
6239
 
  // guaranteed to be non-zero.
6240
 
  ASSERT(right.is(eax));
6241
 
  __ ret(0);
 
6789
  // because we already know they are not identical.  But in the case of
 
6790
  // non-equality compare, we still need to determine the order.
 
6791
  if (equality) {
 
6792
    Label do_compare;
 
6793
    STATIC_ASSERT(kSymbolTag != 0);
 
6794
    __ and_(tmp1, tmp2);
 
6795
    __ test(tmp1, Immediate(kIsSymbolMask));
 
6796
    __ j(zero, &do_compare, Label::kNear);
 
6797
    // Make sure eax is non-zero. At this point input operands are
 
6798
    // guaranteed to be non-zero.
 
6799
    ASSERT(right.is(eax));
 
6800
    __ ret(0);
 
6801
    __ bind(&do_compare);
 
6802
  }
6242
6803
 
6243
6804
  // Check that both strings are sequential ASCII.
6244
6805
  Label runtime;
6245
 
  __ bind(&do_compare);
6246
6806
  __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime);
6247
6807
 
6248
6808
  // Compare flat ASCII strings. Returns when done.
6249
 
  StringCompareStub::GenerateFlatAsciiStringEquals(
6250
 
      masm, left, right, tmp1, tmp2);
 
6809
  if (equality) {
 
6810
    StringCompareStub::GenerateFlatAsciiStringEquals(
 
6811
        masm, left, right, tmp1, tmp2);
 
6812
  } else {
 
6813
    StringCompareStub::GenerateCompareFlatAsciiStrings(
 
6814
        masm, left, right, tmp1, tmp2, tmp3);
 
6815
  }
6251
6816
 
6252
6817
  // Handle more complex cases in runtime.
6253
6818
  __ bind(&runtime);
6255
6820
  __ push(left);
6256
6821
  __ push(right);
6257
6822
  __ push(tmp1);
6258
 
  __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
 
6823
  if (equality) {
 
6824
    __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
 
6825
  } else {
 
6826
    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
 
6827
  }
6259
6828
 
6260
6829
  __ bind(&miss);
6261
6830
  GenerateMiss(masm);
6265
6834
void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
6266
6835
  ASSERT(state_ == CompareIC::OBJECTS);
6267
6836
  Label miss;
6268
 
  __ mov(ecx, Operand(edx));
6269
 
  __ and_(ecx, Operand(eax));
 
6837
  __ mov(ecx, edx);
 
6838
  __ and_(ecx, eax);
6270
6839
  __ JumpIfSmi(ecx, &miss, Label::kNear);
6271
6840
 
6272
6841
  __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
6275
6844
  __ j(not_equal, &miss, Label::kNear);
6276
6845
 
6277
6846
  ASSERT(GetCondition() == equal);
6278
 
  __ sub(eax, Operand(edx));
 
6847
  __ sub(eax, edx);
 
6848
  __ ret(0);
 
6849
 
 
6850
  __ bind(&miss);
 
6851
  GenerateMiss(masm);
 
6852
}
 
6853
 
 
6854
 
 
6855
void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
 
6856
  Label miss;
 
6857
  __ mov(ecx, edx);
 
6858
  __ and_(ecx, eax);
 
6859
  __ JumpIfSmi(ecx, &miss, Label::kNear);
 
6860
 
 
6861
  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
 
6862
  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
 
6863
  __ cmp(ecx, known_map_);
 
6864
  __ j(not_equal, &miss, Label::kNear);
 
6865
  __ cmp(ebx, known_map_);
 
6866
  __ j(not_equal, &miss, Label::kNear);
 
6867
 
 
6868
  __ sub(eax, edx);
6279
6869
  __ ret(0);
6280
6870
 
6281
6871
  __ bind(&miss);
6284
6874
 
6285
6875
 
6286
6876
void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
6287
 
  // Save the registers.
6288
 
  __ pop(ecx);
6289
 
  __ push(edx);
6290
 
  __ push(eax);
6291
 
  __ push(ecx);
6292
 
 
6293
 
  // Call the runtime system in a fresh internal frame.
6294
 
  ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
6295
 
                                             masm->isolate());
6296
 
  __ EnterInternalFrame();
6297
 
  __ push(edx);
6298
 
  __ push(eax);
6299
 
  __ push(Immediate(Smi::FromInt(op_)));
6300
 
  __ CallExternalReference(miss, 3);
6301
 
  __ LeaveInternalFrame();
6302
 
 
6303
 
  // Compute the entry point of the rewritten stub.
6304
 
  __ lea(edi, FieldOperand(eax, Code::kHeaderSize));
6305
 
 
6306
 
  // Restore registers.
6307
 
  __ pop(ecx);
6308
 
  __ pop(eax);
6309
 
  __ pop(edx);
6310
 
  __ push(ecx);
 
6877
  {
 
6878
    // Call the runtime system in a fresh internal frame.
 
6879
    ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
 
6880
                                               masm->isolate());
 
6881
    FrameScope scope(masm, StackFrame::INTERNAL);
 
6882
    __ push(edx);  // Preserve edx and eax.
 
6883
    __ push(eax);
 
6884
    __ push(edx);  // And also use them as the arguments.
 
6885
    __ push(eax);
 
6886
    __ push(Immediate(Smi::FromInt(op_)));
 
6887
    __ CallExternalReference(miss, 3);
 
6888
    // Compute the entry point of the rewritten stub.
 
6889
    __ lea(edi, FieldOperand(eax, Code::kHeaderSize));
 
6890
    __ pop(eax);
 
6891
    __ pop(edx);
 
6892
  }
6311
6893
 
6312
6894
  // Do a tail call to the rewritten stub.
6313
 
  __ jmp(Operand(edi));
 
6895
  __ jmp(edi);
6314
6896
}
6315
6897
 
6316
6898
 
6319
6901
// must always call a backup property check that is complete.
6320
6902
// This function is safe to call if the receiver has fast properties.
6321
6903
// Name must be a symbol and receiver must be a heap object.
6322
 
MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
6323
 
    MacroAssembler* masm,
6324
 
    Label* miss,
6325
 
    Label* done,
6326
 
    Register properties,
6327
 
    String* name,
6328
 
    Register r0) {
 
6904
void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
 
6905
                                                        Label* miss,
 
6906
                                                        Label* done,
 
6907
                                                        Register properties,
 
6908
                                                        Handle<String> name,
 
6909
                                                        Register r0) {
6329
6910
  ASSERT(name->IsSymbol());
6330
6911
 
6331
6912
  // If names of slots in range from 1 to kProbes - 1 for the hash value are
6332
6913
  // not equal to the name and kProbes-th slot is not used (its name is the
6333
6914
  // undefined value), it guarantees the hash table doesn't contain the
6334
6915
  // property. It's true even if some slots represent deleted properties
6335
 
  // (their names are the null value).
 
6916
  // (their names are the hole value).
6336
6917
  for (int i = 0; i < kInlinedProbes; i++) {
6337
6918
    // Compute the masked index: (hash + i + i * i) & mask.
6338
6919
    Register index = r0;
6339
6920
    // Capacity is smi 2^n.
6340
6921
    __ mov(index, FieldOperand(properties, kCapacityOffset));
6341
6922
    __ dec(index);
6342
 
    __ and_(Operand(index),
6343
 
           Immediate(Smi::FromInt(name->Hash() +
 
6923
    __ and_(index,
 
6924
            Immediate(Smi::FromInt(name->Hash() +
6344
6925
                                   StringDictionary::GetProbeOffset(i))));
6345
6926
 
6346
6927
    // Scale the index by multiplying by the entry size.
6358
6939
    __ cmp(entity_name, Handle<String>(name));
6359
6940
    __ j(equal, miss);
6360
6941
 
 
6942
    Label the_hole;
 
6943
    // Check for the hole and skip.
 
6944
    __ cmp(entity_name, masm->isolate()->factory()->the_hole_value());
 
6945
    __ j(equal, &the_hole, Label::kNear);
 
6946
 
6361
6947
    // Check if the entry name is not a symbol.
6362
6948
    __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
6363
6949
    __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
6364
6950
              kIsSymbolMask);
6365
6951
    __ j(zero, miss);
 
6952
    __ bind(&the_hole);
6366
6953
  }
6367
6954
 
6368
6955
  StringDictionaryLookupStub stub(properties,
6371
6958
                                  StringDictionaryLookupStub::NEGATIVE_LOOKUP);
6372
6959
  __ push(Immediate(Handle<Object>(name)));
6373
6960
  __ push(Immediate(name->Hash()));
6374
 
  MaybeObject* result = masm->TryCallStub(&stub);
6375
 
  if (result->IsFailure()) return result;
6376
 
  __ test(r0, Operand(r0));
 
6961
  __ CallStub(&stub);
 
6962
  __ test(r0, r0);
6377
6963
  __ j(not_zero, miss);
6378
6964
  __ jmp(done);
6379
 
  return result;
6380
6965
}
6381
6966
 
6382
6967
 
6391
6976
                                                        Register name,
6392
6977
                                                        Register r0,
6393
6978
                                                        Register r1) {
6394
 
  // Assert that name contains a string.
6395
 
  if (FLAG_debug_code) __ AbortIfNotString(name);
 
6979
  ASSERT(!elements.is(r0));
 
6980
  ASSERT(!elements.is(r1));
 
6981
  ASSERT(!name.is(r0));
 
6982
  ASSERT(!name.is(r1));
 
6983
 
 
6984
  __ AssertString(name);
6396
6985
 
6397
6986
  __ mov(r1, FieldOperand(elements, kCapacityOffset));
6398
6987
  __ shr(r1, kSmiTagSize);  // convert smi to int
6406
6995
    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
6407
6996
    __ shr(r0, String::kHashShift);
6408
6997
    if (i > 0) {
6409
 
      __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
 
6998
      __ add(r0, Immediate(StringDictionary::GetProbeOffset(i)));
6410
6999
    }
6411
 
    __ and_(r0, Operand(r1));
 
7000
    __ and_(r0, r1);
6412
7001
 
6413
7002
    // Scale the index by multiplying by the entry size.
6414
7003
    ASSERT(StringDictionary::kEntrySize == 3);
6432
7021
  __ push(r0);
6433
7022
  __ CallStub(&stub);
6434
7023
 
6435
 
  __ test(r1, Operand(r1));
 
7024
  __ test(r1, r1);
6436
7025
  __ j(zero, miss);
6437
7026
  __ jmp(done);
6438
7027
}
6439
7028
 
6440
7029
 
6441
7030
void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
 
7031
  // This stub overrides SometimesSetsUpAFrame() to return false.  That means
 
7032
  // we cannot call anything that could cause a GC from this stub.
6442
7033
  // Stack frame on entry:
6443
7034
  //  esp[0 * kPointerSize]: return address.
6444
7035
  //  esp[1 * kPointerSize]: key's hash.
6469
7060
    // Compute the masked index: (hash + i + i * i) & mask.
6470
7061
    __ mov(scratch, Operand(esp, 2 * kPointerSize));
6471
7062
    if (i > 0) {
6472
 
      __ add(Operand(scratch),
6473
 
             Immediate(StringDictionary::GetProbeOffset(i)));
 
7063
      __ add(scratch, Immediate(StringDictionary::GetProbeOffset(i)));
6474
7064
    }
6475
7065
    __ and_(scratch, Operand(esp, 0));
6476
7066
 
6526
7116
}
6527
7117
 
6528
7118
 
 
7119
struct AheadOfTimeWriteBarrierStubList {
 
7120
  Register object, value, address;
 
7121
  RememberedSetAction action;
 
7122
};
 
7123
 
 
7124
 
 
7125
#define REG(Name) { kRegister_ ## Name ## _Code }
 
7126
 
 
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}
 
7162
};
 
7163
 
 
7164
#undef REG
 
7165
 
 
7166
bool RecordWriteStub::IsPregenerated() {
 
7167
  for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
 
7168
       !entry->object.is(no_reg);
 
7169
       entry++) {
 
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) {
 
7175
      return true;
 
7176
    }
 
7177
  }
 
7178
  return false;
 
7179
}
 
7180
 
 
7181
 
 
7182
void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() {
 
7183
  StoreBufferOverflowStub stub1(kDontSaveFPRegs);
 
7184
  stub1.GetCode()->set_is_pregenerated(true);
 
7185
 
 
7186
  CpuFeatures::TryForceFeatureScope scope(SSE2);
 
7187
  if (CpuFeatures::IsSupported(SSE2)) {
 
7188
    StoreBufferOverflowStub stub2(kSaveFPRegs);
 
7189
    stub2.GetCode()->set_is_pregenerated(true);
 
7190
  }
 
7191
}
 
7192
 
 
7193
 
 
7194
void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() {
 
7195
  for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
 
7196
       !entry->object.is(no_reg);
 
7197
       entry++) {
 
7198
    RecordWriteStub stub(entry->object,
 
7199
                         entry->value,
 
7200
                         entry->address,
 
7201
                         entry->action,
 
7202
                         kDontSaveFPRegs);
 
7203
    stub.GetCode()->set_is_pregenerated(true);
 
7204
  }
 
7205
}
 
7206
 
 
7207
 
 
7208
bool CodeStub::CanUseFPRegisters() {
 
7209
  return CpuFeatures::IsSupported(SSE2);
 
7210
}
 
7211
 
 
7212
 
 
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;
 
7220
 
 
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);
 
7227
 
 
7228
  if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
 
7229
    __ RememberedSetHelper(object_,
 
7230
                           address_,
 
7231
                           value_,
 
7232
                           save_fp_regs_mode_,
 
7233
                           MacroAssembler::kReturnAtEnd);
 
7234
  } else {
 
7235
    __ ret(0);
 
7236
  }
 
7237
 
 
7238
  __ bind(&skip_to_incremental_noncompacting);
 
7239
  GenerateIncremental(masm, INCREMENTAL);
 
7240
 
 
7241
  __ bind(&skip_to_incremental_compacting);
 
7242
  GenerateIncremental(masm, INCREMENTAL_COMPACTION);
 
7243
 
 
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);
 
7248
}
 
7249
 
 
7250
 
 
7251
void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
 
7252
  regs_.Save(masm);
 
7253
 
 
7254
  if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
 
7255
    Label dont_need_remembered_set;
 
7256
 
 
7257
    __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
 
7258
    __ JumpIfNotInNewSpace(regs_.scratch0(),  // Value.
 
7259
                           regs_.scratch0(),
 
7260
                           &dont_need_remembered_set);
 
7261
 
 
7262
    __ CheckPageFlag(regs_.object(),
 
7263
                     regs_.scratch0(),
 
7264
                     1 << MemoryChunk::SCAN_ON_SCAVENGE,
 
7265
                     not_zero,
 
7266
                     &dont_need_remembered_set);
 
7267
 
 
7268
    // First notify the incremental marker if necessary, then update the
 
7269
    // remembered set.
 
7270
    CheckNeedsToInformIncrementalMarker(
 
7271
        masm,
 
7272
        kUpdateRememberedSetOnNoNeedToInformIncrementalMarker,
 
7273
        mode);
 
7274
    InformIncrementalMarker(masm, mode);
 
7275
    regs_.Restore(masm);
 
7276
    __ RememberedSetHelper(object_,
 
7277
                           address_,
 
7278
                           value_,
 
7279
                           save_fp_regs_mode_,
 
7280
                           MacroAssembler::kReturnAtEnd);
 
7281
 
 
7282
    __ bind(&dont_need_remembered_set);
 
7283
  }
 
7284
 
 
7285
  CheckNeedsToInformIncrementalMarker(
 
7286
      masm,
 
7287
      kReturnOnNoNeedToInformIncrementalMarker,
 
7288
      mode);
 
7289
  InformIncrementalMarker(masm, mode);
 
7290
  regs_.Restore(masm);
 
7291
  __ ret(0);
 
7292
}
 
7293
 
 
7294
 
 
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.
 
7302
  } else {
 
7303
    ASSERT(mode == INCREMENTAL);
 
7304
    __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
 
7305
    __ mov(Operand(esp, 1 * kPointerSize), regs_.scratch0());  // Value.
 
7306
  }
 
7307
  __ mov(Operand(esp, 2 * kPointerSize),
 
7308
         Immediate(ExternalReference::isolate_address()));
 
7309
 
 
7310
  AllowExternalCallThatCantCauseGC scope(masm);
 
7311
  if (mode == INCREMENTAL_COMPACTION) {
 
7312
    __ CallCFunction(
 
7313
        ExternalReference::incremental_evacuation_record_write_function(
 
7314
            masm->isolate()),
 
7315
        argument_count);
 
7316
  } else {
 
7317
    ASSERT(mode == INCREMENTAL);
 
7318
    __ CallCFunction(
 
7319
        ExternalReference::incremental_marking_record_write_function(
 
7320
            masm->isolate()),
 
7321
        argument_count);
 
7322
  }
 
7323
  regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
 
7324
}
 
7325
 
 
7326
 
 
7327
void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
 
7328
    MacroAssembler* masm,
 
7329
    OnNoNeedToInformIncrementalMarker on_no_need,
 
7330
    Mode mode) {
 
7331
  Label object_is_black, need_incremental, need_incremental_pop_object;
 
7332
 
 
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),
 
7341
         regs_.scratch1());
 
7342
  __ j(negative, &need_incremental);
 
7343
 
 
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(),
 
7347
                 regs_.scratch0(),
 
7348
                 regs_.scratch1(),
 
7349
                 &object_is_black,
 
7350
                 Label::kNear);
 
7351
 
 
7352
  regs_.Restore(masm);
 
7353
  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
 
7354
    __ RememberedSetHelper(object_,
 
7355
                           address_,
 
7356
                           value_,
 
7357
                           save_fp_regs_mode_,
 
7358
                           MacroAssembler::kReturnAtEnd);
 
7359
  } else {
 
7360
    __ ret(0);
 
7361
  }
 
7362
 
 
7363
  __ bind(&object_is_black);
 
7364
 
 
7365
  // Get the value from the slot.
 
7366
  __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
 
7367
 
 
7368
  if (mode == INCREMENTAL_COMPACTION) {
 
7369
    Label ensure_not_white;
 
7370
 
 
7371
    __ CheckPageFlag(regs_.scratch0(),  // Contains value.
 
7372
                     regs_.scratch1(),  // Scratch.
 
7373
                     MemoryChunk::kEvacuationCandidateMask,
 
7374
                     zero,
 
7375
                     &ensure_not_white,
 
7376
                     Label::kNear);
 
7377
 
 
7378
    __ CheckPageFlag(regs_.object(),
 
7379
                     regs_.scratch1(),  // Scratch.
 
7380
                     MemoryChunk::kSkipEvacuationSlotsRecordingMask,
 
7381
                     not_zero,
 
7382
                     &ensure_not_white,
 
7383
                     Label::kNear);
 
7384
 
 
7385
    __ jmp(&need_incremental);
 
7386
 
 
7387
    __ bind(&ensure_not_white);
 
7388
  }
 
7389
 
 
7390
  // We need an extra register for this, so we push the object register
 
7391
  // temporarily.
 
7392
  __ push(regs_.object());
 
7393
  __ EnsureNotWhite(regs_.scratch0(),  // The value.
 
7394
                    regs_.scratch1(),  // Scratch.
 
7395
                    regs_.object(),  // Scratch.
 
7396
                    &need_incremental_pop_object,
 
7397
                    Label::kNear);
 
7398
  __ pop(regs_.object());
 
7399
 
 
7400
  regs_.Restore(masm);
 
7401
  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
 
7402
    __ RememberedSetHelper(object_,
 
7403
                           address_,
 
7404
                           value_,
 
7405
                           save_fp_regs_mode_,
 
7406
                           MacroAssembler::kReturnAtEnd);
 
7407
  } else {
 
7408
    __ ret(0);
 
7409
  }
 
7410
 
 
7411
  __ bind(&need_incremental_pop_object);
 
7412
  __ pop(regs_.object());
 
7413
 
 
7414
  __ bind(&need_incremental);
 
7415
 
 
7416
  // Fall through when we need to inform the incremental marker.
 
7417
}
 
7418
 
 
7419
 
 
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
  // -----------------------------------
 
7429
 
 
7430
  Label element_done;
 
7431
  Label double_elements;
 
7432
  Label smi_element;
 
7433
  Label slow_elements;
 
7434
  Label slow_elements_from_double;
 
7435
  Label fast_elements;
 
7436
 
 
7437
  __ CheckFastElements(edi, &double_elements);
 
7438
 
 
7439
  // Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
 
7440
  __ JumpIfSmi(eax, &smi_element);
 
7441
  __ CheckFastSmiElements(edi, &fast_elements, Label::kNear);
 
7442
 
 
7443
  // Store into the array literal requires a elements transition. Call into
 
7444
  // the runtime.
 
7445
 
 
7446
  __ bind(&slow_elements);
 
7447
  __ pop(edi);  // Pop return address and remember to put back later for tail
 
7448
                // call.
 
7449
  __ push(ebx);
 
7450
  __ push(ecx);
 
7451
  __ push(eax);
 
7452
  __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
 
7453
  __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
 
7454
  __ push(edx);
 
7455
  __ push(edi);  // Return return address so that tail call returns to right
 
7456
                 // place.
 
7457
  __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
 
7458
 
 
7459
  __ bind(&slow_elements_from_double);
 
7460
  __ pop(edx);
 
7461
  __ jmp(&slow_elements);
 
7462
 
 
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,
 
7471
                 kDontSaveFPRegs,
 
7472
                 EMIT_REMEMBERED_SET,
 
7473
                 OMIT_SMI_CHECK);
 
7474
  __ ret(0);
 
7475
 
 
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);
 
7482
  __ ret(0);
 
7483
 
 
7484
  // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS.
 
7485
  __ bind(&double_elements);
 
7486
 
 
7487
  __ push(edx);
 
7488
  __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset));
 
7489
  __ StoreNumberToDoubleElements(eax,
 
7490
                                 edx,
 
7491
                                 ecx,
 
7492
                                 edi,
 
7493
                                 xmm0,
 
7494
                                 &slow_elements_from_double,
 
7495
                                 false);
 
7496
  __ pop(edx);
 
7497
  __ ret(0);
 
7498
}
 
7499
 
 
7500
 
 
7501
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
 
7502
  if (entry_hook_ != NULL) {
 
7503
    ProfileEntryHookStub stub;
 
7504
    masm->CallStub(&stub);
 
7505
  }
 
7506
}
 
7507
 
 
7508
 
 
7509
void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
 
7510
  // Ecx is the only volatile register we must save.
 
7511
  __ push(ecx);
 
7512
 
 
7513
  // Calculate and push the original stack pointer.
 
7514
  __ lea(eax, Operand(esp, kPointerSize));
 
7515
  __ push(eax);
 
7516
 
 
7517
  // Calculate and push the function address.
 
7518
  __ mov(eax, Operand(eax, 0));
 
7519
  __ sub(eax, Immediate(Assembler::kCallInstructionLength));
 
7520
  __ push(eax);
 
7521
 
 
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));
 
7526
 
 
7527
  // Restore ecx.
 
7528
  __ pop(ecx);
 
7529
  __ ret(0);
 
7530
}
 
7531
 
6529
7532
#undef __
6530
7533
 
6531
7534
} }  // namespace v8::internal