~james-page/ubuntu/precise/nodejs/test-timeout

« back to all changes in this revision

Viewing changes to deps/v8/src/x64/stub-cache-x64.cc

  • Committer: Bazaar Package Importer
  • Author(s): Fabrice Coutadeur
  • Date: 2011-06-30 07:03:44 UTC
  • mfrom: (7.1.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110630070344-5928xvhb3ddw5adb
Tags: 0.4.9-1ubuntu1
* Merge from Debian unstable (LP: #786428). Remaining changes:
  - debian/patches/2007_remove_internet_test.patch: Remove test which requires
    internet connection

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2010 the V8 project authors. All rights reserved.
 
1
// Copyright 2011 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:
25
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
27
 
28
 
 
29
28
#include "v8.h"
30
29
 
31
30
#if defined(V8_TARGET_ARCH_X64)
33
32
#include "ic-inl.h"
34
33
#include "codegen-inl.h"
35
34
#include "stub-cache.h"
36
 
#include "macro-assembler-x64.h"
37
35
 
38
36
namespace v8 {
39
37
namespace internal {
40
38
 
41
 
//-----------------------------------------------------------------------------
42
 
// StubCompiler static helper functions
43
 
 
44
39
#define __ ACCESS_MASM(masm)
45
40
 
46
41
 
181
176
}
182
177
 
183
178
 
184
 
void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
185
 
  ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
186
 
  Code* code = NULL;
187
 
  if (kind == Code::LOAD_IC) {
188
 
    code = Builtins::builtin(Builtins::LoadIC_Miss);
189
 
  } else {
190
 
    code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
191
 
  }
192
 
 
193
 
  Handle<Code> ic(code);
194
 
  __ Jump(ic, RelocInfo::CODE_TARGET);
195
 
}
196
 
 
197
 
 
198
 
void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
199
 
                                                       int index,
200
 
                                                       Register prototype) {
201
 
  // Load the global or builtins object from the current context.
202
 
  __ movq(prototype,
203
 
             Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
204
 
  // Load the global context from the global or builtins object.
205
 
  __ movq(prototype,
206
 
             FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
207
 
  // Load the function from the global context.
208
 
  __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
209
 
  // Load the initial map.  The global functions all have initial maps.
210
 
  __ movq(prototype,
211
 
             FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
212
 
  // Load the prototype from the initial map.
213
 
  __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
214
 
}
215
 
 
216
 
 
217
 
void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
218
 
    MacroAssembler* masm, int index, Register prototype) {
219
 
  // Get the global function with the given index.
220
 
  JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
221
 
  // Load its initial map. The global functions all have initial maps.
222
 
  __ Move(prototype, Handle<Map>(function->initial_map()));
223
 
  // Load the prototype from the initial map.
224
 
  __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
225
 
}
226
 
 
227
 
 
228
 
// Load a fast property out of a holder object (src). In-object properties
229
 
// are loaded directly otherwise the property is loaded from the properties
230
 
// fixed array.
231
 
void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
232
 
                                            Register dst, Register src,
233
 
                                            JSObject* holder, int index) {
234
 
  // Adjust for the number of properties stored in the holder.
235
 
  index -= holder->map()->inobject_properties();
236
 
  if (index < 0) {
237
 
    // Get the property straight out of the holder.
238
 
    int offset = holder->map()->instance_size() + (index * kPointerSize);
239
 
    __ movq(dst, FieldOperand(src, offset));
240
 
  } else {
241
 
    // Calculate the offset into the properties array.
242
 
    int offset = index * kPointerSize + FixedArray::kHeaderSize;
243
 
    __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
244
 
    __ movq(dst, FieldOperand(dst, offset));
245
 
  }
246
 
}
247
 
 
248
 
 
249
 
static void PushInterceptorArguments(MacroAssembler* masm,
250
 
                                     Register receiver,
251
 
                                     Register holder,
252
 
                                     Register name,
253
 
                                     JSObject* holder_obj) {
254
 
  __ push(name);
255
 
  InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
256
 
  ASSERT(!Heap::InNewSpace(interceptor));
257
 
  __ Move(kScratchRegister, Handle<Object>(interceptor));
258
 
  __ push(kScratchRegister);
259
 
  __ push(receiver);
260
 
  __ push(holder);
261
 
  __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
262
 
}
263
 
 
264
 
 
265
179
void StubCache::GenerateProbe(MacroAssembler* masm,
266
180
                              Code::Flags flags,
267
181
                              Register receiver,
268
182
                              Register name,
269
183
                              Register scratch,
270
 
                              Register extra) {
 
184
                              Register extra,
 
185
                              Register extra2) {
271
186
  Label miss;
272
 
  USE(extra);  // The register extra is not used on the X64 platform.
 
187
  USE(extra);   // The register extra is not used on the X64 platform.
 
188
  USE(extra2);  // The register extra2 is not used on the X64 platform.
273
189
  // Make sure that code is valid. The shifting code relies on the
274
190
  // entry size being 16.
275
191
  ASSERT(sizeof(Entry) == 16);
281
197
  ASSERT(!scratch.is(receiver));
282
198
  ASSERT(!scratch.is(name));
283
199
 
 
200
  // Check scratch register is valid, extra and extra2 are unused.
 
201
  ASSERT(!scratch.is(no_reg));
 
202
  ASSERT(extra2.is(no_reg));
 
203
 
284
204
  // Check that the receiver isn't a smi.
285
205
  __ JumpIfSmi(receiver, &miss);
286
206
 
312
232
}
313
233
 
314
234
 
315
 
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
316
 
// but may be destroyed if store is successful.
317
 
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
318
 
                                      JSObject* object,
319
 
                                      int index,
320
 
                                      Map* transition,
321
 
                                      Register receiver_reg,
322
 
                                      Register name_reg,
323
 
                                      Register scratch,
324
 
                                      Label* miss_label) {
325
 
  // Check that the object isn't a smi.
326
 
  __ JumpIfSmi(receiver_reg, miss_label);
327
 
 
328
 
  // Check that the map of the object hasn't changed.
329
 
  __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
330
 
         Handle<Map>(object->map()));
331
 
  __ j(not_equal, miss_label);
332
 
 
333
 
  // Perform global security token check if needed.
334
 
  if (object->IsJSGlobalProxy()) {
335
 
    __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
336
 
  }
337
 
 
338
 
  // Stub never generated for non-global objects that require access
339
 
  // checks.
340
 
  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
341
 
 
342
 
  // Perform map transition for the receiver if necessary.
343
 
  if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
344
 
    // The properties must be extended before we can store the value.
345
 
    // We jump to a runtime call that extends the properties array.
346
 
    __ pop(scratch);  // Return address.
347
 
    __ push(receiver_reg);
348
 
    __ Push(Handle<Map>(transition));
349
 
    __ push(rax);
350
 
    __ push(scratch);
351
 
    __ TailCallExternalReference(
352
 
        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
353
 
    return;
354
 
  }
355
 
 
356
 
  if (transition != NULL) {
357
 
    // Update the map of the object; no write barrier updating is
358
 
    // needed because the map is never in new space.
359
 
    __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
360
 
            Handle<Map>(transition));
361
 
  }
362
 
 
363
 
  // Adjust for the number of properties stored in the object. Even in the
364
 
  // face of a transition we can use the old map here because the size of the
365
 
  // object and the number of in-object properties is not going to change.
366
 
  index -= object->map()->inobject_properties();
367
 
 
368
 
  if (index < 0) {
369
 
    // Set the property straight into the object.
370
 
    int offset = object->map()->instance_size() + (index * kPointerSize);
371
 
    __ movq(FieldOperand(receiver_reg, offset), rax);
372
 
 
373
 
    // Update the write barrier for the array address.
374
 
    // Pass the value being stored in the now unused name_reg.
375
 
    __ movq(name_reg, rax);
376
 
    __ RecordWrite(receiver_reg, offset, name_reg, scratch);
377
 
  } else {
378
 
    // Write to the properties array.
379
 
    int offset = index * kPointerSize + FixedArray::kHeaderSize;
380
 
    // Get the properties array (optimistically).
381
 
    __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
382
 
    __ movq(FieldOperand(scratch, offset), rax);
383
 
 
384
 
    // Update the write barrier for the array address.
385
 
    // Pass the value being stored in the now unused name_reg.
386
 
    __ movq(name_reg, rax);
387
 
    __ RecordWrite(scratch, offset, name_reg, receiver_reg);
388
 
  }
389
 
 
390
 
  // Return the value (register rax).
391
 
  __ ret(0);
 
235
void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
 
236
                                                       int index,
 
237
                                                       Register prototype) {
 
238
  // Load the global or builtins object from the current context.
 
239
  __ movq(prototype,
 
240
             Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
 
241
  // Load the global context from the global or builtins object.
 
242
  __ movq(prototype,
 
243
             FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
 
244
  // Load the function from the global context.
 
245
  __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
 
246
  // Load the initial map.  The global functions all have initial maps.
 
247
  __ movq(prototype,
 
248
             FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
 
249
  // Load the prototype from the initial map.
 
250
  __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
 
251
}
 
252
 
 
253
 
 
254
void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
 
255
    MacroAssembler* masm, int index, Register prototype, Label* miss) {
 
256
  // Check we're still in the same context.
 
257
  __ Move(prototype, Top::global());
 
258
  __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)),
 
259
          prototype);
 
260
  __ j(not_equal, miss);
 
261
  // Get the global function with the given index.
 
262
  JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
 
263
  // Load its initial map. The global functions all have initial maps.
 
264
  __ Move(prototype, Handle<Map>(function->initial_map()));
 
265
  // Load the prototype from the initial map.
 
266
  __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
392
267
}
393
268
 
394
269
 
432
307
                                            Register receiver,
433
308
                                            Register scratch1,
434
309
                                            Register scratch2,
435
 
                                            Label* miss) {
 
310
                                            Label* miss,
 
311
                                            bool support_wrappers) {
436
312
  Label check_wrapper;
437
313
 
438
314
  // Check if the object is a string leaving the instance type in the
439
315
  // scratch register.
440
 
  GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
 
316
  GenerateStringCheck(masm, receiver, scratch1, miss,
 
317
                      support_wrappers ? &check_wrapper : miss);
441
318
 
442
319
  // Load length directly from the string.
443
320
  __ movq(rax, FieldOperand(receiver, String::kLengthOffset));
444
321
  __ ret(0);
445
322
 
446
 
  // Check if the object is a JSValue wrapper.
447
 
  __ bind(&check_wrapper);
448
 
  __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
449
 
  __ j(not_equal, miss);
450
 
 
451
 
  // Check if the wrapped value is a string and load the length
452
 
  // directly if it is.
453
 
  __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
454
 
  GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
455
 
  __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
 
323
  if (support_wrappers) {
 
324
    // Check if the object is a JSValue wrapper.
 
325
    __ bind(&check_wrapper);
 
326
    __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
 
327
    __ j(not_equal, miss);
 
328
 
 
329
    // Check if the wrapped value is a string and load the length
 
330
    // directly if it is.
 
331
    __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
 
332
    GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
 
333
    __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
 
334
    __ ret(0);
 
335
  }
 
336
}
 
337
 
 
338
 
 
339
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
 
340
                                                 Register receiver,
 
341
                                                 Register result,
 
342
                                                 Register scratch,
 
343
                                                 Label* miss_label) {
 
344
  __ TryGetFunctionPrototype(receiver, result, miss_label);
 
345
  if (!result.is(rax)) __ movq(rax, result);
456
346
  __ ret(0);
457
347
}
458
348
 
459
349
 
 
350
// Load a fast property out of a holder object (src). In-object properties
 
351
// are loaded directly otherwise the property is loaded from the properties
 
352
// fixed array.
 
353
void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
 
354
                                            Register dst, Register src,
 
355
                                            JSObject* holder, int index) {
 
356
  // Adjust for the number of properties stored in the holder.
 
357
  index -= holder->map()->inobject_properties();
 
358
  if (index < 0) {
 
359
    // Get the property straight out of the holder.
 
360
    int offset = holder->map()->instance_size() + (index * kPointerSize);
 
361
    __ movq(dst, FieldOperand(src, offset));
 
362
  } else {
 
363
    // Calculate the offset into the properties array.
 
364
    int offset = index * kPointerSize + FixedArray::kHeaderSize;
 
365
    __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
 
366
    __ movq(dst, FieldOperand(dst, offset));
 
367
  }
 
368
}
 
369
 
 
370
 
 
371
static void PushInterceptorArguments(MacroAssembler* masm,
 
372
                                     Register receiver,
 
373
                                     Register holder,
 
374
                                     Register name,
 
375
                                     JSObject* holder_obj) {
 
376
  __ push(name);
 
377
  InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
 
378
  ASSERT(!Heap::InNewSpace(interceptor));
 
379
  __ Move(kScratchRegister, Handle<Object>(interceptor));
 
380
  __ push(kScratchRegister);
 
381
  __ push(receiver);
 
382
  __ push(holder);
 
383
  __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
 
384
}
 
385
 
 
386
 
460
387
static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
461
388
                                                   Register receiver,
462
389
                                                   Register holder,
474
401
}
475
402
 
476
403
 
477
 
 
478
 
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
479
 
                                                 Register receiver,
480
 
                                                 Register result,
481
 
                                                 Register scratch,
482
 
                                                 Label* miss_label) {
483
 
  __ TryGetFunctionPrototype(receiver, result, miss_label);
484
 
  if (!result.is(rax)) __ movq(rax, result);
485
 
  __ ret(0);
486
 
}
487
 
 
488
 
 
489
 
// Reserves space for the extra arguments to FastHandleApiCall in the
 
404
// Number of pointers to be reserved on stack for fast API call.
 
405
static const int kFastApiCallArguments = 3;
 
406
 
 
407
 
 
408
// Reserves space for the extra arguments to API function in the
490
409
// caller's frame.
491
410
//
492
411
// These arguments are set by CheckPrototypes and GenerateFastApiCall.
496
415
  //  -- rsp[8] : last argument in the internal frame of the caller
497
416
  // -----------------------------------
498
417
  __ movq(scratch, Operand(rsp, 0));
499
 
  __ subq(rsp, Immediate(4 * kPointerSize));
 
418
  __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
500
419
  __ movq(Operand(rsp, 0), scratch);
501
420
  __ Move(scratch, Smi::FromInt(0));
502
 
  __ movq(Operand(rsp, 1 * kPointerSize), scratch);
503
 
  __ movq(Operand(rsp, 2 * kPointerSize), scratch);
504
 
  __ movq(Operand(rsp, 3 * kPointerSize), scratch);
505
 
  __ movq(Operand(rsp, 4 * kPointerSize), scratch);
 
421
  for (int i = 1; i <= kFastApiCallArguments; i++) {
 
422
     __ movq(Operand(rsp, i * kPointerSize), scratch);
 
423
  }
506
424
}
507
425
 
508
426
 
509
427
// Undoes the effects of ReserveSpaceForFastApiCall.
510
428
static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
511
429
  // ----------- S t a t e -------------
512
 
  //  -- rsp[0]  : return address
513
 
  //  -- rsp[8]  : last fast api call extra argument
 
430
  //  -- rsp[0]  : return address.
 
431
  //  -- rsp[8]  : last fast api call extra argument.
514
432
  //  -- ...
515
 
  //  -- rsp[32] : first fast api call extra argument
516
 
  //  -- rsp[40] : last argument in the internal frame
 
433
  //  -- rsp[kFastApiCallArguments * 8] : first fast api call extra argument.
 
434
  //  -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
 
435
  //                                          frame.
517
436
  // -----------------------------------
518
437
  __ movq(scratch, Operand(rsp, 0));
519
 
  __ movq(Operand(rsp, 4 * kPointerSize), scratch);
520
 
  __ addq(rsp, Immediate(kPointerSize * 4));
 
438
  __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch);
 
439
  __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
521
440
}
522
441
 
523
442
 
524
 
// Generates call to FastHandleApiCall builtin.
525
 
static void GenerateFastApiCall(MacroAssembler* masm,
526
 
                                const CallOptimization& optimization,
527
 
                                int argc) {
 
443
// Generates call to API function.
 
444
static MaybeObject* GenerateFastApiCall(MacroAssembler* masm,
 
445
                                        const CallOptimization& optimization,
 
446
                                        int argc) {
528
447
  // ----------- S t a t e -------------
529
448
  //  -- rsp[0]              : return address
530
449
  //  -- rsp[8]              : object passing the type check
531
450
  //                           (last fast api call extra argument,
532
451
  //                            set by CheckPrototypes)
533
 
  //  -- rsp[16]             : api call data
534
 
  //  -- rsp[24]             : api callback
535
 
  //  -- rsp[32]             : api function
 
452
  //  -- rsp[16]             : api function
536
453
  //                           (first fast api call extra argument)
537
 
  //  -- rsp[40]             : last argument
 
454
  //  -- rsp[24]             : api call data
 
455
  //  -- rsp[32]             : last argument
538
456
  //  -- ...
539
 
  //  -- rsp[(argc + 5) * 8] : first argument
540
 
  //  -- rsp[(argc + 6) * 8] : receiver
 
457
  //  -- rsp[(argc + 3) * 8] : first argument
 
458
  //  -- rsp[(argc + 4) * 8] : receiver
541
459
  // -----------------------------------
542
 
 
543
460
  // Get the function and setup the context.
544
461
  JSFunction* function = optimization.constant_function();
545
462
  __ Move(rdi, Handle<JSFunction>(function));
546
463
  __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
547
464
 
548
 
  // Pass the additional arguments FastHandleApiCall expects.
549
 
  __ movq(Operand(rsp, 4 * kPointerSize), rdi);
550
 
  bool info_loaded = false;
551
 
  Object* callback = optimization.api_call_info()->callback();
552
 
  if (Heap::InNewSpace(callback)) {
553
 
    info_loaded = true;
554
 
    __ Move(rcx, Handle<CallHandlerInfo>(optimization.api_call_info()));
555
 
    __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kCallbackOffset));
556
 
    __ movq(Operand(rsp, 3 * kPointerSize), rbx);
557
 
  } else {
558
 
    __ Move(Operand(rsp, 3 * kPointerSize), Handle<Object>(callback));
559
 
  }
 
465
  // Pass the additional arguments.
 
466
  __ movq(Operand(rsp, 2 * kPointerSize), rdi);
560
467
  Object* call_data = optimization.api_call_info()->data();
 
468
  Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
561
469
  if (Heap::InNewSpace(call_data)) {
562
 
    if (!info_loaded) {
563
 
      __ Move(rcx, Handle<CallHandlerInfo>(optimization.api_call_info()));
564
 
    }
 
470
    __ Move(rcx, api_call_info_handle);
565
471
    __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
566
 
    __ movq(Operand(rsp, 2 * kPointerSize), rbx);
 
472
    __ movq(Operand(rsp, 3 * kPointerSize), rbx);
567
473
  } else {
568
 
    __ Move(Operand(rsp, 2 * kPointerSize), Handle<Object>(call_data));
 
474
    __ Move(Operand(rsp, 3 * kPointerSize), Handle<Object>(call_data));
569
475
  }
570
476
 
571
 
  // Set the number of arguments.
572
 
  __ movq(rax, Immediate(argc + 4));
573
 
 
574
 
  // Jump to the fast api call builtin (tail call).
575
 
  Handle<Code> code = Handle<Code>(
576
 
      Builtins::builtin(Builtins::FastHandleApiCall));
577
 
  ParameterCount expected(0);
578
 
  __ InvokeCode(code, expected, expected,
579
 
                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
 
477
  // Prepare arguments.
 
478
  __ lea(rbx, Operand(rsp, 3 * kPointerSize));
 
479
 
 
480
  Object* callback = optimization.api_call_info()->callback();
 
481
  Address api_function_address = v8::ToCData<Address>(callback);
 
482
  ApiFunction fun(api_function_address);
 
483
 
 
484
#ifdef _WIN64
 
485
  // Win64 uses first register--rcx--for returned value.
 
486
  Register arguments_arg = rdx;
 
487
#else
 
488
  Register arguments_arg = rdi;
 
489
#endif
 
490
 
 
491
  // Allocate the v8::Arguments structure in the arguments' space since
 
492
  // it's not controlled by GC.
 
493
  const int kApiStackSpace = 4;
 
494
 
 
495
  __ PrepareCallApiFunction(kApiStackSpace);
 
496
 
 
497
  __ movq(StackSpaceOperand(0), rbx);  // v8::Arguments::implicit_args_.
 
498
  __ addq(rbx, Immediate(argc * kPointerSize));
 
499
  __ movq(StackSpaceOperand(1), rbx);  // v8::Arguments::values_.
 
500
  __ Set(StackSpaceOperand(2), argc);  // v8::Arguments::length_.
 
501
  // v8::Arguments::is_construct_call_.
 
502
  __ Set(StackSpaceOperand(3), 0);
 
503
 
 
504
  // v8::InvocationCallback's argument.
 
505
  __ lea(arguments_arg, StackSpaceOperand(0));
 
506
  // Emitting a stub call may try to allocate (if the code is not
 
507
  // already generated).  Do not allow the assembler to perform a
 
508
  // garbage collection but instead return the allocation failure
 
509
  // object.
 
510
  return masm->TryCallApiFunctionAndReturn(&fun,
 
511
                                           argc + kFastApiCallArguments + 1);
580
512
}
581
513
 
582
514
 
589
521
        arguments_(arguments),
590
522
        name_(name) {}
591
523
 
592
 
  void Compile(MacroAssembler* masm,
593
 
               JSObject* object,
594
 
               JSObject* holder,
595
 
               String* name,
596
 
               LookupResult* lookup,
597
 
               Register receiver,
598
 
               Register scratch1,
599
 
               Register scratch2,
600
 
               Register scratch3,
601
 
               Label* miss) {
 
524
  MaybeObject* Compile(MacroAssembler* masm,
 
525
                       JSObject* object,
 
526
                       JSObject* holder,
 
527
                       String* name,
 
528
                       LookupResult* lookup,
 
529
                       Register receiver,
 
530
                       Register scratch1,
 
531
                       Register scratch2,
 
532
                       Register scratch3,
 
533
                       Label* miss) {
602
534
    ASSERT(holder->HasNamedInterceptor());
603
535
    ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
604
536
 
608
540
    CallOptimization optimization(lookup);
609
541
 
610
542
    if (optimization.is_constant_call()) {
611
 
      CompileCacheable(masm,
612
 
                       object,
613
 
                       receiver,
614
 
                       scratch1,
615
 
                       scratch2,
616
 
                       scratch3,
617
 
                       holder,
618
 
                       lookup,
619
 
                       name,
620
 
                       optimization,
621
 
                       miss);
 
543
      return CompileCacheable(masm,
 
544
                              object,
 
545
                              receiver,
 
546
                              scratch1,
 
547
                              scratch2,
 
548
                              scratch3,
 
549
                              holder,
 
550
                              lookup,
 
551
                              name,
 
552
                              optimization,
 
553
                              miss);
622
554
    } else {
623
555
      CompileRegular(masm,
624
556
                     object,
629
561
                     name,
630
562
                     holder,
631
563
                     miss);
 
564
      return Heap::undefined_value();  // Success.
632
565
    }
633
566
  }
634
567
 
635
568
 private:
636
 
  void CompileCacheable(MacroAssembler* masm,
637
 
                        JSObject* object,
638
 
                        Register receiver,
639
 
                        Register scratch1,
640
 
                        Register scratch2,
641
 
                        Register scratch3,
642
 
                        JSObject* interceptor_holder,
643
 
                        LookupResult* lookup,
644
 
                        String* name,
645
 
                        const CallOptimization& optimization,
646
 
                        Label* miss_label) {
 
569
  MaybeObject* CompileCacheable(MacroAssembler* masm,
 
570
                                JSObject* object,
 
571
                                Register receiver,
 
572
                                Register scratch1,
 
573
                                Register scratch2,
 
574
                                Register scratch3,
 
575
                                JSObject* interceptor_holder,
 
576
                                LookupResult* lookup,
 
577
                                String* name,
 
578
                                const CallOptimization& optimization,
 
579
                                Label* miss_label) {
647
580
    ASSERT(optimization.is_constant_call());
648
581
    ASSERT(!lookup->holder()->IsGlobalObject());
649
582
 
705
638
 
706
639
    // Invoke function.
707
640
    if (can_do_fast_api_call) {
708
 
      GenerateFastApiCall(masm, optimization, arguments_.immediate());
 
641
      MaybeObject* result = GenerateFastApiCall(masm,
 
642
                                                optimization,
 
643
                                                arguments_.immediate());
 
644
      if (result->IsFailure()) return result;
709
645
    } else {
710
646
      __ InvokeFunction(optimization.constant_function(), arguments_,
711
647
                        JUMP_FUNCTION);
723
659
    if (can_do_fast_api_call) {
724
660
      FreeSpaceForFastApiCall(masm, scratch1);
725
661
    }
 
662
 
 
663
    return Heap::undefined_value();  // Success.
726
664
  }
727
665
 
728
666
  void CompileRegular(MacroAssembler* masm,
787
725
};
788
726
 
789
727
 
 
728
void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
 
729
  ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
 
730
  Code* code = NULL;
 
731
  if (kind == Code::LOAD_IC) {
 
732
    code = Builtins::builtin(Builtins::LoadIC_Miss);
 
733
  } else {
 
734
    code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
 
735
  }
 
736
 
 
737
  Handle<Code> ic(code);
 
738
  __ Jump(ic, RelocInfo::CODE_TARGET);
 
739
}
 
740
 
 
741
 
 
742
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
 
743
// but may be destroyed if store is successful.
 
744
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
 
745
                                      JSObject* object,
 
746
                                      int index,
 
747
                                      Map* transition,
 
748
                                      Register receiver_reg,
 
749
                                      Register name_reg,
 
750
                                      Register scratch,
 
751
                                      Label* miss_label) {
 
752
  // Check that the object isn't a smi.
 
753
  __ JumpIfSmi(receiver_reg, miss_label);
 
754
 
 
755
  // Check that the map of the object hasn't changed.
 
756
  __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
 
757
         Handle<Map>(object->map()));
 
758
  __ j(not_equal, miss_label);
 
759
 
 
760
  // Perform global security token check if needed.
 
761
  if (object->IsJSGlobalProxy()) {
 
762
    __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
 
763
  }
 
764
 
 
765
  // Stub never generated for non-global objects that require access
 
766
  // checks.
 
767
  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
768
 
 
769
  // Perform map transition for the receiver if necessary.
 
770
  if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
 
771
    // The properties must be extended before we can store the value.
 
772
    // We jump to a runtime call that extends the properties array.
 
773
    __ pop(scratch);  // Return address.
 
774
    __ push(receiver_reg);
 
775
    __ Push(Handle<Map>(transition));
 
776
    __ push(rax);
 
777
    __ push(scratch);
 
778
    __ TailCallExternalReference(
 
779
        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
 
780
    return;
 
781
  }
 
782
 
 
783
  if (transition != NULL) {
 
784
    // Update the map of the object; no write barrier updating is
 
785
    // needed because the map is never in new space.
 
786
    __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
 
787
            Handle<Map>(transition));
 
788
  }
 
789
 
 
790
  // Adjust for the number of properties stored in the object. Even in the
 
791
  // face of a transition we can use the old map here because the size of the
 
792
  // object and the number of in-object properties is not going to change.
 
793
  index -= object->map()->inobject_properties();
 
794
 
 
795
  if (index < 0) {
 
796
    // Set the property straight into the object.
 
797
    int offset = object->map()->instance_size() + (index * kPointerSize);
 
798
    __ movq(FieldOperand(receiver_reg, offset), rax);
 
799
 
 
800
    // Update the write barrier for the array address.
 
801
    // Pass the value being stored in the now unused name_reg.
 
802
    __ movq(name_reg, rax);
 
803
    __ RecordWrite(receiver_reg, offset, name_reg, scratch);
 
804
  } else {
 
805
    // Write to the properties array.
 
806
    int offset = index * kPointerSize + FixedArray::kHeaderSize;
 
807
    // Get the properties array (optimistically).
 
808
    __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
 
809
    __ movq(FieldOperand(scratch, offset), rax);
 
810
 
 
811
    // Update the write barrier for the array address.
 
812
    // Pass the value being stored in the now unused name_reg.
 
813
    __ movq(name_reg, rax);
 
814
    __ RecordWrite(scratch, offset, name_reg, receiver_reg);
 
815
  }
 
816
 
 
817
  // Return the value (register rax).
 
818
  __ ret(0);
 
819
}
 
820
 
 
821
 
790
822
// Generate code to check that a global property cell is empty. Create
791
823
// the property cell at compilation time if no cell exists for the
792
824
// property.
793
 
static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
794
 
                                         GlobalObject* global,
795
 
                                         String* name,
796
 
                                         Register scratch,
797
 
                                         Label* miss) {
798
 
  Object* probe = global->EnsurePropertyCell(name);
799
 
  if (probe->IsFailure()) return probe;
 
825
MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
 
826
    MacroAssembler* masm,
 
827
    GlobalObject* global,
 
828
    String* name,
 
829
    Register scratch,
 
830
    Label* miss) {
 
831
  Object* probe;
 
832
  { MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
 
833
    if (!maybe_probe->ToObject(&probe)) return maybe_probe;
 
834
  }
800
835
  JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
801
836
  ASSERT(cell->value()->IsTheHole());
802
837
  __ Move(scratch, Handle<Object>(cell));
808
843
 
809
844
 
810
845
#undef __
811
 
 
812
846
#define __ ACCESS_MASM((masm()))
813
847
 
814
848
 
 
849
Register StubCompiler::CheckPrototypes(JSObject* object,
 
850
                                       Register object_reg,
 
851
                                       JSObject* holder,
 
852
                                       Register holder_reg,
 
853
                                       Register scratch1,
 
854
                                       Register scratch2,
 
855
                                       String* name,
 
856
                                       int save_at_depth,
 
857
                                       Label* miss) {
 
858
  // Make sure there's no overlap between holder and object registers.
 
859
  ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
 
860
  ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
 
861
         && !scratch2.is(scratch1));
 
862
 
 
863
  // Keep track of the current object in register reg.  On the first
 
864
  // iteration, reg is an alias for object_reg, on later iterations,
 
865
  // it is an alias for holder_reg.
 
866
  Register reg = object_reg;
 
867
  int depth = 0;
 
868
 
 
869
  if (save_at_depth == depth) {
 
870
    __ movq(Operand(rsp, kPointerSize), object_reg);
 
871
  }
 
872
 
 
873
  // Check the maps in the prototype chain.
 
874
  // Traverse the prototype chain from the object and do map checks.
 
875
  JSObject* current = object;
 
876
  while (current != holder) {
 
877
    depth++;
 
878
 
 
879
    // Only global objects and objects that do not require access
 
880
    // checks are allowed in stubs.
 
881
    ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
 
882
 
 
883
    JSObject* prototype = JSObject::cast(current->GetPrototype());
 
884
    if (!current->HasFastProperties() &&
 
885
        !current->IsJSGlobalObject() &&
 
886
        !current->IsJSGlobalProxy()) {
 
887
      if (!name->IsSymbol()) {
 
888
        MaybeObject* lookup_result = Heap::LookupSymbol(name);
 
889
        if (lookup_result->IsFailure()) {
 
890
          set_failure(Failure::cast(lookup_result));
 
891
          return reg;
 
892
        } else {
 
893
          name = String::cast(lookup_result->ToObjectUnchecked());
 
894
        }
 
895
      }
 
896
      ASSERT(current->property_dictionary()->FindEntry(name) ==
 
897
             StringDictionary::kNotFound);
 
898
 
 
899
      GenerateDictionaryNegativeLookup(masm(),
 
900
                                       miss,
 
901
                                       reg,
 
902
                                       name,
 
903
                                       scratch1,
 
904
                                       scratch2);
 
905
      __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
 
906
      reg = holder_reg;  // from now the object is in holder_reg
 
907
      __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
 
908
    } else if (Heap::InNewSpace(prototype)) {
 
909
      // Get the map of the current object.
 
910
      __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
 
911
      __ Cmp(scratch1, Handle<Map>(current->map()));
 
912
      // Branch on the result of the map check.
 
913
      __ j(not_equal, miss);
 
914
      // Check access rights to the global object.  This has to happen
 
915
      // after the map check so that we know that the object is
 
916
      // actually a global object.
 
917
      if (current->IsJSGlobalProxy()) {
 
918
        __ CheckAccessGlobalProxy(reg, scratch1, miss);
 
919
 
 
920
        // Restore scratch register to be the map of the object.
 
921
        // We load the prototype from the map in the scratch register.
 
922
        __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
 
923
      }
 
924
      // The prototype is in new space; we cannot store a reference
 
925
      // to it in the code. Load it from the map.
 
926
      reg = holder_reg;  // from now the object is in holder_reg
 
927
      __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
 
928
 
 
929
    } else {
 
930
      // Check the map of the current object.
 
931
      __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
 
932
          Handle<Map>(current->map()));
 
933
      // Branch on the result of the map check.
 
934
      __ j(not_equal, miss);
 
935
      // Check access rights to the global object.  This has to happen
 
936
      // after the map check so that we know that the object is
 
937
      // actually a global object.
 
938
      if (current->IsJSGlobalProxy()) {
 
939
        __ CheckAccessGlobalProxy(reg, scratch1, miss);
 
940
      }
 
941
      // The prototype is in old space; load it directly.
 
942
      reg = holder_reg;  // from now the object is in holder_reg
 
943
      __ Move(reg, Handle<JSObject>(prototype));
 
944
    }
 
945
 
 
946
    if (save_at_depth == depth) {
 
947
      __ movq(Operand(rsp, kPointerSize), reg);
 
948
    }
 
949
 
 
950
    // Go to the next object in the prototype chain.
 
951
    current = prototype;
 
952
  }
 
953
 
 
954
  // Check the holder map.
 
955
  __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
 
956
  __ j(not_equal, miss);
 
957
 
 
958
  // Log the check depth.
 
959
  LOG(IntEvent("check-maps-depth", depth + 1));
 
960
 
 
961
  // Perform security check for access to the global object and return
 
962
  // the holder register.
 
963
  ASSERT(current == holder);
 
964
  ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
 
965
  if (current->IsJSGlobalProxy()) {
 
966
    __ CheckAccessGlobalProxy(reg, scratch1, miss);
 
967
  }
 
968
 
 
969
  // If we've skipped any global objects, it's not enough to verify
 
970
  // that their maps haven't changed.  We also need to check that the
 
971
  // property cell for the property is still empty.
 
972
  current = object;
 
973
  while (current != holder) {
 
974
    if (current->IsGlobalObject()) {
 
975
      MaybeObject* cell = GenerateCheckPropertyCell(masm(),
 
976
                                                    GlobalObject::cast(current),
 
977
                                                    name,
 
978
                                                    scratch1,
 
979
                                                    miss);
 
980
      if (cell->IsFailure()) {
 
981
        set_failure(Failure::cast(cell));
 
982
        return reg;
 
983
      }
 
984
    }
 
985
    current = JSObject::cast(current->GetPrototype());
 
986
  }
 
987
 
 
988
  // Return the register containing the holder.
 
989
  return reg;
 
990
}
 
991
 
 
992
 
 
993
void StubCompiler::GenerateLoadField(JSObject* object,
 
994
                                     JSObject* holder,
 
995
                                     Register receiver,
 
996
                                     Register scratch1,
 
997
                                     Register scratch2,
 
998
                                     Register scratch3,
 
999
                                     int index,
 
1000
                                     String* name,
 
1001
                                     Label* miss) {
 
1002
  // Check that the receiver isn't a smi.
 
1003
  __ JumpIfSmi(receiver, miss);
 
1004
 
 
1005
  // Check the prototype chain.
 
1006
  Register reg =
 
1007
      CheckPrototypes(object, receiver, holder,
 
1008
                      scratch1, scratch2, scratch3, name, miss);
 
1009
 
 
1010
  // Get the value from the properties.
 
1011
  GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
 
1012
  __ ret(0);
 
1013
}
 
1014
 
 
1015
 
 
1016
MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
 
1017
                                                JSObject* holder,
 
1018
                                                Register receiver,
 
1019
                                                Register name_reg,
 
1020
                                                Register scratch1,
 
1021
                                                Register scratch2,
 
1022
                                                Register scratch3,
 
1023
                                                AccessorInfo* callback,
 
1024
                                                String* name,
 
1025
                                                Label* miss) {
 
1026
  // Check that the receiver isn't a smi.
 
1027
  __ JumpIfSmi(receiver, miss);
 
1028
 
 
1029
  // Check that the maps haven't changed.
 
1030
  Register reg =
 
1031
      CheckPrototypes(object, receiver, holder, scratch1,
 
1032
                      scratch2, scratch3, name, miss);
 
1033
 
 
1034
  Handle<AccessorInfo> callback_handle(callback);
 
1035
 
 
1036
  // Insert additional parameters into the stack frame above return address.
 
1037
  ASSERT(!scratch2.is(reg));
 
1038
  __ pop(scratch2);  // Get return address to place it below.
 
1039
 
 
1040
  __ push(receiver);  // receiver
 
1041
  __ push(reg);  // holder
 
1042
  if (Heap::InNewSpace(callback_handle->data())) {
 
1043
    __ Move(scratch1, callback_handle);
 
1044
    __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));  // data
 
1045
  } else {
 
1046
    __ Push(Handle<Object>(callback_handle->data()));
 
1047
  }
 
1048
  __ push(name_reg);  // name
 
1049
  // Save a pointer to where we pushed the arguments pointer.
 
1050
  // This will be passed as the const AccessorInfo& to the C++ callback.
 
1051
 
 
1052
#ifdef _WIN64
 
1053
  // Win64 uses first register--rcx--for returned value.
 
1054
  Register accessor_info_arg = r8;
 
1055
  Register name_arg = rdx;
 
1056
#else
 
1057
  Register accessor_info_arg = rsi;
 
1058
  Register name_arg = rdi;
 
1059
#endif
 
1060
 
 
1061
  ASSERT(!name_arg.is(scratch2));
 
1062
  __ movq(name_arg, rsp);
 
1063
  __ push(scratch2);  // Restore return address.
 
1064
 
 
1065
  // Do call through the api.
 
1066
  Address getter_address = v8::ToCData<Address>(callback->getter());
 
1067
  ApiFunction fun(getter_address);
 
1068
 
 
1069
  // 3 elements array for v8::Agruments::values_ and handler for name.
 
1070
  const int kStackSpace = 4;
 
1071
 
 
1072
  // Allocate v8::AccessorInfo in non-GCed stack space.
 
1073
  const int kArgStackSpace = 1;
 
1074
 
 
1075
  __ PrepareCallApiFunction(kArgStackSpace);
 
1076
  __ lea(rax, Operand(name_arg, 3 * kPointerSize));
 
1077
 
 
1078
  // v8::AccessorInfo::args_.
 
1079
  __ movq(StackSpaceOperand(0), rax);
 
1080
 
 
1081
  // The context register (rsi) has been saved in PrepareCallApiFunction and
 
1082
  // could be used to pass arguments.
 
1083
  __ lea(accessor_info_arg, StackSpaceOperand(0));
 
1084
 
 
1085
  // Emitting a stub call may try to allocate (if the code is not
 
1086
  // already generated).  Do not allow the assembler to perform a
 
1087
  // garbage collection but instead return the allocation failure
 
1088
  // object.
 
1089
  return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
 
1090
}
 
1091
 
 
1092
 
 
1093
void StubCompiler::GenerateLoadConstant(JSObject* object,
 
1094
                                        JSObject* holder,
 
1095
                                        Register receiver,
 
1096
                                        Register scratch1,
 
1097
                                        Register scratch2,
 
1098
                                        Register scratch3,
 
1099
                                        Object* value,
 
1100
                                        String* name,
 
1101
                                        Label* miss) {
 
1102
  // Check that the receiver isn't a smi.
 
1103
  __ JumpIfSmi(receiver, miss);
 
1104
 
 
1105
  // Check that the maps haven't changed.
 
1106
  Register reg =
 
1107
      CheckPrototypes(object, receiver, holder,
 
1108
                      scratch1, scratch2, scratch3, name, miss);
 
1109
 
 
1110
  // Return the constant value.
 
1111
  __ Move(rax, Handle<Object>(value));
 
1112
  __ ret(0);
 
1113
}
 
1114
 
 
1115
 
 
1116
void StubCompiler::GenerateLoadInterceptor(JSObject* object,
 
1117
                                           JSObject* interceptor_holder,
 
1118
                                           LookupResult* lookup,
 
1119
                                           Register receiver,
 
1120
                                           Register name_reg,
 
1121
                                           Register scratch1,
 
1122
                                           Register scratch2,
 
1123
                                           Register scratch3,
 
1124
                                           String* name,
 
1125
                                           Label* miss) {
 
1126
  ASSERT(interceptor_holder->HasNamedInterceptor());
 
1127
  ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
 
1128
 
 
1129
  // Check that the receiver isn't a smi.
 
1130
  __ JumpIfSmi(receiver, miss);
 
1131
 
 
1132
  // So far the most popular follow ups for interceptor loads are FIELD
 
1133
  // and CALLBACKS, so inline only them, other cases may be added
 
1134
  // later.
 
1135
  bool compile_followup_inline = false;
 
1136
  if (lookup->IsProperty() && lookup->IsCacheable()) {
 
1137
    if (lookup->type() == FIELD) {
 
1138
      compile_followup_inline = true;
 
1139
    } else if (lookup->type() == CALLBACKS &&
 
1140
        lookup->GetCallbackObject()->IsAccessorInfo() &&
 
1141
        AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
 
1142
      compile_followup_inline = true;
 
1143
    }
 
1144
  }
 
1145
 
 
1146
  if (compile_followup_inline) {
 
1147
    // Compile the interceptor call, followed by inline code to load the
 
1148
    // property from further up the prototype chain if the call fails.
 
1149
    // Check that the maps haven't changed.
 
1150
    Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
 
1151
                                          scratch1, scratch2, scratch3,
 
1152
                                          name, miss);
 
1153
    ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
 
1154
 
 
1155
    // Save necessary data before invoking an interceptor.
 
1156
    // Requires a frame to make GC aware of pushed pointers.
 
1157
    __ EnterInternalFrame();
 
1158
 
 
1159
    if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
 
1160
      // CALLBACKS case needs a receiver to be passed into C++ callback.
 
1161
      __ push(receiver);
 
1162
    }
 
1163
    __ push(holder_reg);
 
1164
    __ push(name_reg);
 
1165
 
 
1166
    // Invoke an interceptor.  Note: map checks from receiver to
 
1167
    // interceptor's holder has been compiled before (see a caller
 
1168
    // of this method.)
 
1169
    CompileCallLoadPropertyWithInterceptor(masm(),
 
1170
                                           receiver,
 
1171
                                           holder_reg,
 
1172
                                           name_reg,
 
1173
                                           interceptor_holder);
 
1174
 
 
1175
    // Check if interceptor provided a value for property.  If it's
 
1176
    // the case, return immediately.
 
1177
    Label interceptor_failed;
 
1178
    __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
 
1179
    __ j(equal, &interceptor_failed);
 
1180
    __ LeaveInternalFrame();
 
1181
    __ ret(0);
 
1182
 
 
1183
    __ bind(&interceptor_failed);
 
1184
    __ pop(name_reg);
 
1185
    __ pop(holder_reg);
 
1186
    if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
 
1187
      __ pop(receiver);
 
1188
    }
 
1189
 
 
1190
    __ LeaveInternalFrame();
 
1191
 
 
1192
    // Check that the maps from interceptor's holder to lookup's holder
 
1193
    // haven't changed.  And load lookup's holder into |holder| register.
 
1194
    if (interceptor_holder != lookup->holder()) {
 
1195
      holder_reg = CheckPrototypes(interceptor_holder,
 
1196
                                   holder_reg,
 
1197
                                   lookup->holder(),
 
1198
                                   scratch1,
 
1199
                                   scratch2,
 
1200
                                   scratch3,
 
1201
                                   name,
 
1202
                                   miss);
 
1203
    }
 
1204
 
 
1205
    if (lookup->type() == FIELD) {
 
1206
      // We found FIELD property in prototype chain of interceptor's holder.
 
1207
      // Retrieve a field from field's holder.
 
1208
      GenerateFastPropertyLoad(masm(), rax, holder_reg,
 
1209
                               lookup->holder(), lookup->GetFieldIndex());
 
1210
      __ ret(0);
 
1211
    } else {
 
1212
      // We found CALLBACKS property in prototype chain of interceptor's
 
1213
      // holder.
 
1214
      ASSERT(lookup->type() == CALLBACKS);
 
1215
      ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
 
1216
      AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
 
1217
      ASSERT(callback != NULL);
 
1218
      ASSERT(callback->getter() != NULL);
 
1219
 
 
1220
      // Tail call to runtime.
 
1221
      // Important invariant in CALLBACKS case: the code above must be
 
1222
      // structured to never clobber |receiver| register.
 
1223
      __ pop(scratch2);  // return address
 
1224
      __ push(receiver);
 
1225
      __ push(holder_reg);
 
1226
      __ Move(holder_reg, Handle<AccessorInfo>(callback));
 
1227
      __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
 
1228
      __ push(holder_reg);
 
1229
      __ push(name_reg);
 
1230
      __ push(scratch2);  // restore return address
 
1231
 
 
1232
      ExternalReference ref =
 
1233
          ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
 
1234
      __ TailCallExternalReference(ref, 5, 1);
 
1235
    }
 
1236
  } else {  // !compile_followup_inline
 
1237
    // Call the runtime system to load the interceptor.
 
1238
    // Check that the maps haven't changed.
 
1239
    Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
 
1240
                                          scratch1, scratch2, scratch3,
 
1241
                                          name, miss);
 
1242
    __ pop(scratch2);  // save old return address
 
1243
    PushInterceptorArguments(masm(), receiver, holder_reg,
 
1244
                             name_reg, interceptor_holder);
 
1245
    __ push(scratch2);  // restore old return address
 
1246
 
 
1247
    ExternalReference ref = ExternalReference(
 
1248
        IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
 
1249
    __ TailCallExternalReference(ref, 5, 1);
 
1250
  }
 
1251
}
 
1252
 
 
1253
 
815
1254
void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
816
1255
  if (kind_ == Code::KEYED_CALL_IC) {
817
1256
    __ Cmp(rcx, Handle<String>(name));
820
1259
}
821
1260
 
822
1261
 
823
 
Object* CallStubCompiler::GenerateMissBranch() {
824
 
  Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
825
 
  if (obj->IsFailure()) return obj;
 
1262
void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
 
1263
                                                   JSObject* holder,
 
1264
                                                   String* name,
 
1265
                                                   Label* miss) {
 
1266
  ASSERT(holder->IsGlobalObject());
 
1267
 
 
1268
  // Get the number of arguments.
 
1269
  const int argc = arguments().immediate();
 
1270
 
 
1271
  // Get the receiver from the stack.
 
1272
  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
 
1273
 
 
1274
  // If the object is the holder then we know that it's a global
 
1275
  // object which can only happen for contextual calls. In this case,
 
1276
  // the receiver cannot be a smi.
 
1277
  if (object != holder) {
 
1278
    __ JumpIfSmi(rdx, miss);
 
1279
  }
 
1280
 
 
1281
  // Check that the maps haven't changed.
 
1282
  CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss);
 
1283
}
 
1284
 
 
1285
 
 
1286
void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
 
1287
                                                    JSFunction* function,
 
1288
                                                    Label* miss) {
 
1289
  // Get the value from the cell.
 
1290
  __ Move(rdi, Handle<JSGlobalPropertyCell>(cell));
 
1291
  __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
 
1292
 
 
1293
  // Check that the cell contains the same function.
 
1294
  if (Heap::InNewSpace(function)) {
 
1295
    // We can't embed a pointer to a function in new space so we have
 
1296
    // to verify that the shared function info is unchanged. This has
 
1297
    // the nice side effect that multiple closures based on the same
 
1298
    // function can all use this call IC. Before we load through the
 
1299
    // function, we have to verify that it still is a function.
 
1300
    __ JumpIfSmi(rdi, miss);
 
1301
    __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
 
1302
    __ j(not_equal, miss);
 
1303
 
 
1304
    // Check the shared function info. Make sure it hasn't changed.
 
1305
    __ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
 
1306
    __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
 
1307
    __ j(not_equal, miss);
 
1308
  } else {
 
1309
    __ Cmp(rdi, Handle<JSFunction>(function));
 
1310
    __ j(not_equal, miss);
 
1311
  }
 
1312
}
 
1313
 
 
1314
 
 
1315
MaybeObject* CallStubCompiler::GenerateMissBranch() {
 
1316
  MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(),
 
1317
                                                      kind_);
 
1318
  Object* obj;
 
1319
  if (!maybe_obj->ToObject(&obj)) return maybe_obj;
826
1320
  __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
827
1321
  return obj;
828
1322
}
829
1323
 
830
1324
 
831
 
Object* CallStubCompiler::CompileCallConstant(Object* object,
832
 
                                              JSObject* holder,
833
 
                                              JSFunction* function,
834
 
                                              String* name,
835
 
                                              StubCompiler::CheckType check) {
836
 
  // ----------- S t a t e -------------
837
 
  // rcx                 : function name
838
 
  // rsp[0]              : return address
839
 
  // rsp[8]              : argument argc
840
 
  // rsp[16]             : argument argc - 1
841
 
  // ...
842
 
  // rsp[argc * 8]       : argument 1
843
 
  // rsp[(argc + 1) * 8] : argument 0 = receiver
844
 
  // -----------------------------------
845
 
 
846
 
  SharedFunctionInfo* function_info = function->shared();
847
 
  if (function_info->HasCustomCallGenerator()) {
848
 
    const int id = function_info->custom_call_generator_id();
849
 
    Object* result =
850
 
        CompileCustomCall(id, object, holder, function, name, check);
851
 
    // undefined means bail out to regular compiler.
852
 
    if (!result->IsUndefined()) {
853
 
      return result;
854
 
    }
855
 
  }
856
 
 
857
 
  Label miss_in_smi_check;
858
 
 
859
 
  GenerateNameCheck(name, &miss_in_smi_check);
860
 
 
861
 
  // Get the receiver from the stack.
862
 
  const int argc = arguments().immediate();
863
 
  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
864
 
 
865
 
  // Check that the receiver isn't a smi.
866
 
  if (check != NUMBER_CHECK) {
867
 
    __ JumpIfSmi(rdx, &miss_in_smi_check);
868
 
  }
869
 
 
870
 
  // Make sure that it's okay not to patch the on stack receiver
871
 
  // unless we're doing a receiver map check.
872
 
  ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
873
 
 
874
 
  CallOptimization optimization(function);
875
 
  int depth = kInvalidProtoDepth;
876
 
  Label miss;
877
 
 
878
 
  switch (check) {
879
 
    case RECEIVER_MAP_CHECK:
880
 
      __ IncrementCounter(&Counters::call_const, 1);
881
 
 
882
 
      if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
883
 
        depth = optimization.GetPrototypeDepthOfExpectedType(
884
 
            JSObject::cast(object), holder);
885
 
      }
886
 
 
887
 
      if (depth != kInvalidProtoDepth) {
888
 
        __ IncrementCounter(&Counters::call_const_fast_api, 1);
889
 
        ReserveSpaceForFastApiCall(masm(), rax);
890
 
      }
891
 
 
892
 
      // Check that the maps haven't changed.
893
 
      CheckPrototypes(JSObject::cast(object), rdx, holder,
894
 
                      rbx, rax, rdi, name, depth, &miss);
895
 
 
896
 
      // Patch the receiver on the stack with the global proxy if
897
 
      // necessary.
898
 
      if (object->IsGlobalObject()) {
899
 
        ASSERT(depth == kInvalidProtoDepth);
900
 
        __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
901
 
        __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
902
 
      }
903
 
      break;
904
 
 
905
 
    case STRING_CHECK:
906
 
      if (!function->IsBuiltin()) {
907
 
        // Calling non-builtins with a value as receiver requires boxing.
908
 
        __ jmp(&miss);
909
 
      } else {
910
 
        // Check that the object is a two-byte string or a symbol.
911
 
        __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
912
 
        __ j(above_equal, &miss);
913
 
        // Check that the maps starting from the prototype haven't changed.
914
 
        GenerateDirectLoadGlobalFunctionPrototype(
915
 
            masm(), Context::STRING_FUNCTION_INDEX, rax);
916
 
        CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
917
 
                        rbx, rdx, rdi, name, &miss);
918
 
      }
919
 
      break;
920
 
 
921
 
    case NUMBER_CHECK: {
922
 
      if (!function->IsBuiltin()) {
923
 
        // Calling non-builtins with a value as receiver requires boxing.
924
 
        __ jmp(&miss);
925
 
      } else {
926
 
        Label fast;
927
 
        // Check that the object is a smi or a heap number.
928
 
        __ JumpIfSmi(rdx, &fast);
929
 
        __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
930
 
        __ j(not_equal, &miss);
931
 
        __ bind(&fast);
932
 
        // Check that the maps starting from the prototype haven't changed.
933
 
        GenerateDirectLoadGlobalFunctionPrototype(
934
 
            masm(), Context::NUMBER_FUNCTION_INDEX, rax);
935
 
        CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
936
 
                        rbx, rdx, rdi, name, &miss);
937
 
      }
938
 
      break;
939
 
    }
940
 
 
941
 
    case BOOLEAN_CHECK: {
942
 
      if (!function->IsBuiltin()) {
943
 
        // Calling non-builtins with a value as receiver requires boxing.
944
 
        __ jmp(&miss);
945
 
      } else {
946
 
        Label fast;
947
 
        // Check that the object is a boolean.
948
 
        __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
949
 
        __ j(equal, &fast);
950
 
        __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
951
 
        __ j(not_equal, &miss);
952
 
        __ bind(&fast);
953
 
        // Check that the maps starting from the prototype haven't changed.
954
 
        GenerateDirectLoadGlobalFunctionPrototype(
955
 
            masm(), Context::BOOLEAN_FUNCTION_INDEX, rax);
956
 
        CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
957
 
                        rbx, rdx, rdi, name, &miss);
958
 
      }
959
 
      break;
960
 
    }
961
 
 
962
 
    default:
963
 
      UNREACHABLE();
964
 
  }
965
 
 
966
 
  if (depth != kInvalidProtoDepth) {
967
 
    GenerateFastApiCall(masm(), optimization, argc);
968
 
  } else {
969
 
    __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
970
 
  }
971
 
 
972
 
  // Handle call cache miss.
973
 
  __ bind(&miss);
974
 
  if (depth != kInvalidProtoDepth) {
975
 
    FreeSpaceForFastApiCall(masm(), rax);
976
 
  }
977
 
 
978
 
  // Handle call cache miss.
979
 
  __ bind(&miss_in_smi_check);
980
 
  Object* obj = GenerateMissBranch();
981
 
  if (obj->IsFailure()) return obj;
982
 
 
983
 
  // Return the generated code.
984
 
  return GetCode(function);
985
 
}
986
 
 
987
 
 
988
 
Object* CallStubCompiler::CompileCallField(JSObject* object,
989
 
                                           JSObject* holder,
990
 
                                           int index,
991
 
                                           String* name) {
 
1325
MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
 
1326
                                                JSObject* holder,
 
1327
                                                int index,
 
1328
                                                String* name) {
992
1329
  // ----------- S t a t e -------------
993
1330
  // rcx                 : function name
994
1331
  // rsp[0]              : return address
1032
1369
 
1033
1370
  // Handle call cache miss.
1034
1371
  __ bind(&miss);
1035
 
  Object* obj = GenerateMissBranch();
1036
 
  if (obj->IsFailure()) return obj;
 
1372
  Object* obj;
 
1373
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
1374
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
1375
  }
1037
1376
 
1038
1377
  // Return the generated code.
1039
1378
  return GetCode(FIELD, name);
1040
1379
}
1041
1380
 
1042
1381
 
1043
 
Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1044
 
                                               JSObject* holder,
1045
 
                                               JSFunction* function,
1046
 
                                               String* name,
1047
 
                                               CheckType check) {
 
1382
MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
 
1383
                                                    JSObject* holder,
 
1384
                                                    JSGlobalPropertyCell* cell,
 
1385
                                                    JSFunction* function,
 
1386
                                                    String* name) {
1048
1387
  // ----------- S t a t e -------------
1049
1388
  //  -- rcx                 : name
1050
1389
  //  -- rsp[0]              : return address
1052
1391
  //  -- ...
1053
1392
  //  -- rsp[(argc + 1) * 8] : receiver
1054
1393
  // -----------------------------------
1055
 
  ASSERT(check == RECEIVER_MAP_CHECK);
1056
1394
 
1057
1395
  // If object is not an array, bail out to regular call.
1058
 
  if (!object->IsJSArray()) {
1059
 
    return Heap::undefined_value();
1060
 
  }
 
1396
  if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
1061
1397
 
1062
1398
  Label miss;
1063
1399
 
1084
1420
    __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1085
1421
    __ ret((argc + 1) * kPointerSize);
1086
1422
  } else {
 
1423
    Label call_builtin;
 
1424
 
1087
1425
    // Get the elements array of the object.
1088
1426
    __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1089
1427
 
1090
 
    // Check that the elements are in fast mode (not dictionary).
 
1428
    // Check that the elements are in fast mode and writable.
1091
1429
    __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
1092
1430
           Factory::fixed_array_map());
1093
 
    __ j(not_equal, &miss);
 
1431
    __ j(not_equal, &call_builtin);
1094
1432
 
1095
1433
    if (argc == 1) {  // Otherwise fall through to call builtin.
1096
 
      Label call_builtin, exit, with_write_barrier, attempt_to_grow_elements;
 
1434
      Label exit, with_write_barrier, attempt_to_grow_elements;
1097
1435
 
1098
1436
      // Get the array's length into rax and calculate new length.
1099
1437
      __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1129
1467
 
1130
1468
      __ InNewSpace(rbx, rcx, equal, &exit);
1131
1469
 
1132
 
      RecordWriteStub stub(rbx, rdx, rcx);
1133
 
      __ CallStub(&stub);
 
1470
      __ RecordWriteHelper(rbx, rdx, rcx);
1134
1471
 
1135
1472
      __ ret((argc + 1) * kPointerSize);
1136
1473
 
1137
1474
      __ bind(&attempt_to_grow_elements);
 
1475
      if (!FLAG_inline_new) {
 
1476
        __ jmp(&call_builtin);
 
1477
      }
 
1478
 
1138
1479
      ExternalReference new_space_allocation_top =
1139
1480
          ExternalReference::new_space_allocation_top_address();
1140
1481
      ExternalReference new_space_allocation_limit =
1164
1505
      // Push the argument...
1165
1506
      __ movq(Operand(rdx, 0), rcx);
1166
1507
      // ... and fill the rest with holes.
1167
 
      __ Move(kScratchRegister, Factory::the_hole_value());
 
1508
      __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
1168
1509
      for (int i = 1; i < kAllocationDelta; i++) {
1169
1510
        __ movq(Operand(rdx, i * kPointerSize), kScratchRegister);
1170
1511
      }
1175
1516
      // Increment element's and array's sizes.
1176
1517
      __ SmiAddConstant(FieldOperand(rbx, FixedArray::kLengthOffset),
1177
1518
                        Smi::FromInt(kAllocationDelta));
 
1519
 
1178
1520
      // Make new length a smi before returning it.
1179
1521
      __ Integer32ToSmi(rax, rax);
1180
1522
      __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
 
1523
 
1181
1524
      // Elements are in new space, so write barrier is not required.
1182
1525
      __ ret((argc + 1) * kPointerSize);
1183
 
 
1184
 
      __ bind(&call_builtin);
1185
1526
    }
1186
1527
 
 
1528
    __ bind(&call_builtin);
1187
1529
    __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1188
1530
                                 argc + 1,
1189
1531
                                 1);
1190
1532
  }
1191
1533
 
1192
1534
  __ bind(&miss);
1193
 
  Object* obj = GenerateMissBranch();
1194
 
  if (obj->IsFailure()) return obj;
 
1535
  Object* obj;
 
1536
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
1537
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
1538
  }
1195
1539
 
1196
1540
  // Return the generated code.
1197
1541
  return GetCode(function);
1198
1542
}
1199
1543
 
1200
1544
 
1201
 
Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1202
 
                                              JSObject* holder,
1203
 
                                              JSFunction* function,
1204
 
                                              String* name,
1205
 
                                              CheckType check) {
 
1545
MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
 
1546
                                                   JSObject* holder,
 
1547
                                                   JSGlobalPropertyCell* cell,
 
1548
                                                   JSFunction* function,
 
1549
                                                   String* name) {
1206
1550
  // ----------- S t a t e -------------
1207
 
  //  -- ecx                 : name
1208
 
  //  -- esp[0]              : return address
1209
 
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
 
1551
  //  -- rcx                 : name
 
1552
  //  -- rsp[0]              : return address
 
1553
  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1210
1554
  //  -- ...
1211
 
  //  -- esp[(argc + 1) * 4] : receiver
 
1555
  //  -- rsp[(argc + 1) * 8] : receiver
1212
1556
  // -----------------------------------
1213
 
  ASSERT(check == RECEIVER_MAP_CHECK);
1214
1557
 
1215
1558
  // If object is not an array, bail out to regular call.
1216
 
  if (!object->IsJSArray()) {
1217
 
    return Heap::undefined_value();
1218
 
  }
 
1559
  if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
1219
1560
 
1220
1561
  Label miss, return_undefined, call_builtin;
1221
1562
 
1235
1576
  // Get the elements array of the object.
1236
1577
  __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1237
1578
 
1238
 
  // Check that the elements are in fast mode (not dictionary).
1239
 
  __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), Factory::fixed_array_map());
1240
 
  __ j(not_equal, &miss);
 
1579
  // Check that the elements are in fast mode and writable.
 
1580
  __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
 
1581
                 Heap::kFixedArrayMapRootIndex);
 
1582
  __ j(not_equal, &call_builtin);
1241
1583
 
1242
1584
  // Get the array's length into rcx and calculate new length.
1243
1585
  __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
1245
1587
  __ j(negative, &return_undefined);
1246
1588
 
1247
1589
  // Get the last element.
1248
 
  __ Move(r9, Factory::the_hole_value());
 
1590
  __ LoadRoot(r9, Heap::kTheHoleValueRootIndex);
1249
1591
  __ movq(rax, FieldOperand(rbx,
1250
1592
                            rcx, times_pointer_size,
1251
1593
                            FixedArray::kHeaderSize));
1265
1607
  __ ret((argc + 1) * kPointerSize);
1266
1608
 
1267
1609
  __ bind(&return_undefined);
1268
 
 
1269
 
  __ Move(rax, Factory::undefined_value());
 
1610
  __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1270
1611
  __ ret((argc + 1) * kPointerSize);
1271
1612
 
1272
1613
  __ bind(&call_builtin);
1273
1614
  __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1274
1615
                               argc + 1,
1275
1616
                               1);
1276
 
  __ bind(&miss);
1277
 
  Object* obj = GenerateMissBranch();
1278
 
  if (obj->IsFailure()) return obj;
1279
 
 
1280
 
  // Return the generated code.
1281
 
  return GetCode(function);
1282
 
}
1283
 
 
1284
 
 
1285
 
Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
 
1617
 
 
1618
  __ bind(&miss);
 
1619
  Object* obj;
 
1620
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
1621
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
1622
  }
 
1623
 
 
1624
  // Return the generated code.
 
1625
  return GetCode(function);
 
1626
}
 
1627
 
 
1628
 
 
1629
MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
 
1630
    Object* object,
 
1631
    JSObject* holder,
 
1632
    JSGlobalPropertyCell* cell,
 
1633
    JSFunction* function,
 
1634
    String* name) {
 
1635
  // ----------- S t a t e -------------
 
1636
  //  -- rcx                 : function name
 
1637
  //  -- rsp[0]              : return address
 
1638
  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
 
1639
  //  -- ...
 
1640
  //  -- rsp[(argc + 1) * 8] : receiver
 
1641
  // -----------------------------------
 
1642
 
 
1643
  // If object is not a string, bail out to regular call.
 
1644
  if (!object->IsString() || cell != NULL) return Heap::undefined_value();
 
1645
 
 
1646
  const int argc = arguments().immediate();
 
1647
 
 
1648
  Label miss;
 
1649
  Label name_miss;
 
1650
  Label index_out_of_range;
 
1651
  Label* index_out_of_range_label = &index_out_of_range;
 
1652
 
 
1653
  if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
 
1654
    index_out_of_range_label = &miss;
 
1655
  }
 
1656
 
 
1657
  GenerateNameCheck(name, &name_miss);
 
1658
 
 
1659
  // Check that the maps starting from the prototype haven't changed.
 
1660
  GenerateDirectLoadGlobalFunctionPrototype(masm(),
 
1661
                                            Context::STRING_FUNCTION_INDEX,
 
1662
                                            rax,
 
1663
                                            &miss);
 
1664
  ASSERT(object != holder);
 
1665
  CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
 
1666
                  rbx, rdx, rdi, name, &miss);
 
1667
 
 
1668
  Register receiver = rbx;
 
1669
  Register index = rdi;
 
1670
  Register scratch = rdx;
 
1671
  Register result = rax;
 
1672
  __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
 
1673
  if (argc > 0) {
 
1674
    __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
 
1675
  } else {
 
1676
    __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
 
1677
  }
 
1678
 
 
1679
  StringCharCodeAtGenerator char_code_at_generator(receiver,
 
1680
                                                   index,
 
1681
                                                   scratch,
 
1682
                                                   result,
 
1683
                                                   &miss,  // When not a string.
 
1684
                                                   &miss,  // When not a number.
 
1685
                                                   index_out_of_range_label,
 
1686
                                                   STRING_INDEX_IS_NUMBER);
 
1687
  char_code_at_generator.GenerateFast(masm());
 
1688
  __ ret((argc + 1) * kPointerSize);
 
1689
 
 
1690
  StubRuntimeCallHelper call_helper;
 
1691
  char_code_at_generator.GenerateSlow(masm(), call_helper);
 
1692
 
 
1693
  if (index_out_of_range.is_linked()) {
 
1694
    __ bind(&index_out_of_range);
 
1695
    __ LoadRoot(rax, Heap::kNanValueRootIndex);
 
1696
    __ ret((argc + 1) * kPointerSize);
 
1697
  }
 
1698
 
 
1699
  __ bind(&miss);
 
1700
  // Restore function name in rcx.
 
1701
  __ Move(rcx, Handle<String>(name));
 
1702
  __ bind(&name_miss);
 
1703
  Object* obj;
 
1704
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
1705
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
1706
  }
 
1707
 
 
1708
  // Return the generated code.
 
1709
  return GetCode(function);
 
1710
}
 
1711
 
 
1712
 
 
1713
MaybeObject* CallStubCompiler::CompileStringCharAtCall(
 
1714
    Object* object,
 
1715
    JSObject* holder,
 
1716
    JSGlobalPropertyCell* cell,
 
1717
    JSFunction* function,
 
1718
    String* name) {
 
1719
  // ----------- S t a t e -------------
 
1720
  //  -- rcx                 : function name
 
1721
  //  -- rsp[0]              : return address
 
1722
  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
 
1723
  //  -- ...
 
1724
  //  -- rsp[(argc + 1) * 8] : receiver
 
1725
  // -----------------------------------
 
1726
 
 
1727
  // If object is not a string, bail out to regular call.
 
1728
  if (!object->IsString() || cell != NULL) return Heap::undefined_value();
 
1729
 
 
1730
  const int argc = arguments().immediate();
 
1731
 
 
1732
  Label miss;
 
1733
  Label name_miss;
 
1734
  Label index_out_of_range;
 
1735
  Label* index_out_of_range_label = &index_out_of_range;
 
1736
 
 
1737
  if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
 
1738
    index_out_of_range_label = &miss;
 
1739
  }
 
1740
 
 
1741
  GenerateNameCheck(name, &name_miss);
 
1742
 
 
1743
  // Check that the maps starting from the prototype haven't changed.
 
1744
  GenerateDirectLoadGlobalFunctionPrototype(masm(),
 
1745
                                            Context::STRING_FUNCTION_INDEX,
 
1746
                                            rax,
 
1747
                                            &miss);
 
1748
  ASSERT(object != holder);
 
1749
  CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
 
1750
                  rbx, rdx, rdi, name, &miss);
 
1751
 
 
1752
  Register receiver = rax;
 
1753
  Register index = rdi;
 
1754
  Register scratch1 = rbx;
 
1755
  Register scratch2 = rdx;
 
1756
  Register result = rax;
 
1757
  __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
 
1758
  if (argc > 0) {
 
1759
    __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
 
1760
  } else {
 
1761
    __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
 
1762
  }
 
1763
 
 
1764
  StringCharAtGenerator char_at_generator(receiver,
 
1765
                                          index,
 
1766
                                          scratch1,
 
1767
                                          scratch2,
 
1768
                                          result,
 
1769
                                          &miss,  // When not a string.
 
1770
                                          &miss,  // When not a number.
 
1771
                                          index_out_of_range_label,
 
1772
                                          STRING_INDEX_IS_NUMBER);
 
1773
  char_at_generator.GenerateFast(masm());
 
1774
  __ ret((argc + 1) * kPointerSize);
 
1775
 
 
1776
  StubRuntimeCallHelper call_helper;
 
1777
  char_at_generator.GenerateSlow(masm(), call_helper);
 
1778
 
 
1779
  if (index_out_of_range.is_linked()) {
 
1780
    __ bind(&index_out_of_range);
 
1781
    __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
 
1782
    __ ret((argc + 1) * kPointerSize);
 
1783
  }
 
1784
 
 
1785
  __ bind(&miss);
 
1786
  // Restore function name in rcx.
 
1787
  __ Move(rcx, Handle<String>(name));
 
1788
  __ bind(&name_miss);
 
1789
  Object* obj;
 
1790
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
1791
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
1792
  }
 
1793
 
 
1794
  // Return the generated code.
 
1795
  return GetCode(function);
 
1796
}
 
1797
 
 
1798
 
 
1799
MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
 
1800
    Object* object,
 
1801
    JSObject* holder,
 
1802
    JSGlobalPropertyCell* cell,
 
1803
    JSFunction* function,
 
1804
    String* name) {
 
1805
  // ----------- S t a t e -------------
 
1806
  //  -- rcx                 : function name
 
1807
  //  -- rsp[0]              : return address
 
1808
  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
 
1809
  //  -- ...
 
1810
  //  -- rsp[(argc + 1) * 8] : receiver
 
1811
  // -----------------------------------
 
1812
 
 
1813
  const int argc = arguments().immediate();
 
1814
 
 
1815
  // If the object is not a JSObject or we got an unexpected number of
 
1816
  // arguments, bail out to the regular call.
 
1817
  if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
 
1818
 
 
1819
  Label miss;
 
1820
  GenerateNameCheck(name, &miss);
 
1821
 
 
1822
  if (cell == NULL) {
 
1823
    __ movq(rdx, Operand(rsp, 2 * kPointerSize));
 
1824
 
 
1825
    __ JumpIfSmi(rdx, &miss);
 
1826
 
 
1827
    CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name,
 
1828
                    &miss);
 
1829
  } else {
 
1830
    ASSERT(cell->value() == function);
 
1831
    GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
 
1832
    GenerateLoadFunctionFromCell(cell, function, &miss);
 
1833
  }
 
1834
 
 
1835
  // Load the char code argument.
 
1836
  Register code = rbx;
 
1837
  __ movq(code, Operand(rsp, 1 * kPointerSize));
 
1838
 
 
1839
  // Check the code is a smi.
 
1840
  Label slow;
 
1841
  __ JumpIfNotSmi(code, &slow);
 
1842
 
 
1843
  // Convert the smi code to uint16.
 
1844
  __ SmiAndConstant(code, code, Smi::FromInt(0xffff));
 
1845
 
 
1846
  StringCharFromCodeGenerator char_from_code_generator(code, rax);
 
1847
  char_from_code_generator.GenerateFast(masm());
 
1848
  __ ret(2 * kPointerSize);
 
1849
 
 
1850
  StubRuntimeCallHelper call_helper;
 
1851
  char_from_code_generator.GenerateSlow(masm(), call_helper);
 
1852
 
 
1853
  // Tail call the full function. We do not have to patch the receiver
 
1854
  // because the function makes no use of it.
 
1855
  __ bind(&slow);
 
1856
  __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
 
1857
 
 
1858
  __ bind(&miss);
 
1859
  // rcx: function name.
 
1860
  Object* obj;
 
1861
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
1862
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
1863
  }
 
1864
 
 
1865
  // Return the generated code.
 
1866
  return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
 
1867
}
 
1868
 
 
1869
 
 
1870
MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
 
1871
                                                    JSObject* holder,
 
1872
                                                    JSGlobalPropertyCell* cell,
 
1873
                                                    JSFunction* function,
 
1874
                                                    String* name) {
 
1875
  // TODO(872): implement this.
 
1876
  return Heap::undefined_value();
 
1877
}
 
1878
 
 
1879
 
 
1880
MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
1286
1881
                                                  JSObject* holder,
 
1882
                                                  JSGlobalPropertyCell* cell,
1287
1883
                                                  JSFunction* function,
1288
 
                                                  String* name,
1289
 
                                                  CheckType check) {
1290
 
  // TODO(722): implement this.
1291
 
  return Heap::undefined_value();
1292
 
}
1293
 
 
1294
 
 
1295
 
Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
 
1884
                                                  String* name) {
 
1885
  // ----------- S t a t e -------------
 
1886
  //  -- rcx                 : function name
 
1887
  //  -- rsp[0]              : return address
 
1888
  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
 
1889
  //  -- ...
 
1890
  //  -- rsp[(argc + 1) * 8] : receiver
 
1891
  // -----------------------------------
 
1892
 
 
1893
  const int argc = arguments().immediate();
 
1894
 
 
1895
  // If the object is not a JSObject or we got an unexpected number of
 
1896
  // arguments, bail out to the regular call.
 
1897
  if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
 
1898
 
 
1899
  Label miss;
 
1900
  GenerateNameCheck(name, &miss);
 
1901
 
 
1902
  if (cell == NULL) {
 
1903
    __ movq(rdx, Operand(rsp, 2 * kPointerSize));
 
1904
 
 
1905
    __ JumpIfSmi(rdx, &miss);
 
1906
 
 
1907
    CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name,
 
1908
                    &miss);
 
1909
  } else {
 
1910
    ASSERT(cell->value() == function);
 
1911
    GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
 
1912
    GenerateLoadFunctionFromCell(cell, function, &miss);
 
1913
  }
 
1914
 
 
1915
  // Load the (only) argument into rax.
 
1916
  __ movq(rax, Operand(rsp, 1 * kPointerSize));
 
1917
 
 
1918
  // Check if the argument is a smi.
 
1919
  Label not_smi;
 
1920
  STATIC_ASSERT(kSmiTag == 0);
 
1921
  __ JumpIfNotSmi(rax, &not_smi);
 
1922
  __ SmiToInteger32(rax, rax);
 
1923
 
 
1924
  // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
 
1925
  // otherwise.
 
1926
  __ movl(rbx, rax);
 
1927
  __ sarl(rbx, Immediate(kBitsPerInt - 1));
 
1928
 
 
1929
  // Do bitwise not or do nothing depending on ebx.
 
1930
  __ xorl(rax, rbx);
 
1931
 
 
1932
  // Add 1 or do nothing depending on ebx.
 
1933
  __ subl(rax, rbx);
 
1934
 
 
1935
  // If the result is still negative, go to the slow case.
 
1936
  // This only happens for the most negative smi.
 
1937
  Label slow;
 
1938
  __ j(negative, &slow);
 
1939
 
 
1940
  // Smi case done.
 
1941
  __ Integer32ToSmi(rax, rax);
 
1942
  __ ret(2 * kPointerSize);
 
1943
 
 
1944
  // Check if the argument is a heap number and load its value.
 
1945
  __ bind(&not_smi);
 
1946
  __ CheckMap(rax, Factory::heap_number_map(), &slow, true);
 
1947
  __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
 
1948
 
 
1949
  // Check the sign of the argument. If the argument is positive,
 
1950
  // just return it.
 
1951
  Label negative_sign;
 
1952
  const int sign_mask_shift =
 
1953
      (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte;
 
1954
  __ movq(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift,
 
1955
          RelocInfo::NONE);
 
1956
  __ testq(rbx, rdi);
 
1957
  __ j(not_zero, &negative_sign);
 
1958
  __ ret(2 * kPointerSize);
 
1959
 
 
1960
  // If the argument is negative, clear the sign, and return a new
 
1961
  // number. We still have the sign mask in rdi.
 
1962
  __ bind(&negative_sign);
 
1963
  __ xor_(rbx, rdi);
 
1964
  __ AllocateHeapNumber(rax, rdx, &slow);
 
1965
  __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rbx);
 
1966
  __ ret(2 * kPointerSize);
 
1967
 
 
1968
  // Tail call the full function. We do not have to patch the receiver
 
1969
  // because the function makes no use of it.
 
1970
  __ bind(&slow);
 
1971
  __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
 
1972
 
 
1973
  __ bind(&miss);
 
1974
  // rcx: function name.
 
1975
  Object* obj;
 
1976
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
1977
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
1978
  }
 
1979
 
 
1980
  // Return the generated code.
 
1981
  return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
 
1982
}
 
1983
 
 
1984
 
 
1985
MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
 
1986
                                                   JSObject* holder,
 
1987
                                                   JSFunction* function,
 
1988
                                                   String* name,
 
1989
                                                   CheckType check) {
 
1990
  // ----------- S t a t e -------------
 
1991
  // rcx                 : function name
 
1992
  // rsp[0]              : return address
 
1993
  // rsp[8]              : argument argc
 
1994
  // rsp[16]             : argument argc - 1
 
1995
  // ...
 
1996
  // rsp[argc * 8]       : argument 1
 
1997
  // rsp[(argc + 1) * 8] : argument 0 = receiver
 
1998
  // -----------------------------------
 
1999
 
 
2000
  SharedFunctionInfo* function_info = function->shared();
 
2001
  if (function_info->HasBuiltinFunctionId()) {
 
2002
    BuiltinFunctionId id = function_info->builtin_function_id();
 
2003
    MaybeObject* maybe_result = CompileCustomCall(
 
2004
        id, object, holder,  NULL, function, name);
 
2005
    Object* result;
 
2006
    if (!maybe_result->ToObject(&result)) return maybe_result;
 
2007
    // undefined means bail out to regular compiler.
 
2008
    if (!result->IsUndefined()) return result;
 
2009
  }
 
2010
 
 
2011
  Label miss_in_smi_check;
 
2012
 
 
2013
  GenerateNameCheck(name, &miss_in_smi_check);
 
2014
 
 
2015
  // Get the receiver from the stack.
 
2016
  const int argc = arguments().immediate();
 
2017
  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
 
2018
 
 
2019
  // Check that the receiver isn't a smi.
 
2020
  if (check != NUMBER_CHECK) {
 
2021
    __ JumpIfSmi(rdx, &miss_in_smi_check);
 
2022
  }
 
2023
 
 
2024
  // Make sure that it's okay not to patch the on stack receiver
 
2025
  // unless we're doing a receiver map check.
 
2026
  ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
 
2027
 
 
2028
  CallOptimization optimization(function);
 
2029
  int depth = kInvalidProtoDepth;
 
2030
  Label miss;
 
2031
 
 
2032
  switch (check) {
 
2033
    case RECEIVER_MAP_CHECK:
 
2034
      __ IncrementCounter(&Counters::call_const, 1);
 
2035
 
 
2036
      if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
 
2037
        depth = optimization.GetPrototypeDepthOfExpectedType(
 
2038
            JSObject::cast(object), holder);
 
2039
      }
 
2040
 
 
2041
      if (depth != kInvalidProtoDepth) {
 
2042
        __ IncrementCounter(&Counters::call_const_fast_api, 1);
 
2043
 
 
2044
        // Allocate space for v8::Arguments implicit values. Must be initialized
 
2045
        // before to call any runtime function.
 
2046
        __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
 
2047
      }
 
2048
 
 
2049
      // Check that the maps haven't changed.
 
2050
      CheckPrototypes(JSObject::cast(object), rdx, holder,
 
2051
                      rbx, rax, rdi, name, depth, &miss);
 
2052
 
 
2053
      // Patch the receiver on the stack with the global proxy if
 
2054
      // necessary.
 
2055
      if (object->IsGlobalObject()) {
 
2056
        ASSERT(depth == kInvalidProtoDepth);
 
2057
        __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
 
2058
        __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
 
2059
      }
 
2060
      break;
 
2061
 
 
2062
    case STRING_CHECK:
 
2063
      if (!function->IsBuiltin() && !function_info->strict_mode()) {
 
2064
        // Calling non-strict non-builtins with a value as the receiver
 
2065
        // requires boxing.
 
2066
        __ jmp(&miss);
 
2067
      } else {
 
2068
        // Check that the object is a two-byte string or a symbol.
 
2069
        __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
 
2070
        __ j(above_equal, &miss);
 
2071
        // Check that the maps starting from the prototype haven't changed.
 
2072
        GenerateDirectLoadGlobalFunctionPrototype(
 
2073
            masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
 
2074
        CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
 
2075
                        rbx, rdx, rdi, name, &miss);
 
2076
      }
 
2077
      break;
 
2078
 
 
2079
    case NUMBER_CHECK: {
 
2080
      if (!function->IsBuiltin() && !function_info->strict_mode()) {
 
2081
        // Calling non-strict non-builtins with a value as the receiver
 
2082
        // requires boxing.
 
2083
        __ jmp(&miss);
 
2084
      } else {
 
2085
        Label fast;
 
2086
        // Check that the object is a smi or a heap number.
 
2087
        __ JumpIfSmi(rdx, &fast);
 
2088
        __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
 
2089
        __ j(not_equal, &miss);
 
2090
        __ bind(&fast);
 
2091
        // Check that the maps starting from the prototype haven't changed.
 
2092
        GenerateDirectLoadGlobalFunctionPrototype(
 
2093
            masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
 
2094
        CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
 
2095
                        rbx, rdx, rdi, name, &miss);
 
2096
      }
 
2097
      break;
 
2098
    }
 
2099
 
 
2100
    case BOOLEAN_CHECK: {
 
2101
      if (!function->IsBuiltin() && !function_info->strict_mode()) {
 
2102
        // Calling non-strict non-builtins with a value as the receiver
 
2103
        // requires boxing.
 
2104
        __ jmp(&miss);
 
2105
      } else {
 
2106
        Label fast;
 
2107
        // Check that the object is a boolean.
 
2108
        __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
 
2109
        __ j(equal, &fast);
 
2110
        __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
 
2111
        __ j(not_equal, &miss);
 
2112
        __ bind(&fast);
 
2113
        // Check that the maps starting from the prototype haven't changed.
 
2114
        GenerateDirectLoadGlobalFunctionPrototype(
 
2115
            masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
 
2116
        CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
 
2117
                        rbx, rdx, rdi, name, &miss);
 
2118
      }
 
2119
      break;
 
2120
    }
 
2121
 
 
2122
    default:
 
2123
      UNREACHABLE();
 
2124
  }
 
2125
 
 
2126
  if (depth != kInvalidProtoDepth) {
 
2127
    // Move the return address on top of the stack.
 
2128
    __ movq(rax, Operand(rsp, 3 * kPointerSize));
 
2129
    __ movq(Operand(rsp, 0 * kPointerSize), rax);
 
2130
 
 
2131
    // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
 
2132
    // duplicate of return address and will be overwritten.
 
2133
    MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
 
2134
    if (result->IsFailure()) return result;
 
2135
  } else {
 
2136
    __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
 
2137
  }
 
2138
 
 
2139
  // Handle call cache miss.
 
2140
  __ bind(&miss);
 
2141
  if (depth != kInvalidProtoDepth) {
 
2142
    __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
 
2143
  }
 
2144
 
 
2145
  // Handle call cache miss.
 
2146
  __ bind(&miss_in_smi_check);
 
2147
  Object* obj;
 
2148
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
2149
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
2150
  }
 
2151
 
 
2152
  // Return the generated code.
 
2153
  return GetCode(function);
 
2154
}
 
2155
 
 
2156
 
 
2157
MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
1296
2158
                                                      JSObject* holder,
1297
 
                                                      JSFunction* function,
1298
 
                                                      String* name,
1299
 
                                                      CheckType check) {
1300
 
  // TODO(722): implement this.
1301
 
  return Heap::undefined_value();
1302
 
}
1303
 
 
1304
 
 
1305
 
 
1306
 
Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
1307
 
                                                 JSObject* holder,
1308
 
                                                 String* name) {
 
2159
                                                      String* name) {
1309
2160
  // ----------- S t a t e -------------
1310
2161
  // rcx                 : function name
1311
2162
  // rsp[0]              : return address
1329
2180
  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1330
2181
 
1331
2182
  CallInterceptorCompiler compiler(this, arguments(), rcx);
1332
 
  compiler.Compile(masm(),
1333
 
                   object,
1334
 
                   holder,
1335
 
                   name,
1336
 
                   &lookup,
1337
 
                   rdx,
1338
 
                   rbx,
1339
 
                   rdi,
1340
 
                   rax,
1341
 
                   &miss);
 
2183
  MaybeObject* result = compiler.Compile(masm(),
 
2184
                                         object,
 
2185
                                         holder,
 
2186
                                         name,
 
2187
                                         &lookup,
 
2188
                                         rdx,
 
2189
                                         rbx,
 
2190
                                         rdi,
 
2191
                                         rax,
 
2192
                                         &miss);
 
2193
  if (result->IsFailure()) return result;
1342
2194
 
1343
2195
  // Restore receiver.
1344
2196
  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1361
2213
 
1362
2214
  // Handle load cache miss.
1363
2215
  __ bind(&miss);
1364
 
  Object* obj = GenerateMissBranch();
1365
 
  if (obj->IsFailure()) return obj;
 
2216
  Object* obj;
 
2217
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
2218
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
2219
  }
1366
2220
 
1367
2221
  // Return the generated code.
1368
2222
  return GetCode(INTERCEPTOR, name);
1369
2223
}
1370
2224
 
1371
2225
 
1372
 
Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1373
 
                                            GlobalObject* holder,
1374
 
                                            JSGlobalPropertyCell* cell,
1375
 
                                            JSFunction* function,
1376
 
                                            String* name) {
 
2226
MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
 
2227
                                                 GlobalObject* holder,
 
2228
                                                 JSGlobalPropertyCell* cell,
 
2229
                                                 JSFunction* function,
 
2230
                                                 String* name) {
1377
2231
  // ----------- S t a t e -------------
1378
 
  // -----------------------------------
1379
2232
  // rcx                 : function name
1380
2233
  // rsp[0]              : return address
1381
2234
  // rsp[8]              : argument argc
1383
2236
  // ...
1384
2237
  // rsp[argc * 8]       : argument 1
1385
2238
  // rsp[(argc + 1) * 8] : argument 0 = receiver
 
2239
  // -----------------------------------
 
2240
 
 
2241
  SharedFunctionInfo* function_info = function->shared();
 
2242
  if (function_info->HasBuiltinFunctionId()) {
 
2243
    BuiltinFunctionId id = function_info->builtin_function_id();
 
2244
    MaybeObject* maybe_result = CompileCustomCall(
 
2245
        id, object, holder, cell, function, name);
 
2246
    Object* result;
 
2247
    if (!maybe_result->ToObject(&result)) return maybe_result;
 
2248
    // undefined means bail out to regular compiler.
 
2249
    if (!result->IsUndefined()) return result;
 
2250
  }
 
2251
 
1386
2252
  Label miss;
1387
2253
 
1388
2254
  GenerateNameCheck(name, &miss);
1390
2256
  // Get the number of arguments.
1391
2257
  const int argc = arguments().immediate();
1392
2258
 
1393
 
  // Get the receiver from the stack.
1394
 
  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1395
 
 
1396
 
  // If the object is the holder then we know that it's a global
1397
 
  // object which can only happen for contextual calls. In this case,
1398
 
  // the receiver cannot be a smi.
1399
 
  if (object != holder) {
1400
 
    __ JumpIfSmi(rdx, &miss);
1401
 
  }
1402
 
 
1403
 
  // Check that the maps haven't changed.
1404
 
  CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, &miss);
1405
 
 
1406
 
  // Get the value from the cell.
1407
 
  __ Move(rdi, Handle<JSGlobalPropertyCell>(cell));
1408
 
  __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
1409
 
 
1410
 
  // Check that the cell contains the same function.
1411
 
  if (Heap::InNewSpace(function)) {
1412
 
    // We can't embed a pointer to a function in new space so we have
1413
 
    // to verify that the shared function info is unchanged. This has
1414
 
    // the nice side effect that multiple closures based on the same
1415
 
    // function can all use this call IC. Before we load through the
1416
 
    // function, we have to verify that it still is a function.
1417
 
    __ JumpIfSmi(rdi, &miss);
1418
 
    __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
1419
 
    __ j(not_equal, &miss);
1420
 
 
1421
 
    // Check the shared function info. Make sure it hasn't changed.
1422
 
    __ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
1423
 
    __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
1424
 
    __ j(not_equal, &miss);
1425
 
  } else {
1426
 
    __ Cmp(rdi, Handle<JSFunction>(function));
1427
 
    __ j(not_equal, &miss);
1428
 
  }
 
2259
  GenerateGlobalReceiverCheck(object, holder, name, &miss);
 
2260
 
 
2261
  GenerateLoadFunctionFromCell(cell, function, &miss);
1429
2262
 
1430
2263
  // Patch the receiver on the stack with the global proxy.
1431
2264
  if (object->IsGlobalObject()) {
1433
2266
    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
1434
2267
  }
1435
2268
 
1436
 
  // Setup the context (function already in edi).
 
2269
  // Setup the context (function already in rdi).
1437
2270
  __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
1438
2271
 
1439
2272
  // Jump to the cached code (tail call).
1440
2273
  __ IncrementCounter(&Counters::call_global_inline, 1);
1441
2274
  ASSERT(function->is_compiled());
1442
 
  Handle<Code> code(function->code());
1443
2275
  ParameterCount expected(function->shared()->formal_parameter_count());
1444
 
  __ InvokeCode(code, expected, arguments(),
1445
 
                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1446
 
 
 
2276
  if (V8::UseCrankshaft()) {
 
2277
    // TODO(kasperl): For now, we always call indirectly through the
 
2278
    // code field in the function to allow recompilation to take effect
 
2279
    // without changing any of the call sites.
 
2280
    __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
 
2281
    __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION);
 
2282
  } else {
 
2283
    Handle<Code> code(function->code());
 
2284
    __ InvokeCode(code, expected, arguments(),
 
2285
                  RelocInfo::CODE_TARGET, JUMP_FUNCTION);
 
2286
  }
1447
2287
  // Handle call cache miss.
1448
2288
  __ bind(&miss);
1449
2289
  __ IncrementCounter(&Counters::call_global_inline_miss, 1);
1450
 
  Object* obj = GenerateMissBranch();
1451
 
  if (obj->IsFailure()) return obj;
 
2290
  Object* obj;
 
2291
  { MaybeObject* maybe_obj = GenerateMissBranch();
 
2292
    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
 
2293
  }
1452
2294
 
1453
2295
  // Return the generated code.
1454
2296
  return GetCode(NORMAL, name);
1455
2297
}
1456
2298
 
1457
2299
 
1458
 
Object* LoadStubCompiler::CompileLoadCallback(String* name,
1459
 
                                              JSObject* object,
1460
 
                                              JSObject* holder,
1461
 
                                              AccessorInfo* callback) {
1462
 
  // ----------- S t a t e -------------
1463
 
  //  -- rax    : receiver
1464
 
  //  -- rcx    : name
1465
 
  //  -- rsp[0] : return address
1466
 
  // -----------------------------------
1467
 
  Label miss;
1468
 
 
1469
 
  Failure* failure = Failure::InternalError();
1470
 
  bool success = GenerateLoadCallback(object, holder, rax, rcx, rbx, rdx, rdi,
1471
 
                                      callback, name, &miss, &failure);
1472
 
  if (!success) return failure;
1473
 
 
1474
 
  __ bind(&miss);
1475
 
  GenerateLoadMiss(masm(), Code::LOAD_IC);
 
2300
MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
 
2301
                                                  int index,
 
2302
                                                  Map* transition,
 
2303
                                                  String* name) {
 
2304
  // ----------- S t a t e -------------
 
2305
  //  -- rax    : value
 
2306
  //  -- rcx    : name
 
2307
  //  -- rdx    : receiver
 
2308
  //  -- rsp[0] : return address
 
2309
  // -----------------------------------
 
2310
  Label miss;
 
2311
 
 
2312
  // Generate store field code.  Preserves receiver and name on jump to miss.
 
2313
  GenerateStoreField(masm(),
 
2314
                     object,
 
2315
                     index,
 
2316
                     transition,
 
2317
                     rdx, rcx, rbx,
 
2318
                     &miss);
 
2319
 
 
2320
  // Handle store cache miss.
 
2321
  __ bind(&miss);
 
2322
  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
 
2323
  __ Jump(ic, RelocInfo::CODE_TARGET);
 
2324
 
 
2325
  // Return the generated code.
 
2326
  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
 
2327
}
 
2328
 
 
2329
 
 
2330
MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
 
2331
                                                     AccessorInfo* callback,
 
2332
                                                     String* name) {
 
2333
  // ----------- S t a t e -------------
 
2334
  //  -- rax    : value
 
2335
  //  -- rcx    : name
 
2336
  //  -- rdx    : receiver
 
2337
  //  -- rsp[0] : return address
 
2338
  // -----------------------------------
 
2339
  Label miss;
 
2340
 
 
2341
  // Check that the object isn't a smi.
 
2342
  __ JumpIfSmi(rdx, &miss);
 
2343
 
 
2344
  // Check that the map of the object hasn't changed.
 
2345
  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
 
2346
         Handle<Map>(object->map()));
 
2347
  __ j(not_equal, &miss);
 
2348
 
 
2349
  // Perform global security token check if needed.
 
2350
  if (object->IsJSGlobalProxy()) {
 
2351
    __ CheckAccessGlobalProxy(rdx, rbx, &miss);
 
2352
  }
 
2353
 
 
2354
  // Stub never generated for non-global objects that require access
 
2355
  // checks.
 
2356
  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
2357
 
 
2358
  __ pop(rbx);  // remove the return address
 
2359
  __ push(rdx);  // receiver
 
2360
  __ Push(Handle<AccessorInfo>(callback));  // callback info
 
2361
  __ push(rcx);  // name
 
2362
  __ push(rax);  // value
 
2363
  __ push(rbx);  // restore return address
 
2364
 
 
2365
  // Do tail-call to the runtime system.
 
2366
  ExternalReference store_callback_property =
 
2367
      ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
 
2368
  __ TailCallExternalReference(store_callback_property, 4, 1);
 
2369
 
 
2370
  // Handle store cache miss.
 
2371
  __ bind(&miss);
 
2372
  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
 
2373
  __ Jump(ic, RelocInfo::CODE_TARGET);
1476
2374
 
1477
2375
  // Return the generated code.
1478
2376
  return GetCode(CALLBACKS, name);
1479
2377
}
1480
2378
 
1481
2379
 
1482
 
Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1483
 
                                              JSObject* holder,
1484
 
                                              Object* value,
1485
 
                                              String* name) {
1486
 
  // ----------- S t a t e -------------
1487
 
  //  -- rax    : receiver
1488
 
  //  -- rcx    : name
1489
 
  //  -- rsp[0] : return address
1490
 
  // -----------------------------------
1491
 
  Label miss;
1492
 
 
1493
 
  GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss);
1494
 
  __ bind(&miss);
1495
 
  GenerateLoadMiss(masm(), Code::LOAD_IC);
1496
 
 
1497
 
  // Return the generated code.
1498
 
  return GetCode(CONSTANT_FUNCTION, name);
1499
 
}
1500
 
 
1501
 
 
1502
 
Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1503
 
                                                 JSObject* object,
1504
 
                                                 JSObject* last) {
 
2380
MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
 
2381
                                                        String* name) {
 
2382
  // ----------- S t a t e -------------
 
2383
  //  -- rax    : value
 
2384
  //  -- rcx    : name
 
2385
  //  -- rdx    : receiver
 
2386
  //  -- rsp[0] : return address
 
2387
  // -----------------------------------
 
2388
  Label miss;
 
2389
 
 
2390
  // Check that the object isn't a smi.
 
2391
  __ JumpIfSmi(rdx, &miss);
 
2392
 
 
2393
  // Check that the map of the object hasn't changed.
 
2394
  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
 
2395
         Handle<Map>(receiver->map()));
 
2396
  __ j(not_equal, &miss);
 
2397
 
 
2398
  // Perform global security token check if needed.
 
2399
  if (receiver->IsJSGlobalProxy()) {
 
2400
    __ CheckAccessGlobalProxy(rdx, rbx, &miss);
 
2401
  }
 
2402
 
 
2403
  // Stub never generated for non-global objects that require access
 
2404
  // checks.
 
2405
  ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
 
2406
 
 
2407
  __ pop(rbx);  // remove the return address
 
2408
  __ push(rdx);  // receiver
 
2409
  __ push(rcx);  // name
 
2410
  __ push(rax);  // value
 
2411
  __ Push(Smi::FromInt(strict_mode_));
 
2412
  __ push(rbx);  // restore return address
 
2413
 
 
2414
  // Do tail-call to the runtime system.
 
2415
  ExternalReference store_ic_property =
 
2416
      ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
 
2417
  __ TailCallExternalReference(store_ic_property, 4, 1);
 
2418
 
 
2419
  // Handle store cache miss.
 
2420
  __ bind(&miss);
 
2421
  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
 
2422
  __ Jump(ic, RelocInfo::CODE_TARGET);
 
2423
 
 
2424
  // Return the generated code.
 
2425
  return GetCode(INTERCEPTOR, name);
 
2426
}
 
2427
 
 
2428
 
 
2429
MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
 
2430
                                                   JSGlobalPropertyCell* cell,
 
2431
                                                   String* name) {
 
2432
  // ----------- S t a t e -------------
 
2433
  //  -- rax    : value
 
2434
  //  -- rcx    : name
 
2435
  //  -- rdx    : receiver
 
2436
  //  -- rsp[0] : return address
 
2437
  // -----------------------------------
 
2438
  Label miss;
 
2439
 
 
2440
  // Check that the map of the global has not changed.
 
2441
  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
 
2442
         Handle<Map>(object->map()));
 
2443
  __ j(not_equal, &miss);
 
2444
 
 
2445
  // Check that the value in the cell is not the hole. If it is, this
 
2446
  // cell could have been deleted and reintroducing the global needs
 
2447
  // to update the property details in the property dictionary of the
 
2448
  // global object. We bail out to the runtime system to do that.
 
2449
  __ Move(rbx, Handle<JSGlobalPropertyCell>(cell));
 
2450
  __ CompareRoot(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
 
2451
                 Heap::kTheHoleValueRootIndex);
 
2452
  __ j(equal, &miss);
 
2453
 
 
2454
  // Store the value in the cell.
 
2455
  __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rax);
 
2456
 
 
2457
  // Return the value (register rax).
 
2458
  __ IncrementCounter(&Counters::named_store_global_inline, 1);
 
2459
  __ ret(0);
 
2460
 
 
2461
  // Handle store cache miss.
 
2462
  __ bind(&miss);
 
2463
  __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
 
2464
  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
 
2465
  __ Jump(ic, RelocInfo::CODE_TARGET);
 
2466
 
 
2467
  // Return the generated code.
 
2468
  return GetCode(NORMAL, name);
 
2469
}
 
2470
 
 
2471
 
 
2472
MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
 
2473
                                                       int index,
 
2474
                                                       Map* transition,
 
2475
                                                       String* name) {
 
2476
  // ----------- S t a t e -------------
 
2477
  //  -- rax     : value
 
2478
  //  -- rcx     : key
 
2479
  //  -- rdx     : receiver
 
2480
  //  -- rsp[0]  : return address
 
2481
  // -----------------------------------
 
2482
  Label miss;
 
2483
 
 
2484
  __ IncrementCounter(&Counters::keyed_store_field, 1);
 
2485
 
 
2486
  // Check that the name has not changed.
 
2487
  __ Cmp(rcx, Handle<String>(name));
 
2488
  __ j(not_equal, &miss);
 
2489
 
 
2490
  // Generate store field code.  Preserves receiver and name on jump to miss.
 
2491
  GenerateStoreField(masm(),
 
2492
                     object,
 
2493
                     index,
 
2494
                     transition,
 
2495
                     rdx, rcx, rbx,
 
2496
                     &miss);
 
2497
 
 
2498
  // Handle store cache miss.
 
2499
  __ bind(&miss);
 
2500
  __ DecrementCounter(&Counters::keyed_store_field, 1);
 
2501
  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
 
2502
  __ Jump(ic, RelocInfo::CODE_TARGET);
 
2503
 
 
2504
  // Return the generated code.
 
2505
  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
 
2506
}
 
2507
 
 
2508
 
 
2509
MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
 
2510
    JSObject* receiver) {
 
2511
  // ----------- S t a t e -------------
 
2512
  //  -- rax    : value
 
2513
  //  -- rcx    : key
 
2514
  //  -- rdx    : receiver
 
2515
  //  -- rsp[0] : return address
 
2516
  // -----------------------------------
 
2517
  Label miss;
 
2518
 
 
2519
  // Check that the receiver isn't a smi.
 
2520
  __ JumpIfSmi(rdx, &miss);
 
2521
 
 
2522
  // Check that the map matches.
 
2523
  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
 
2524
         Handle<Map>(receiver->map()));
 
2525
  __ j(not_equal, &miss);
 
2526
 
 
2527
  // Check that the key is a smi.
 
2528
  __ JumpIfNotSmi(rcx, &miss);
 
2529
 
 
2530
  // Get the elements array and make sure it is a fast element array, not 'cow'.
 
2531
  __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
 
2532
  __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
 
2533
         Factory::fixed_array_map());
 
2534
  __ j(not_equal, &miss);
 
2535
 
 
2536
  // Check that the key is within bounds.
 
2537
  if (receiver->IsJSArray()) {
 
2538
    __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
 
2539
    __ j(above_equal, &miss);
 
2540
  } else {
 
2541
    __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
 
2542
    __ j(above_equal, &miss);
 
2543
  }
 
2544
 
 
2545
  // Do the store and update the write barrier. Make sure to preserve
 
2546
  // the value in register eax.
 
2547
  __ movq(rdx, rax);
 
2548
  __ SmiToInteger32(rcx, rcx);
 
2549
  __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
 
2550
          rax);
 
2551
  __ RecordWrite(rdi, 0, rdx, rcx);
 
2552
 
 
2553
  // Done.
 
2554
  __ ret(0);
 
2555
 
 
2556
  // Handle store cache miss.
 
2557
  __ bind(&miss);
 
2558
  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
 
2559
  __ jmp(ic, RelocInfo::CODE_TARGET);
 
2560
 
 
2561
  // Return the generated code.
 
2562
  return GetCode(NORMAL, NULL);
 
2563
}
 
2564
 
 
2565
 
 
2566
MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray(
 
2567
    JSObject* receiver) {
 
2568
  // ----------- S t a t e -------------
 
2569
  //  -- rax    : value
 
2570
  //  -- rcx    : key
 
2571
  //  -- rdx    : receiver
 
2572
  //  -- rsp[0] : return address
 
2573
  // -----------------------------------
 
2574
  Label miss;
 
2575
 
 
2576
  // Check that the map matches.
 
2577
  __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false);
 
2578
 
 
2579
  // Do the load.
 
2580
  GenerateFastPixelArrayStore(masm(),
 
2581
                              rdx,
 
2582
                              rcx,
 
2583
                              rax,
 
2584
                              rdi,
 
2585
                              rbx,
 
2586
                              true,
 
2587
                              false,
 
2588
                              &miss,
 
2589
                              &miss,
 
2590
                              NULL,
 
2591
                              &miss);
 
2592
 
 
2593
  // Handle store cache miss.
 
2594
  __ bind(&miss);
 
2595
  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
 
2596
  __ jmp(ic, RelocInfo::CODE_TARGET);
 
2597
 
 
2598
  // Return the generated code.
 
2599
  return GetCode(NORMAL, NULL);
 
2600
}
 
2601
 
 
2602
 
 
2603
MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
 
2604
                                                      JSObject* object,
 
2605
                                                      JSObject* last) {
1505
2606
  // ----------- S t a t e -------------
1506
2607
  //  -- rax    : receiver
1507
2608
  //  -- rcx    : name
1520
2621
  // If the last object in the prototype chain is a global object,
1521
2622
  // check that the global property cell is empty.
1522
2623
  if (last->IsGlobalObject()) {
1523
 
    Object* cell = GenerateCheckPropertyCell(masm(),
1524
 
                                             GlobalObject::cast(last),
1525
 
                                             name,
1526
 
                                             rdx,
1527
 
                                             &miss);
1528
 
    if (cell->IsFailure()) return cell;
 
2624
    MaybeObject* cell = GenerateCheckPropertyCell(masm(),
 
2625
                                                  GlobalObject::cast(last),
 
2626
                                                  name,
 
2627
                                                  rdx,
 
2628
                                                  &miss);
 
2629
    if (cell->IsFailure()) {
 
2630
      miss.Unuse();
 
2631
      return cell;
 
2632
    }
1529
2633
  }
1530
2634
 
1531
2635
  // Return undefined if maps of the full prototype chain are still the
1541
2645
}
1542
2646
 
1543
2647
 
1544
 
Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1545
 
                                           JSObject* holder,
1546
 
                                           int index,
1547
 
                                           String* name) {
 
2648
MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
 
2649
                                                JSObject* holder,
 
2650
                                                int index,
 
2651
                                                String* name) {
1548
2652
  // ----------- S t a t e -------------
1549
2653
  //  -- rax    : receiver
1550
2654
  //  -- rcx    : name
1561
2665
}
1562
2666
 
1563
2667
 
1564
 
Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1565
 
                                                 JSObject* holder,
1566
 
                                                 String* name) {
 
2668
MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
 
2669
                                                   JSObject* object,
 
2670
                                                   JSObject* holder,
 
2671
                                                   AccessorInfo* callback) {
 
2672
  // ----------- S t a t e -------------
 
2673
  //  -- rax    : receiver
 
2674
  //  -- rcx    : name
 
2675
  //  -- rsp[0] : return address
 
2676
  // -----------------------------------
 
2677
  Label miss;
 
2678
 
 
2679
  MaybeObject* result = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx,
 
2680
                                             rdi, callback, name, &miss);
 
2681
  if (result->IsFailure()) {
 
2682
    miss.Unuse();
 
2683
    return result;
 
2684
  }
 
2685
 
 
2686
  __ bind(&miss);
 
2687
  GenerateLoadMiss(masm(), Code::LOAD_IC);
 
2688
 
 
2689
  // Return the generated code.
 
2690
  return GetCode(CALLBACKS, name);
 
2691
}
 
2692
 
 
2693
 
 
2694
MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
 
2695
                                                   JSObject* holder,
 
2696
                                                   Object* value,
 
2697
                                                   String* name) {
 
2698
  // ----------- S t a t e -------------
 
2699
  //  -- rax    : receiver
 
2700
  //  -- rcx    : name
 
2701
  //  -- rsp[0] : return address
 
2702
  // -----------------------------------
 
2703
  Label miss;
 
2704
 
 
2705
  GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss);
 
2706
  __ bind(&miss);
 
2707
  GenerateLoadMiss(masm(), Code::LOAD_IC);
 
2708
 
 
2709
  // Return the generated code.
 
2710
  return GetCode(CONSTANT_FUNCTION, name);
 
2711
}
 
2712
 
 
2713
 
 
2714
MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
 
2715
                                                      JSObject* holder,
 
2716
                                                      String* name) {
1567
2717
  // ----------- S t a t e -------------
1568
2718
  //  -- rax    : receiver
1569
2719
  //  -- rcx    : name
1595
2745
}
1596
2746
 
1597
2747
 
1598
 
Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1599
 
                                            GlobalObject* holder,
1600
 
                                            JSGlobalPropertyCell* cell,
1601
 
                                            String* name,
1602
 
                                            bool is_dont_delete) {
 
2748
MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
 
2749
                                                 GlobalObject* holder,
 
2750
                                                 JSGlobalPropertyCell* cell,
 
2751
                                                 String* name,
 
2752
                                                 bool is_dont_delete) {
1603
2753
  // ----------- S t a t e -------------
1604
2754
  //  -- rax    : receiver
1605
2755
  //  -- rcx    : name
1630
2780
    __ Check(not_equal, "DontDelete cells can't contain the hole");
1631
2781
  }
1632
2782
 
1633
 
  __ IncrementCounter(&Counters::named_load_global_inline, 1);
 
2783
  __ IncrementCounter(&Counters::named_load_global_stub, 1);
1634
2784
  __ movq(rax, rbx);
1635
2785
  __ ret(0);
1636
2786
 
1637
2787
  __ bind(&miss);
1638
 
  __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
 
2788
  __ IncrementCounter(&Counters::named_load_global_stub_miss, 1);
1639
2789
  GenerateLoadMiss(masm(), Code::LOAD_IC);
1640
2790
 
1641
2791
  // Return the generated code.
1643
2793
}
1644
2794
 
1645
2795
 
1646
 
Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1647
 
                                                   JSObject* receiver,
1648
 
                                                   JSObject* holder,
1649
 
                                                   AccessorInfo* callback) {
 
2796
MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
 
2797
                                                     JSObject* receiver,
 
2798
                                                     JSObject* holder,
 
2799
                                                     int index) {
 
2800
  // ----------- S t a t e -------------
 
2801
  //  -- rax     : key
 
2802
  //  -- rdx     : receiver
 
2803
  //  -- rsp[0]  : return address
 
2804
  // -----------------------------------
 
2805
  Label miss;
 
2806
 
 
2807
  __ IncrementCounter(&Counters::keyed_load_field, 1);
 
2808
 
 
2809
  // Check that the name has not changed.
 
2810
  __ Cmp(rax, Handle<String>(name));
 
2811
  __ j(not_equal, &miss);
 
2812
 
 
2813
  GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
 
2814
 
 
2815
  __ bind(&miss);
 
2816
  __ DecrementCounter(&Counters::keyed_load_field, 1);
 
2817
  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
 
2818
 
 
2819
  // Return the generated code.
 
2820
  return GetCode(FIELD, name);
 
2821
}
 
2822
 
 
2823
 
 
2824
MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
 
2825
    String* name,
 
2826
    JSObject* receiver,
 
2827
    JSObject* holder,
 
2828
    AccessorInfo* callback) {
1650
2829
  // ----------- S t a t e -------------
1651
2830
  //  -- rax     : key
1652
2831
  //  -- rdx     : receiver
1660
2839
  __ Cmp(rax, Handle<String>(name));
1661
2840
  __ j(not_equal, &miss);
1662
2841
 
1663
 
  Failure* failure = Failure::InternalError();
1664
 
  bool success = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi,
1665
 
                                      callback, name, &miss, &failure);
1666
 
  if (!success) return failure;
 
2842
  MaybeObject* result = GenerateLoadCallback(receiver, holder, rdx, rax, rbx,
 
2843
                                             rcx, rdi, callback, name, &miss);
 
2844
  if (result->IsFailure()) {
 
2845
    miss.Unuse();
 
2846
    return result;
 
2847
  }
1667
2848
 
1668
2849
  __ bind(&miss);
 
2850
 
1669
2851
  __ DecrementCounter(&Counters::keyed_load_callback, 1);
1670
2852
  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1671
2853
 
1674
2856
}
1675
2857
 
1676
2858
 
1677
 
Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1678
 
  // ----------- S t a t e -------------
1679
 
  //  -- rax    : key
1680
 
  //  -- rdx    : receiver
1681
 
  //  -- rsp[0]  : return address
1682
 
  // -----------------------------------
1683
 
  Label miss;
1684
 
 
1685
 
  __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1686
 
 
1687
 
  // Check that the name has not changed.
1688
 
  __ Cmp(rax, Handle<String>(name));
1689
 
  __ j(not_equal, &miss);
1690
 
 
1691
 
  GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
1692
 
  __ bind(&miss);
1693
 
  __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1694
 
  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1695
 
 
1696
 
  // Return the generated code.
1697
 
  return GetCode(CALLBACKS, name);
1698
 
}
1699
 
 
1700
 
 
1701
 
Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1702
 
                                                   JSObject* receiver,
1703
 
                                                   JSObject* holder,
1704
 
                                                   Object* value) {
 
2859
MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
 
2860
                                                        JSObject* receiver,
 
2861
                                                        JSObject* holder,
 
2862
                                                        Object* value) {
1705
2863
  // ----------- S t a t e -------------
1706
2864
  //  -- rax    : key
1707
2865
  //  -- rdx    : receiver
1726
2884
}
1727
2885
 
1728
2886
 
1729
 
Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1730
 
  // ----------- S t a t e -------------
1731
 
  //  -- rax    : key
1732
 
  //  -- rdx    : receiver
1733
 
  //  -- rsp[0]  : return address
1734
 
  // -----------------------------------
1735
 
  Label miss;
1736
 
 
1737
 
  __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1738
 
 
1739
 
  // Check that the name has not changed.
1740
 
  __ Cmp(rax, Handle<String>(name));
1741
 
  __ j(not_equal, &miss);
1742
 
 
1743
 
  GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
1744
 
  __ bind(&miss);
1745
 
  __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1746
 
  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1747
 
 
1748
 
  // Return the generated code.
1749
 
  return GetCode(CALLBACKS, name);
1750
 
}
1751
 
 
1752
 
 
1753
 
Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1754
 
                                                      JSObject* holder,
1755
 
                                                      String* name) {
 
2887
MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
 
2888
                                                           JSObject* holder,
 
2889
                                                           String* name) {
1756
2890
  // ----------- S t a t e -------------
1757
2891
  //  -- rax    : key
1758
2892
  //  -- rdx    : receiver
1787
2921
}
1788
2922
 
1789
2923
 
1790
 
Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
 
2924
MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
 
2925
  // ----------- S t a t e -------------
 
2926
  //  -- rax    : key
 
2927
  //  -- rdx    : receiver
 
2928
  //  -- rsp[0]  : return address
 
2929
  // -----------------------------------
 
2930
  Label miss;
 
2931
 
 
2932
  __ IncrementCounter(&Counters::keyed_load_array_length, 1);
 
2933
 
 
2934
  // Check that the name has not changed.
 
2935
  __ Cmp(rax, Handle<String>(name));
 
2936
  __ j(not_equal, &miss);
 
2937
 
 
2938
  GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
 
2939
  __ bind(&miss);
 
2940
  __ DecrementCounter(&Counters::keyed_load_array_length, 1);
 
2941
  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
 
2942
 
 
2943
  // Return the generated code.
 
2944
  return GetCode(CALLBACKS, name);
 
2945
}
 
2946
 
 
2947
 
 
2948
MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
1791
2949
  // ----------- S t a t e -------------
1792
2950
  //  -- rax    : key
1793
2951
  //  -- rdx    : receiver
1801
2959
  __ Cmp(rax, Handle<String>(name));
1802
2960
  __ j(not_equal, &miss);
1803
2961
 
1804
 
  GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss);
 
2962
  GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true);
1805
2963
  __ bind(&miss);
1806
2964
  __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1807
2965
  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1811
2969
}
1812
2970
 
1813
2971
 
1814
 
Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1815
 
                                                AccessorInfo* callback,
1816
 
                                                String* name) {
 
2972
MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1817
2973
  // ----------- S t a t e -------------
1818
 
  //  -- rax    : value
1819
 
  //  -- rcx    : name
 
2974
  //  -- rax    : key
1820
2975
  //  -- rdx    : receiver
1821
 
  //  -- rsp[0] : return address
 
2976
  //  -- rsp[0]  : return address
1822
2977
  // -----------------------------------
1823
2978
  Label miss;
1824
2979
 
1825
 
  // Check that the object isn't a smi.
1826
 
  __ JumpIfSmi(rdx, &miss);
 
2980
  __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1827
2981
 
1828
 
  // Check that the map of the object hasn't changed.
1829
 
  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
1830
 
         Handle<Map>(object->map()));
 
2982
  // Check that the name has not changed.
 
2983
  __ Cmp(rax, Handle<String>(name));
1831
2984
  __ j(not_equal, &miss);
1832
2985
 
1833
 
  // Perform global security token check if needed.
1834
 
  if (object->IsJSGlobalProxy()) {
1835
 
    __ CheckAccessGlobalProxy(rdx, rbx, &miss);
1836
 
  }
1837
 
 
1838
 
  // Stub never generated for non-global objects that require access
1839
 
  // checks.
1840
 
  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1841
 
 
1842
 
  __ pop(rbx);  // remove the return address
1843
 
  __ push(rdx);  // receiver
1844
 
  __ Push(Handle<AccessorInfo>(callback));  // callback info
1845
 
  __ push(rcx);  // name
1846
 
  __ push(rax);  // value
1847
 
  __ push(rbx);  // restore return address
1848
 
 
1849
 
  // Do tail-call to the runtime system.
1850
 
  ExternalReference store_callback_property =
1851
 
      ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
1852
 
  __ TailCallExternalReference(store_callback_property, 4, 1);
1853
 
 
1854
 
  // Handle store cache miss.
 
2986
  GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
1855
2987
  __ bind(&miss);
1856
 
  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1857
 
  __ Jump(ic, RelocInfo::CODE_TARGET);
 
2988
  __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
 
2989
  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1858
2990
 
1859
2991
  // Return the generated code.
1860
2992
  return GetCode(CALLBACKS, name);
1861
2993
}
1862
2994
 
1863
2995
 
1864
 
Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1865
 
                                             int index,
1866
 
                                             Map* transition,
1867
 
                                             String* name) {
1868
 
  // ----------- S t a t e -------------
1869
 
  //  -- rax    : value
1870
 
  //  -- rcx    : name
1871
 
  //  -- rdx    : receiver
1872
 
  //  -- rsp[0] : return address
1873
 
  // -----------------------------------
1874
 
  Label miss;
1875
 
 
1876
 
  // Generate store field code.  Preserves receiver and name on jump to miss.
1877
 
  GenerateStoreField(masm(),
1878
 
                     object,
1879
 
                     index,
1880
 
                     transition,
1881
 
                     rdx, rcx, rbx,
1882
 
                     &miss);
1883
 
 
1884
 
  // Handle store cache miss.
1885
 
  __ bind(&miss);
1886
 
  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1887
 
  __ Jump(ic, RelocInfo::CODE_TARGET);
1888
 
 
1889
 
  // Return the generated code.
1890
 
  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1891
 
}
1892
 
 
1893
 
 
1894
 
Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1895
 
                                                   String* name) {
1896
 
  // ----------- S t a t e -------------
1897
 
  //  -- rax    : value
1898
 
  //  -- rcx    : name
1899
 
  //  -- rdx    : receiver
1900
 
  //  -- rsp[0] : return address
1901
 
  // -----------------------------------
1902
 
  Label miss;
1903
 
 
1904
 
  // Check that the object isn't a smi.
 
2996
MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
 
2997
  // ----------- S t a t e -------------
 
2998
  //  -- rax    : key
 
2999
  //  -- rdx    : receiver
 
3000
  //  -- esp[0] : return address
 
3001
  // -----------------------------------
 
3002
  Label miss;
 
3003
 
 
3004
  // Check that the receiver isn't a smi.
1905
3005
  __ JumpIfSmi(rdx, &miss);
1906
3006
 
1907
 
  // Check that the map of the object hasn't changed.
 
3007
  // Check that the map matches.
1908
3008
  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
1909
3009
         Handle<Map>(receiver->map()));
1910
3010
  __ j(not_equal, &miss);
1911
3011
 
1912
 
  // Perform global security token check if needed.
1913
 
  if (receiver->IsJSGlobalProxy()) {
1914
 
    __ CheckAccessGlobalProxy(rdx, rbx, &miss);
1915
 
  }
1916
 
 
1917
 
  // Stub never generated for non-global objects that require access
1918
 
  // checks.
1919
 
  ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1920
 
 
1921
 
  __ pop(rbx);  // remove the return address
1922
 
  __ push(rdx);  // receiver
1923
 
  __ push(rcx);  // name
1924
 
  __ push(rax);  // value
1925
 
  __ push(rbx);  // restore return address
1926
 
 
1927
 
  // Do tail-call to the runtime system.
1928
 
  ExternalReference store_ic_property =
1929
 
      ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
1930
 
  __ TailCallExternalReference(store_ic_property, 3, 1);
1931
 
 
1932
 
  // Handle store cache miss.
 
3012
  // Check that the key is a smi.
 
3013
  __ JumpIfNotSmi(rax, &miss);
 
3014
 
 
3015
  // Get the elements array.
 
3016
  __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
 
3017
  __ AssertFastElements(rcx);
 
3018
 
 
3019
  // Check that the key is within bounds.
 
3020
  __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
 
3021
  __ j(above_equal, &miss);
 
3022
 
 
3023
  // Load the result and make sure it's not the hole.
 
3024
  SmiIndex index = masm()->SmiToIndex(rbx, rax, kPointerSizeLog2);
 
3025
  __ movq(rbx, FieldOperand(rcx,
 
3026
                            index.reg,
 
3027
                            index.scale,
 
3028
                            FixedArray::kHeaderSize));
 
3029
  __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
 
3030
  __ j(equal, &miss);
 
3031
  __ movq(rax, rbx);
 
3032
  __ ret(0);
 
3033
 
1933
3034
  __ bind(&miss);
1934
 
  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1935
 
  __ Jump(ic, RelocInfo::CODE_TARGET);
 
3035
  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1936
3036
 
1937
3037
  // Return the generated code.
1938
 
  return GetCode(INTERCEPTOR, name);
 
3038
  return GetCode(NORMAL, NULL);
1939
3039
}
1940
3040
 
1941
3041
 
1942
 
Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1943
 
                                              JSGlobalPropertyCell* cell,
1944
 
                                              String* name) {
 
3042
MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) {
1945
3043
  // ----------- S t a t e -------------
1946
 
  //  -- rax    : value
1947
 
  //  -- rcx    : name
 
3044
  //  -- rax    : key
1948
3045
  //  -- rdx    : receiver
1949
 
  //  -- rsp[0] : return address
1950
 
  // -----------------------------------
1951
 
  Label miss;
1952
 
 
1953
 
  // Check that the map of the global has not changed.
1954
 
  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
1955
 
         Handle<Map>(object->map()));
1956
 
  __ j(not_equal, &miss);
1957
 
 
1958
 
  // Store the value in the cell.
1959
 
  __ Move(rcx, Handle<JSGlobalPropertyCell>(cell));
1960
 
  __ movq(FieldOperand(rcx, JSGlobalPropertyCell::kValueOffset), rax);
1961
 
 
1962
 
  // Return the value (register rax).
1963
 
  __ IncrementCounter(&Counters::named_store_global_inline, 1);
1964
 
  __ ret(0);
1965
 
 
1966
 
  // Handle store cache miss.
1967
 
  __ bind(&miss);
1968
 
  __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
1969
 
  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1970
 
  __ Jump(ic, RelocInfo::CODE_TARGET);
1971
 
 
1972
 
  // Return the generated code.
1973
 
  return GetCode(NORMAL, name);
1974
 
}
1975
 
 
1976
 
 
1977
 
Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1978
 
                                                JSObject* receiver,
1979
 
                                                JSObject* holder,
1980
 
                                                int index) {
1981
 
  // ----------- S t a t e -------------
1982
 
  //  -- rax     : key
1983
 
  //  -- rdx     : receiver
1984
 
  //  -- rsp[0]  : return address
1985
 
  // -----------------------------------
1986
 
  Label miss;
1987
 
 
1988
 
  __ IncrementCounter(&Counters::keyed_load_field, 1);
1989
 
 
1990
 
  // Check that the name has not changed.
1991
 
  __ Cmp(rax, Handle<String>(name));
1992
 
  __ j(not_equal, &miss);
1993
 
 
1994
 
  GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
1995
 
 
1996
 
  __ bind(&miss);
1997
 
  __ DecrementCounter(&Counters::keyed_load_field, 1);
 
3046
  //  -- esp[0] : return address
 
3047
  // -----------------------------------
 
3048
  Label miss;
 
3049
 
 
3050
  // Check that the map matches.
 
3051
  __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false);
 
3052
 
 
3053
  GenerateFastPixelArrayLoad(masm(),
 
3054
                             rdx,
 
3055
                             rax,
 
3056
                             rbx,
 
3057
                             rcx,
 
3058
                             rax,
 
3059
                             &miss,
 
3060
                             &miss,
 
3061
                             &miss);
 
3062
 
 
3063
  __ bind(&miss);
1998
3064
  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1999
3065
 
2000
3066
  // Return the generated code.
2001
 
  return GetCode(FIELD, name);
2002
 
}
2003
 
 
2004
 
 
2005
 
Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2006
 
                                                  int index,
2007
 
                                                  Map* transition,
2008
 
                                                  String* name) {
2009
 
  // ----------- S t a t e -------------
2010
 
  //  -- rax     : value
2011
 
  //  -- rcx     : key
2012
 
  //  -- rdx     : receiver
2013
 
  //  -- rsp[0]  : return address
2014
 
  // -----------------------------------
2015
 
  Label miss;
2016
 
 
2017
 
  __ IncrementCounter(&Counters::keyed_store_field, 1);
2018
 
 
2019
 
  // Check that the name has not changed.
2020
 
  __ Cmp(rcx, Handle<String>(name));
2021
 
  __ j(not_equal, &miss);
2022
 
 
2023
 
  // Generate store field code.  Preserves receiver and name on jump to miss.
2024
 
  GenerateStoreField(masm(),
2025
 
                     object,
2026
 
                     index,
2027
 
                     transition,
2028
 
                     rdx, rcx, rbx,
2029
 
                     &miss);
2030
 
 
2031
 
  // Handle store cache miss.
2032
 
  __ bind(&miss);
2033
 
  __ DecrementCounter(&Counters::keyed_store_field, 1);
2034
 
  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
2035
 
  __ Jump(ic, RelocInfo::CODE_TARGET);
2036
 
 
2037
 
  // Return the generated code.
2038
 
  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2039
 
}
2040
 
 
2041
 
 
2042
 
void StubCompiler::GenerateLoadInterceptor(JSObject* object,
2043
 
                                           JSObject* interceptor_holder,
2044
 
                                           LookupResult* lookup,
2045
 
                                           Register receiver,
2046
 
                                           Register name_reg,
2047
 
                                           Register scratch1,
2048
 
                                           Register scratch2,
2049
 
                                           Register scratch3,
2050
 
                                           String* name,
2051
 
                                           Label* miss) {
2052
 
  ASSERT(interceptor_holder->HasNamedInterceptor());
2053
 
  ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
2054
 
 
2055
 
  // Check that the receiver isn't a smi.
2056
 
  __ JumpIfSmi(receiver, miss);
2057
 
 
2058
 
  // So far the most popular follow ups for interceptor loads are FIELD
2059
 
  // and CALLBACKS, so inline only them, other cases may be added
2060
 
  // later.
2061
 
  bool compile_followup_inline = false;
2062
 
  if (lookup->IsProperty() && lookup->IsCacheable()) {
2063
 
    if (lookup->type() == FIELD) {
2064
 
      compile_followup_inline = true;
2065
 
    } else if (lookup->type() == CALLBACKS &&
2066
 
        lookup->GetCallbackObject()->IsAccessorInfo() &&
2067
 
        AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
2068
 
      compile_followup_inline = true;
2069
 
    }
2070
 
  }
2071
 
 
2072
 
  if (compile_followup_inline) {
2073
 
    // Compile the interceptor call, followed by inline code to load the
2074
 
    // property from further up the prototype chain if the call fails.
2075
 
    // Check that the maps haven't changed.
2076
 
    Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
2077
 
                                          scratch1, scratch2, scratch3,
2078
 
                                          name, miss);
2079
 
    ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
2080
 
 
2081
 
    // Save necessary data before invoking an interceptor.
2082
 
    // Requires a frame to make GC aware of pushed pointers.
2083
 
    __ EnterInternalFrame();
2084
 
 
2085
 
    if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
2086
 
      // CALLBACKS case needs a receiver to be passed into C++ callback.
2087
 
      __ push(receiver);
2088
 
    }
2089
 
    __ push(holder_reg);
2090
 
    __ push(name_reg);
2091
 
 
2092
 
    // Invoke an interceptor.  Note: map checks from receiver to
2093
 
    // interceptor's holder has been compiled before (see a caller
2094
 
    // of this method.)
2095
 
    CompileCallLoadPropertyWithInterceptor(masm(),
2096
 
                                           receiver,
2097
 
                                           holder_reg,
2098
 
                                           name_reg,
2099
 
                                           interceptor_holder);
2100
 
 
2101
 
    // Check if interceptor provided a value for property.  If it's
2102
 
    // the case, return immediately.
2103
 
    Label interceptor_failed;
2104
 
    __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
2105
 
    __ j(equal, &interceptor_failed);
2106
 
    __ LeaveInternalFrame();
2107
 
    __ ret(0);
2108
 
 
2109
 
    __ bind(&interceptor_failed);
2110
 
    __ pop(name_reg);
2111
 
    __ pop(holder_reg);
2112
 
    if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
2113
 
      __ pop(receiver);
2114
 
    }
2115
 
 
2116
 
    __ LeaveInternalFrame();
2117
 
 
2118
 
    // Check that the maps from interceptor's holder to lookup's holder
2119
 
    // haven't changed.  And load lookup's holder into |holder| register.
2120
 
    if (interceptor_holder != lookup->holder()) {
2121
 
      holder_reg = CheckPrototypes(interceptor_holder,
2122
 
                                   holder_reg,
2123
 
                                   lookup->holder(),
2124
 
                                   scratch1,
2125
 
                                   scratch2,
2126
 
                                   scratch3,
2127
 
                                   name,
2128
 
                                   miss);
2129
 
    }
2130
 
 
2131
 
    if (lookup->type() == FIELD) {
2132
 
      // We found FIELD property in prototype chain of interceptor's holder.
2133
 
      // Retrieve a field from field's holder.
2134
 
      GenerateFastPropertyLoad(masm(), rax, holder_reg,
2135
 
                               lookup->holder(), lookup->GetFieldIndex());
2136
 
      __ ret(0);
2137
 
    } else {
2138
 
      // We found CALLBACKS property in prototype chain of interceptor's
2139
 
      // holder.
2140
 
      ASSERT(lookup->type() == CALLBACKS);
2141
 
      ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
2142
 
      AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
2143
 
      ASSERT(callback != NULL);
2144
 
      ASSERT(callback->getter() != NULL);
2145
 
 
2146
 
      // Tail call to runtime.
2147
 
      // Important invariant in CALLBACKS case: the code above must be
2148
 
      // structured to never clobber |receiver| register.
2149
 
      __ pop(scratch2);  // return address
2150
 
      __ push(receiver);
2151
 
      __ push(holder_reg);
2152
 
      __ Move(holder_reg, Handle<AccessorInfo>(callback));
2153
 
      __ push(holder_reg);
2154
 
      __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
2155
 
      __ push(name_reg);
2156
 
      __ push(scratch2);  // restore return address
2157
 
 
2158
 
      ExternalReference ref =
2159
 
          ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
2160
 
      __ TailCallExternalReference(ref, 5, 1);
2161
 
    }
2162
 
  } else {  // !compile_followup_inline
2163
 
    // Call the runtime system to load the interceptor.
2164
 
    // Check that the maps haven't changed.
2165
 
    Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
2166
 
                                          scratch1, scratch2, scratch3,
2167
 
                                          name, miss);
2168
 
    __ pop(scratch2);  // save old return address
2169
 
    PushInterceptorArguments(masm(), receiver, holder_reg,
2170
 
                             name_reg, interceptor_holder);
2171
 
    __ push(scratch2);  // restore old return address
2172
 
 
2173
 
    ExternalReference ref = ExternalReference(
2174
 
        IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
2175
 
    __ TailCallExternalReference(ref, 5, 1);
2176
 
  }
2177
 
}
2178
 
 
2179
 
 
2180
 
bool StubCompiler::GenerateLoadCallback(JSObject* object,
2181
 
                                        JSObject* holder,
2182
 
                                        Register receiver,
2183
 
                                        Register name_reg,
2184
 
                                        Register scratch1,
2185
 
                                        Register scratch2,
2186
 
                                        Register scratch3,
2187
 
                                        AccessorInfo* callback,
2188
 
                                        String* name,
2189
 
                                        Label* miss,
2190
 
                                        Failure** failure) {
2191
 
  // Check that the receiver isn't a smi.
2192
 
  __ JumpIfSmi(receiver, miss);
2193
 
 
2194
 
  // Check that the maps haven't changed.
2195
 
  Register reg =
2196
 
      CheckPrototypes(object, receiver, holder, scratch1,
2197
 
                      scratch2, scratch3, name, miss);
2198
 
 
2199
 
  Handle<AccessorInfo> callback_handle(callback);
2200
 
 
2201
 
  __ EnterInternalFrame();
2202
 
  __ PushHandleScope(scratch2);
2203
 
  // Push the stack address where the list of arguments ends.
2204
 
  __ movq(scratch2, rsp);
2205
 
  __ subq(scratch2, Immediate(2 * kPointerSize));
2206
 
  __ push(scratch2);
2207
 
  __ push(receiver);  // receiver
2208
 
  __ push(reg);  // holder
2209
 
  if (Heap::InNewSpace(callback_handle->data())) {
2210
 
    __ Move(scratch2, callback_handle);
2211
 
    __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset));  // data
2212
 
  } else {
2213
 
    __ Push(Handle<Object>(callback_handle->data()));
2214
 
  }
2215
 
  __ push(name_reg);  // name
2216
 
  // Save a pointer to where we pushed the arguments pointer.
2217
 
  // This will be passed as the const AccessorInfo& to the C++ callback.
2218
 
 
2219
 
#ifdef _WIN64
2220
 
  // Win64 uses first register--rcx--for returned value.
2221
 
  Register accessor_info_arg = r8;
2222
 
  Register name_arg = rdx;
2223
 
#else
2224
 
  Register accessor_info_arg = rdx;  // temporary, copied to rsi by the stub.
2225
 
  Register name_arg = rdi;
2226
 
#endif
2227
 
 
2228
 
  __ movq(accessor_info_arg, rsp);
2229
 
  __ addq(accessor_info_arg, Immediate(4 * kPointerSize));
2230
 
  __ movq(name_arg, rsp);
2231
 
 
2232
 
  // Do call through the api.
2233
 
  ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace);
2234
 
  Address getter_address = v8::ToCData<Address>(callback->getter());
2235
 
  ApiFunction fun(getter_address);
2236
 
  ApiGetterEntryStub stub(callback_handle, &fun);
2237
 
#ifdef _WIN64
2238
 
  // We need to prepare a slot for result handle on stack and put
2239
 
  // a pointer to it into 1st arg register.
2240
 
  __ push(Immediate(0));
2241
 
  __ movq(rcx, rsp);
2242
 
#endif
2243
 
  // Emitting a stub call may try to allocate (if the code is not
2244
 
  // already generated).  Do not allow the assembler to perform a
2245
 
  // garbage collection but instead return the allocation failure
2246
 
  // object.
2247
 
  Object* result = masm()->TryCallStub(&stub);
2248
 
  if (result->IsFailure()) {
2249
 
    *failure = Failure::cast(result);
2250
 
    return false;
2251
 
  }
2252
 
#ifdef _WIN64
2253
 
  // Discard allocated slot.
2254
 
  __ addq(rsp, Immediate(kPointerSize));
2255
 
#endif
2256
 
 
2257
 
  // We need to avoid using rax since that now holds the result.
2258
 
  Register tmp = scratch2.is(rax) ? reg : scratch2;
2259
 
  // Emitting PopHandleScope may try to allocate.  Do not allow the
2260
 
  // assembler to perform a garbage collection but instead return a
2261
 
  // failure object.
2262
 
  result = masm()->TryPopHandleScope(rax, tmp);
2263
 
  if (result->IsFailure()) {
2264
 
    *failure = Failure::cast(result);
2265
 
    return false;
2266
 
  }
2267
 
  __ LeaveInternalFrame();
2268
 
 
2269
 
  __ ret(0);
2270
 
 
2271
 
  return true;
2272
 
}
2273
 
 
2274
 
 
2275
 
Register StubCompiler::CheckPrototypes(JSObject* object,
2276
 
                                       Register object_reg,
2277
 
                                       JSObject* holder,
2278
 
                                       Register holder_reg,
2279
 
                                       Register scratch1,
2280
 
                                       Register scratch2,
2281
 
                                       String* name,
2282
 
                                       int save_at_depth,
2283
 
                                       Label* miss) {
2284
 
  // Make sure there's no overlap between holder and object registers.
2285
 
  ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
2286
 
  ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
2287
 
         && !scratch2.is(scratch1));
2288
 
 
2289
 
  // Keep track of the current object in register reg.  On the first
2290
 
  // iteration, reg is an alias for object_reg, on later iterations,
2291
 
  // it is an alias for holder_reg.
2292
 
  Register reg = object_reg;
2293
 
  int depth = 0;
2294
 
 
2295
 
  if (save_at_depth == depth) {
2296
 
    __ movq(Operand(rsp, kPointerSize), object_reg);
2297
 
  }
2298
 
 
2299
 
  // Check the maps in the prototype chain.
2300
 
  // Traverse the prototype chain from the object and do map checks.
2301
 
  JSObject* current = object;
2302
 
  while (current != holder) {
2303
 
    depth++;
2304
 
 
2305
 
    // Only global objects and objects that do not require access
2306
 
    // checks are allowed in stubs.
2307
 
    ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
2308
 
 
2309
 
    JSObject* prototype = JSObject::cast(current->GetPrototype());
2310
 
    if (!current->HasFastProperties() &&
2311
 
        !current->IsJSGlobalObject() &&
2312
 
        !current->IsJSGlobalProxy()) {
2313
 
      if (!name->IsSymbol()) {
2314
 
        Object* lookup_result = Heap::LookupSymbol(name);
2315
 
        if (lookup_result->IsFailure()) {
2316
 
          set_failure(Failure::cast(lookup_result));
2317
 
          return reg;
2318
 
        } else {
2319
 
          name = String::cast(lookup_result);
2320
 
        }
2321
 
      }
2322
 
      ASSERT(current->property_dictionary()->FindEntry(name) ==
2323
 
             StringDictionary::kNotFound);
2324
 
 
2325
 
      GenerateDictionaryNegativeLookup(masm(),
2326
 
                                       miss,
2327
 
                                       reg,
2328
 
                                       name,
2329
 
                                       scratch1,
2330
 
                                       scratch2);
2331
 
      __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
2332
 
      reg = holder_reg;  // from now the object is in holder_reg
2333
 
      __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
2334
 
    } else if (Heap::InNewSpace(prototype)) {
2335
 
      // Get the map of the current object.
2336
 
      __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
2337
 
      __ Cmp(scratch1, Handle<Map>(current->map()));
2338
 
      // Branch on the result of the map check.
2339
 
      __ j(not_equal, miss);
2340
 
      // Check access rights to the global object.  This has to happen
2341
 
      // after the map check so that we know that the object is
2342
 
      // actually a global object.
2343
 
      if (current->IsJSGlobalProxy()) {
2344
 
        __ CheckAccessGlobalProxy(reg, scratch1, miss);
2345
 
 
2346
 
        // Restore scratch register to be the map of the object.
2347
 
        // We load the prototype from the map in the scratch register.
2348
 
        __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
2349
 
      }
2350
 
      // The prototype is in new space; we cannot store a reference
2351
 
      // to it in the code. Load it from the map.
2352
 
      reg = holder_reg;  // from now the object is in holder_reg
2353
 
      __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
2354
 
 
2355
 
    } else {
2356
 
      // Check the map of the current object.
2357
 
      __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
2358
 
          Handle<Map>(current->map()));
2359
 
      // Branch on the result of the map check.
2360
 
      __ j(not_equal, miss);
2361
 
      // Check access rights to the global object.  This has to happen
2362
 
      // after the map check so that we know that the object is
2363
 
      // actually a global object.
2364
 
      if (current->IsJSGlobalProxy()) {
2365
 
        __ CheckAccessGlobalProxy(reg, scratch1, miss);
2366
 
      }
2367
 
      // The prototype is in old space; load it directly.
2368
 
      reg = holder_reg;  // from now the object is in holder_reg
2369
 
      __ Move(reg, Handle<JSObject>(prototype));
2370
 
    }
2371
 
 
2372
 
    if (save_at_depth == depth) {
2373
 
      __ movq(Operand(rsp, kPointerSize), reg);
2374
 
    }
2375
 
 
2376
 
    // Go to the next object in the prototype chain.
2377
 
    current = prototype;
2378
 
  }
2379
 
 
2380
 
  // Check the holder map.
2381
 
  __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
2382
 
  __ j(not_equal, miss);
2383
 
 
2384
 
  // Log the check depth.
2385
 
  LOG(IntEvent("check-maps-depth", depth + 1));
2386
 
 
2387
 
  // Perform security check for access to the global object and return
2388
 
  // the holder register.
2389
 
  ASSERT(current == holder);
2390
 
  ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
2391
 
  if (current->IsJSGlobalProxy()) {
2392
 
    __ CheckAccessGlobalProxy(reg, scratch1, miss);
2393
 
  }
2394
 
 
2395
 
  // If we've skipped any global objects, it's not enough to verify
2396
 
  // that their maps haven't changed.  We also need to check that the
2397
 
  // property cell for the property is still empty.
2398
 
  current = object;
2399
 
  while (current != holder) {
2400
 
    if (current->IsGlobalObject()) {
2401
 
      Object* cell = GenerateCheckPropertyCell(masm(),
2402
 
                                               GlobalObject::cast(current),
2403
 
                                               name,
2404
 
                                               scratch1,
2405
 
                                               miss);
2406
 
      if (cell->IsFailure()) {
2407
 
        set_failure(Failure::cast(cell));
2408
 
        return reg;
2409
 
      }
2410
 
    }
2411
 
    current = JSObject::cast(current->GetPrototype());
2412
 
  }
2413
 
 
2414
 
  // Return the register containing the holder.
2415
 
  return reg;
2416
 
}
2417
 
 
2418
 
 
2419
 
void StubCompiler::GenerateLoadField(JSObject* object,
2420
 
                                     JSObject* holder,
2421
 
                                     Register receiver,
2422
 
                                     Register scratch1,
2423
 
                                     Register scratch2,
2424
 
                                     Register scratch3,
2425
 
                                     int index,
2426
 
                                     String* name,
2427
 
                                     Label* miss) {
2428
 
  // Check that the receiver isn't a smi.
2429
 
  __ JumpIfSmi(receiver, miss);
2430
 
 
2431
 
  // Check the prototype chain.
2432
 
  Register reg =
2433
 
      CheckPrototypes(object, receiver, holder,
2434
 
                      scratch1, scratch2, scratch3, name, miss);
2435
 
 
2436
 
  // Get the value from the properties.
2437
 
  GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
2438
 
  __ ret(0);
2439
 
}
2440
 
 
2441
 
 
2442
 
void StubCompiler::GenerateLoadConstant(JSObject* object,
2443
 
                                        JSObject* holder,
2444
 
                                        Register receiver,
2445
 
                                        Register scratch1,
2446
 
                                        Register scratch2,
2447
 
                                        Register scratch3,
2448
 
                                        Object* value,
2449
 
                                        String* name,
2450
 
                                        Label* miss) {
2451
 
  // Check that the receiver isn't a smi.
2452
 
  __ JumpIfSmi(receiver, miss);
2453
 
 
2454
 
  // Check that the maps haven't changed.
2455
 
  Register reg =
2456
 
      CheckPrototypes(object, receiver, holder,
2457
 
                      scratch1, scratch2, scratch3, name, miss);
2458
 
 
2459
 
  // Return the constant value.
2460
 
  __ Move(rax, Handle<Object>(value));
2461
 
  __ ret(0);
 
3067
  return GetCode(NORMAL, NULL);
2462
3068
}
2463
3069
 
2464
3070
 
2465
3071
// Specialized stub for constructing objects from functions which only have only
2466
3072
// simple assignments of the form this.x = ...; in their body.
2467
 
Object* ConstructStubCompiler::CompileConstructStub(
2468
 
    SharedFunctionInfo* shared) {
 
3073
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
2469
3074
  // ----------- S t a t e -------------
2470
3075
  //  -- rax : argc
2471
3076
  //  -- rdi : constructor
2538
3143
  // r9: first in-object property of the JSObject
2539
3144
  // Fill the initialized properties with a constant value or a passed argument
2540
3145
  // depending on the this.x = ...; assignment in the function.
 
3146
  SharedFunctionInfo* shared = function->shared();
2541
3147
  for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2542
3148
    if (shared->IsThisPropertyAssignmentArgument(i)) {
2543
3149
      // Check if the argument assigned to the property is actually passed.
2557
3163
  }
2558
3164
 
2559
3165
  // Fill the unused in-object property fields with undefined.
 
3166
  ASSERT(function->has_initial_map());
2560
3167
  for (int i = shared->this_property_assignments_count();
2561
 
       i < shared->CalculateInObjectProperties();
 
3168
       i < function->initial_map()->inobject_properties();
2562
3169
       i++) {
2563
3170
    __ movq(Operand(r9, i * kPointerSize), r8);
2564
3171
  }
2592
3199
}
2593
3200
 
2594
3201
 
 
3202
MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
 
3203
    ExternalArrayType array_type, Code::Flags flags) {
 
3204
  // ----------- S t a t e -------------
 
3205
  //  -- rax    : key
 
3206
  //  -- rdx    : receiver
 
3207
  //  -- rsp[0] : return address
 
3208
  // -----------------------------------
 
3209
  Label slow;
 
3210
 
 
3211
  // Check that the object isn't a smi.
 
3212
  __ JumpIfSmi(rdx, &slow);
 
3213
 
 
3214
  // Check that the key is a smi.
 
3215
  __ JumpIfNotSmi(rax, &slow);
 
3216
 
 
3217
  // Check that the object is a JS object.
 
3218
  __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
 
3219
  __ j(not_equal, &slow);
 
3220
  // Check that the receiver does not require access checks.  We need
 
3221
  // to check this explicitly since this generic stub does not perform
 
3222
  // map checks.  The map is already in rdx.
 
3223
  __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
 
3224
           Immediate(1 << Map::kIsAccessCheckNeeded));
 
3225
  __ j(not_zero, &slow);
 
3226
 
 
3227
  // Check that the elements array is the appropriate type of
 
3228
  // ExternalArray.
 
3229
  // rax: index (as a smi)
 
3230
  // rdx: JSObject
 
3231
  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
 
3232
  __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
 
3233
                 Heap::RootIndexForExternalArrayType(array_type));
 
3234
  __ j(not_equal, &slow);
 
3235
 
 
3236
  // Check that the index is in range.
 
3237
  __ SmiToInteger32(rcx, rax);
 
3238
  __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
 
3239
  // Unsigned comparison catches both negative and too-large values.
 
3240
  __ j(above_equal, &slow);
 
3241
 
 
3242
  // rax: index (as a smi)
 
3243
  // rdx: receiver (JSObject)
 
3244
  // rcx: untagged index
 
3245
  // rbx: elements array
 
3246
  __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
 
3247
  // rbx: base pointer of external storage
 
3248
  switch (array_type) {
 
3249
    case kExternalByteArray:
 
3250
      __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
 
3251
      break;
 
3252
    case kExternalUnsignedByteArray:
 
3253
      __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
 
3254
      break;
 
3255
    case kExternalShortArray:
 
3256
      __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0));
 
3257
      break;
 
3258
    case kExternalUnsignedShortArray:
 
3259
      __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0));
 
3260
      break;
 
3261
    case kExternalIntArray:
 
3262
      __ movsxlq(rcx, Operand(rbx, rcx, times_4, 0));
 
3263
      break;
 
3264
    case kExternalUnsignedIntArray:
 
3265
      __ movl(rcx, Operand(rbx, rcx, times_4, 0));
 
3266
      break;
 
3267
    case kExternalFloatArray:
 
3268
      __ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0));
 
3269
      break;
 
3270
    default:
 
3271
      UNREACHABLE();
 
3272
      break;
 
3273
  }
 
3274
 
 
3275
  // rax: index
 
3276
  // rdx: receiver
 
3277
  // For integer array types:
 
3278
  // rcx: value
 
3279
  // For floating-point array type:
 
3280
  // xmm0: value as double.
 
3281
 
 
3282
  ASSERT(kSmiValueSize == 32);
 
3283
  if (array_type == kExternalUnsignedIntArray) {
 
3284
    // For the UnsignedInt array type, we need to see whether
 
3285
    // the value can be represented in a Smi. If not, we need to convert
 
3286
    // it to a HeapNumber.
 
3287
    NearLabel box_int;
 
3288
 
 
3289
    __ JumpIfUIntNotValidSmiValue(rcx, &box_int);
 
3290
 
 
3291
    __ Integer32ToSmi(rax, rcx);
 
3292
    __ ret(0);
 
3293
 
 
3294
    __ bind(&box_int);
 
3295
 
 
3296
    // Allocate a HeapNumber for the int and perform int-to-double
 
3297
    // conversion.
 
3298
    // The value is zero-extended since we loaded the value from memory
 
3299
    // with movl.
 
3300
    __ cvtqsi2sd(xmm0, rcx);
 
3301
 
 
3302
    __ AllocateHeapNumber(rcx, rbx, &slow);
 
3303
    // Set the value.
 
3304
    __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
 
3305
    __ movq(rax, rcx);
 
3306
    __ ret(0);
 
3307
  } else if (array_type == kExternalFloatArray) {
 
3308
    // For the floating-point array type, we need to always allocate a
 
3309
    // HeapNumber.
 
3310
    __ AllocateHeapNumber(rcx, rbx, &slow);
 
3311
    // Set the value.
 
3312
    __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
 
3313
    __ movq(rax, rcx);
 
3314
    __ ret(0);
 
3315
  } else {
 
3316
    __ Integer32ToSmi(rax, rcx);
 
3317
    __ ret(0);
 
3318
  }
 
3319
 
 
3320
  // Slow case: Jump to runtime.
 
3321
  __ bind(&slow);
 
3322
  __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
 
3323
 
 
3324
  // ----------- S t a t e -------------
 
3325
  //  -- rax    : key
 
3326
  //  -- rdx    : receiver
 
3327
  //  -- rsp[0]  : return address
 
3328
  // -----------------------------------
 
3329
 
 
3330
  __ pop(rbx);
 
3331
  __ push(rdx);  // receiver
 
3332
  __ push(rax);  // name
 
3333
  __ push(rbx);  // return address
 
3334
 
 
3335
  // Perform tail call to the entry.
 
3336
  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
 
3337
 
 
3338
  // Return the generated code.
 
3339
  return GetCode(flags);
 
3340
}
 
3341
 
 
3342
 
 
3343
MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
 
3344
    ExternalArrayType array_type, Code::Flags flags) {
 
3345
  // ----------- S t a t e -------------
 
3346
  //  -- rax     : value
 
3347
  //  -- rcx     : key
 
3348
  //  -- rdx     : receiver
 
3349
  //  -- rsp[0]  : return address
 
3350
  // -----------------------------------
 
3351
  Label slow;
 
3352
 
 
3353
  // Check that the object isn't a smi.
 
3354
  __ JumpIfSmi(rdx, &slow);
 
3355
  // Get the map from the receiver.
 
3356
  __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
 
3357
  // Check that the receiver does not require access checks.  We need
 
3358
  // to do this because this generic stub does not perform map checks.
 
3359
  __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
 
3360
           Immediate(1 << Map::kIsAccessCheckNeeded));
 
3361
  __ j(not_zero, &slow);
 
3362
  // Check that the key is a smi.
 
3363
  __ JumpIfNotSmi(rcx, &slow);
 
3364
 
 
3365
  // Check that the object is a JS object.
 
3366
  __ CmpInstanceType(rbx, JS_OBJECT_TYPE);
 
3367
  __ j(not_equal, &slow);
 
3368
 
 
3369
  // Check that the elements array is the appropriate type of
 
3370
  // ExternalArray.
 
3371
  // rax: value
 
3372
  // rcx: key (a smi)
 
3373
  // rdx: receiver (a JSObject)
 
3374
  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
 
3375
  __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
 
3376
                 Heap::RootIndexForExternalArrayType(array_type));
 
3377
  __ j(not_equal, &slow);
 
3378
 
 
3379
  // Check that the index is in range.
 
3380
  __ SmiToInteger32(rdi, rcx);  // Untag the index.
 
3381
  __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset));
 
3382
  // Unsigned comparison catches both negative and too-large values.
 
3383
  __ j(above_equal, &slow);
 
3384
 
 
3385
  // Handle both smis and HeapNumbers in the fast path. Go to the
 
3386
  // runtime for all other kinds of values.
 
3387
  // rax: value
 
3388
  // rcx: key (a smi)
 
3389
  // rdx: receiver (a JSObject)
 
3390
  // rbx: elements array
 
3391
  // rdi: untagged key
 
3392
  NearLabel check_heap_number;
 
3393
  __ JumpIfNotSmi(rax, &check_heap_number);
 
3394
  // No more branches to slow case on this path.  Key and receiver not needed.
 
3395
  __ SmiToInteger32(rdx, rax);
 
3396
  __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
 
3397
  // rbx: base pointer of external storage
 
3398
  switch (array_type) {
 
3399
    case kExternalByteArray:
 
3400
    case kExternalUnsignedByteArray:
 
3401
      __ movb(Operand(rbx, rdi, times_1, 0), rdx);
 
3402
      break;
 
3403
    case kExternalShortArray:
 
3404
    case kExternalUnsignedShortArray:
 
3405
      __ movw(Operand(rbx, rdi, times_2, 0), rdx);
 
3406
      break;
 
3407
    case kExternalIntArray:
 
3408
    case kExternalUnsignedIntArray:
 
3409
      __ movl(Operand(rbx, rdi, times_4, 0), rdx);
 
3410
      break;
 
3411
    case kExternalFloatArray:
 
3412
      // Need to perform int-to-float conversion.
 
3413
      __ cvtlsi2ss(xmm0, rdx);
 
3414
      __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
 
3415
      break;
 
3416
    default:
 
3417
      UNREACHABLE();
 
3418
      break;
 
3419
  }
 
3420
  __ ret(0);
 
3421
 
 
3422
  __ bind(&check_heap_number);
 
3423
  // rax: value
 
3424
  // rcx: key (a smi)
 
3425
  // rdx: receiver (a JSObject)
 
3426
  // rbx: elements array
 
3427
  // rdi: untagged key
 
3428
  __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
 
3429
  __ j(not_equal, &slow);
 
3430
  // No more branches to slow case on this path.
 
3431
 
 
3432
  // The WebGL specification leaves the behavior of storing NaN and
 
3433
  // +/-Infinity into integer arrays basically undefined. For more
 
3434
  // reproducible behavior, convert these to zero.
 
3435
  __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
 
3436
  __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
 
3437
  // rdi: untagged index
 
3438
  // rbx: base pointer of external storage
 
3439
  // top of FPU stack: value
 
3440
  if (array_type == kExternalFloatArray) {
 
3441
    __ cvtsd2ss(xmm0, xmm0);
 
3442
    __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
 
3443
    __ ret(0);
 
3444
  } else {
 
3445
    // Perform float-to-int conversion with truncation (round-to-zero)
 
3446
    // behavior.
 
3447
 
 
3448
    // Convert to int32 and store the low byte/word.
 
3449
    // If the value is NaN or +/-infinity, the result is 0x80000000,
 
3450
    // which is automatically zero when taken mod 2^n, n < 32.
 
3451
    // rdx: value (converted to an untagged integer)
 
3452
    // rdi: untagged index
 
3453
    // rbx: base pointer of external storage
 
3454
    switch (array_type) {
 
3455
      case kExternalByteArray:
 
3456
      case kExternalUnsignedByteArray:
 
3457
        __ cvttsd2si(rdx, xmm0);
 
3458
        __ movb(Operand(rbx, rdi, times_1, 0), rdx);
 
3459
        break;
 
3460
      case kExternalShortArray:
 
3461
      case kExternalUnsignedShortArray:
 
3462
        __ cvttsd2si(rdx, xmm0);
 
3463
        __ movw(Operand(rbx, rdi, times_2, 0), rdx);
 
3464
        break;
 
3465
      case kExternalIntArray:
 
3466
      case kExternalUnsignedIntArray: {
 
3467
        // Convert to int64, so that NaN and infinities become
 
3468
        // 0x8000000000000000, which is zero mod 2^32.
 
3469
        __ cvttsd2siq(rdx, xmm0);
 
3470
        __ movl(Operand(rbx, rdi, times_4, 0), rdx);
 
3471
        break;
 
3472
      }
 
3473
      default:
 
3474
        UNREACHABLE();
 
3475
        break;
 
3476
    }
 
3477
    __ ret(0);
 
3478
  }
 
3479
 
 
3480
  // Slow case: call runtime.
 
3481
  __ bind(&slow);
 
3482
 
 
3483
  // ----------- S t a t e -------------
 
3484
  //  -- rax     : value
 
3485
  //  -- rcx     : key
 
3486
  //  -- rdx     : receiver
 
3487
  //  -- rsp[0]  : return address
 
3488
  // -----------------------------------
 
3489
 
 
3490
  __ pop(rbx);
 
3491
  __ push(rdx);  // receiver
 
3492
  __ push(rcx);  // key
 
3493
  __ push(rax);  // value
 
3494
  __ Push(Smi::FromInt(NONE));   // PropertyAttributes
 
3495
  __ Push(Smi::FromInt(
 
3496
      Code::ExtractExtraICStateFromFlags(flags) & kStrictMode));
 
3497
  __ push(rbx);  // return address
 
3498
 
 
3499
  // Do tail-call to runtime routine.
 
3500
  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
 
3501
 
 
3502
  return GetCode(flags);
 
3503
}
 
3504
 
2595
3505
#undef __
2596
3506
 
2597
3507
} }  // namespace v8::internal