485d87dc5790552ccda5161646650c9df29d7beb
[platform/upstream/nodejs.git] / deps / v8 / src / ic / x64 / handler-compiler-x64.cc
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #if V8_TARGET_ARCH_X64
8
9 #include "src/ic/call-optimization.h"
10 #include "src/ic/handler-compiler.h"
11 #include "src/ic/ic.h"
12
13 namespace v8 {
14 namespace internal {
15
16 #define __ ACCESS_MASM(masm)
17
18 void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
19                                                 Register slot) {
20   MacroAssembler* masm = this->masm();
21   __ Push(vector);
22   __ Push(slot);
23 }
24
25
26 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
27   MacroAssembler* masm = this->masm();
28   __ Pop(slot);
29   __ Pop(vector);
30 }
31
32
33 void PropertyHandlerCompiler::DiscardVectorAndSlot() {
34   MacroAssembler* masm = this->masm();
35   // Remove vector and slot.
36   __ addp(rsp, Immediate(2 * kPointerSize));
37 }
38
39
40 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
41     MacroAssembler* masm, Label* miss_label, Register receiver,
42     Handle<Name> name, Register scratch0, Register scratch1) {
43   DCHECK(name->IsUniqueName());
44   DCHECK(!receiver.is(scratch0));
45   Counters* counters = masm->isolate()->counters();
46   __ IncrementCounter(counters->negative_lookups(), 1);
47   __ IncrementCounter(counters->negative_lookups_miss(), 1);
48
49   __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
50
51   const int kInterceptorOrAccessCheckNeededMask =
52       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
53
54   // Bail out if the receiver has a named interceptor or requires access checks.
55   __ testb(FieldOperand(scratch0, Map::kBitFieldOffset),
56            Immediate(kInterceptorOrAccessCheckNeededMask));
57   __ j(not_zero, miss_label);
58
59   // Check that receiver is a JSObject.
60   __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
61   __ j(below, miss_label);
62
63   // Load properties array.
64   Register properties = scratch0;
65   __ movp(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
66
67   // Check that the properties array is a dictionary.
68   __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
69                  Heap::kHashTableMapRootIndex);
70   __ j(not_equal, miss_label);
71
72   Label done;
73   NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
74                                                    properties, name, scratch1);
75   __ bind(&done);
76   __ DecrementCounter(counters->negative_lookups_miss(), 1);
77 }
78
79
80 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
81     MacroAssembler* masm, int index, Register result, Label* miss) {
82   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
83   __ movp(result, Operand(rsi, offset));
84   __ movp(result, FieldOperand(result, GlobalObject::kNativeContextOffset));
85   __ movp(result, Operand(result, Context::SlotOffset(index)));
86   // Load its initial map. The global functions all have initial maps.
87   __ movp(result,
88           FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
89   // Load the prototype from the initial map.
90   __ movp(result, FieldOperand(result, Map::kPrototypeOffset));
91 }
92
93
94 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
95     MacroAssembler* masm, Register receiver, Register result, Register scratch,
96     Label* miss_label) {
97   __ TryGetFunctionPrototype(receiver, result, miss_label);
98   if (!result.is(rax)) __ movp(rax, result);
99   __ ret(0);
100 }
101
102
103 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
104                                      Register holder, Register name,
105                                      Handle<JSObject> holder_obj) {
106   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
107   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
108   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
109   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
110   __ Push(name);
111   __ Push(receiver);
112   __ Push(holder);
113 }
114
115
116 static void CompileCallLoadPropertyWithInterceptor(
117     MacroAssembler* masm, Register receiver, Register holder, Register name,
118     Handle<JSObject> holder_obj, IC::UtilityId id) {
119   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
120   __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()),
121                            NamedLoadHandlerCompiler::kInterceptorArgsLength);
122 }
123
124
125 // Generate call to api function.
126 void PropertyHandlerCompiler::GenerateApiAccessorCall(
127     MacroAssembler* masm, const CallOptimization& optimization,
128     Handle<Map> receiver_map, Register receiver, Register scratch,
129     bool is_store, Register store_parameter, Register accessor_holder,
130     int accessor_index) {
131   DCHECK(!accessor_holder.is(scratch));
132   DCHECK(optimization.is_simple_api_call());
133
134   __ PopReturnAddressTo(scratch);
135   // receiver
136   __ Push(receiver);
137   // Write the arguments to stack frame.
138   if (is_store) {
139     DCHECK(!receiver.is(store_parameter));
140     DCHECK(!scratch.is(store_parameter));
141     __ Push(store_parameter);
142   }
143   __ PushReturnAddressFrom(scratch);
144   // Stack now matches JSFunction abi.
145
146   // Abi for CallApiFunctionStub.
147   Register callee = rdi;
148   Register data = rbx;
149   Register holder = rcx;
150   Register api_function_address = rdx;
151   scratch = no_reg;
152
153   // Put callee in place.
154   __ LoadAccessor(callee, accessor_holder, accessor_index,
155                   is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
156
157   // Put holder in place.
158   CallOptimization::HolderLookup holder_lookup;
159   int holder_depth = 0;
160   optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
161                                           &holder_depth);
162   switch (holder_lookup) {
163     case CallOptimization::kHolderIsReceiver:
164       __ Move(holder, receiver);
165       break;
166     case CallOptimization::kHolderFound:
167       __ movp(holder, FieldOperand(receiver, HeapObject::kMapOffset));
168       __ movp(holder, FieldOperand(holder, Map::kPrototypeOffset));
169       for (int i = 1; i < holder_depth; i++) {
170         __ movp(holder, FieldOperand(holder, HeapObject::kMapOffset));
171         __ movp(holder, FieldOperand(holder, Map::kPrototypeOffset));
172       }
173       break;
174     case CallOptimization::kHolderNotFound:
175       UNREACHABLE();
176       break;
177   }
178
179   Isolate* isolate = masm->isolate();
180   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
181   bool call_data_undefined = false;
182   // Put call data in place.
183   if (api_call_info->data()->IsUndefined()) {
184     call_data_undefined = true;
185     __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
186   } else {
187     __ movp(data, FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
188     __ movp(data, FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
189     __ movp(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
190     __ movp(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
191   }
192
193   // Put api_function_address in place.
194   Address function_address = v8::ToCData<Address>(api_call_info->callback());
195   __ Move(api_function_address, function_address,
196           RelocInfo::EXTERNAL_REFERENCE);
197
198   // Jump to stub.
199   CallApiAccessorStub stub(isolate, is_store, call_data_undefined);
200   __ TailCallStub(&stub);
201 }
202
203
204 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
205     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
206     Register scratch, Label* miss) {
207   Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
208   DCHECK(cell->value()->IsTheHole());
209   Factory* factory = masm->isolate()->factory();
210   Handle<WeakCell> weak_cell = factory->NewWeakCell(cell);
211   __ LoadWeakValue(scratch, weak_cell, miss);
212   __ Cmp(FieldOperand(scratch, Cell::kValueOffset), factory->the_hole_value());
213   __ j(not_equal, miss);
214 }
215
216
217 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
218     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
219     int accessor_index, int expected_arguments, Register scratch) {
220   // ----------- S t a t e -------------
221   //  -- rsp[0] : return address
222   // -----------------------------------
223   {
224     FrameScope scope(masm, StackFrame::INTERNAL);
225
226     // Save value register, so we can restore it later.
227     __ Push(value());
228
229     if (accessor_index >= 0) {
230       DCHECK(!holder.is(scratch));
231       DCHECK(!receiver.is(scratch));
232       DCHECK(!value().is(scratch));
233       // Call the JavaScript setter with receiver and value on the stack.
234       if (map->IsJSGlobalObjectMap()) {
235         // Swap in the global receiver.
236         __ movp(scratch,
237                 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
238         receiver = scratch;
239       }
240       __ Push(receiver);
241       __ Push(value());
242       ParameterCount actual(1);
243       ParameterCount expected(expected_arguments);
244       __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_SETTER);
245       __ InvokeFunction(rdi, expected, actual, CALL_FUNCTION,
246                         NullCallWrapper());
247     } else {
248       // If we generate a global code snippet for deoptimization only, remember
249       // the place to continue after deoptimization.
250       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
251     }
252
253     // We have to return the passed value, not the return value of the setter.
254     __ Pop(rax);
255
256     // Restore context register.
257     __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
258   }
259   __ ret(0);
260 }
261
262
263 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
264     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
265     int accessor_index, int expected_arguments, Register scratch) {
266   // ----------- S t a t e -------------
267   //  -- rax    : receiver
268   //  -- rcx    : name
269   //  -- rsp[0] : return address
270   // -----------------------------------
271   {
272     FrameScope scope(masm, StackFrame::INTERNAL);
273
274     if (accessor_index >= 0) {
275       DCHECK(!holder.is(scratch));
276       DCHECK(!receiver.is(scratch));
277       // Call the JavaScript getter with the receiver on the stack.
278       if (map->IsJSGlobalObjectMap()) {
279         // Swap in the global receiver.
280         __ movp(scratch,
281                 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
282         receiver = scratch;
283       }
284       __ Push(receiver);
285       ParameterCount actual(0);
286       ParameterCount expected(expected_arguments);
287       __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_GETTER);
288       __ InvokeFunction(rdi, expected, actual, CALL_FUNCTION,
289                         NullCallWrapper());
290     } else {
291       // If we generate a global code snippet for deoptimization only, remember
292       // the place to continue after deoptimization.
293       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
294     }
295
296     // Restore context register.
297     __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
298   }
299   __ ret(0);
300 }
301
302
303 static void StoreIC_PushArgs(MacroAssembler* masm) {
304   Register receiver = StoreDescriptor::ReceiverRegister();
305   Register name = StoreDescriptor::NameRegister();
306   Register value = StoreDescriptor::ValueRegister();
307
308   DCHECK(!rbx.is(receiver) && !rbx.is(name) && !rbx.is(value));
309
310   __ PopReturnAddressTo(rbx);
311   __ Push(receiver);
312   __ Push(name);
313   __ Push(value);
314   __ PushReturnAddressFrom(rbx);
315 }
316
317
318 void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
319   // Return address is on the stack.
320   StoreIC_PushArgs(masm);
321
322   // Do tail-call to runtime routine.
323   ExternalReference ref(IC_Utility(IC::kStoreIC_Slow), masm->isolate());
324   __ TailCallExternalReference(ref, 3, 1);
325 }
326
327
328 void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
329   // Return address is on the stack.
330   StoreIC_PushArgs(masm);
331
332   // Do tail-call to runtime routine.
333   ExternalReference ref(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate());
334   __ TailCallExternalReference(ref, 3, 1);
335 }
336
337
338 #undef __
339 #define __ ACCESS_MASM((masm()))
340
341
342 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
343                                                     Handle<Name> name) {
344   if (!label->is_unused()) {
345     __ bind(label);
346     __ Move(this->name(), name);
347   }
348 }
349
350
351 void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
352   __ Move(this->name(), name);
353 }
354
355
356 void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
357                                                    Register scratch,
358                                                    Label* miss) {
359   Handle<WeakCell> cell = Map::WeakCellForMap(transition);
360   Register map_reg = StoreTransitionDescriptor::MapRegister();
361   DCHECK(!map_reg.is(scratch));
362   __ LoadWeakValue(map_reg, cell, miss);
363   if (transition->CanBeDeprecated()) {
364     __ movl(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
365     __ andl(scratch, Immediate(Map::Deprecated::kMask));
366     __ j(not_zero, miss);
367   }
368 }
369
370
371 void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
372                                                       int descriptor,
373                                                       Register value_reg,
374                                                       Register scratch,
375                                                       Label* miss_label) {
376   DCHECK(!map_reg.is(scratch));
377   DCHECK(!map_reg.is(value_reg));
378   DCHECK(!value_reg.is(scratch));
379   __ LoadInstanceDescriptors(map_reg, scratch);
380   __ movp(scratch,
381           FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
382   __ cmpp(value_reg, scratch);
383   __ j(not_equal, miss_label);
384 }
385
386
387 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
388                                                         Register value_reg,
389                                                         Label* miss_label) {
390   Register map_reg = scratch1();
391   Register scratch = scratch2();
392   DCHECK(!value_reg.is(map_reg));
393   DCHECK(!value_reg.is(scratch));
394   __ JumpIfSmi(value_reg, miss_label);
395   HeapType::Iterator<Map> it = field_type->Classes();
396   if (!it.Done()) {
397     Label do_store;
398     __ movp(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
399     while (true) {
400       __ CmpWeakValue(map_reg, Map::WeakCellForMap(it.Current()), scratch);
401       it.Advance();
402       if (it.Done()) {
403         __ j(not_equal, miss_label);
404         break;
405       }
406       __ j(equal, &do_store, Label::kNear);
407     }
408     __ bind(&do_store);
409   }
410 }
411
412
413 Register PropertyHandlerCompiler::CheckPrototypes(
414     Register object_reg, Register holder_reg, Register scratch1,
415     Register scratch2, Handle<Name> name, Label* miss,
416     PrototypeCheckType check) {
417   Handle<Map> receiver_map = map();
418
419   // Make sure there's no overlap between holder and object registers.
420   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
421   DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
422          !scratch2.is(scratch1));
423
424   // Keep track of the current object in register reg.  On the first
425   // iteration, reg is an alias for object_reg, on later iterations,
426   // it is an alias for holder_reg.
427   Register reg = object_reg;
428   int depth = 0;
429
430   Handle<JSObject> current = Handle<JSObject>::null();
431   if (receiver_map->IsJSGlobalObjectMap()) {
432     current = isolate()->global_object();
433   }
434   Handle<JSObject> prototype = Handle<JSObject>::null();
435   Handle<Map> current_map = receiver_map;
436   Handle<Map> holder_map(holder()->map());
437   // Traverse the prototype chain and check the maps in the prototype chain for
438   // fast and global objects or do negative lookup for normal objects.
439   while (!current_map.is_identical_to(holder_map)) {
440     ++depth;
441
442     // Only global objects and objects that do not require access
443     // checks are allowed in stubs.
444     DCHECK(current_map->IsJSGlobalProxyMap() ||
445            !current_map->is_access_check_needed());
446
447     prototype = handle(JSObject::cast(current_map->prototype()));
448     if (current_map->is_dictionary_map() &&
449         !current_map->IsJSGlobalObjectMap()) {
450       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
451       if (!name->IsUniqueName()) {
452         DCHECK(name->IsString());
453         name = factory()->InternalizeString(Handle<String>::cast(name));
454       }
455       DCHECK(current.is_null() ||
456              current->property_dictionary()->FindEntry(name) ==
457                  NameDictionary::kNotFound);
458
459       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
460                                        scratch2);
461
462       __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
463       reg = holder_reg;  // From now on the object will be in holder_reg.
464       __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
465     } else {
466       Register map_reg = scratch1;
467       __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
468
469       if (depth != 1 || check == CHECK_ALL_MAPS) {
470         Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
471         __ CmpWeakValue(map_reg, cell, scratch2);
472         __ j(not_equal, miss);
473       }
474
475       // Check access rights to the global object.  This has to happen after
476       // the map check so that we know that the object is actually a global
477       // object.
478       // This allows us to install generated handlers for accesses to the
479       // global proxy (as opposed to using slow ICs). See corresponding code
480       // in LookupForRead().
481       if (current_map->IsJSGlobalProxyMap()) {
482         __ CheckAccessGlobalProxy(reg, scratch2, miss);
483       } else if (current_map->IsJSGlobalObjectMap()) {
484         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
485                                   name, scratch2, miss);
486       }
487       reg = holder_reg;  // From now on the object will be in holder_reg.
488
489       __ movp(reg, FieldOperand(map_reg, Map::kPrototypeOffset));
490     }
491
492     // Go to the next object in the prototype chain.
493     current = prototype;
494     current_map = handle(current->map());
495   }
496
497   // Log the check depth.
498   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
499
500   if (depth != 0 || check == CHECK_ALL_MAPS) {
501     __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
502     Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
503     __ CmpWeakValue(scratch1, cell, scratch2);
504     __ j(not_equal, miss);
505   }
506
507   // Perform security check for access to the global object.
508   DCHECK(current_map->IsJSGlobalProxyMap() ||
509          !current_map->is_access_check_needed());
510   if (current_map->IsJSGlobalProxyMap()) {
511     __ CheckAccessGlobalProxy(reg, scratch1, miss);
512   }
513
514   // Return the register containing the holder.
515   return reg;
516 }
517
518
519 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
520   if (!miss->is_unused()) {
521     Label success;
522     __ jmp(&success);
523     __ bind(miss);
524     if (IC::ICUseVector(kind())) {
525       DCHECK(kind() == Code::LOAD_IC);
526       PopVectorAndSlot();
527     }
528     TailCallBuiltin(masm(), MissBuiltin(kind()));
529     __ bind(&success);
530   }
531 }
532
533
534 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
535   if (!miss->is_unused()) {
536     Label success;
537     __ jmp(&success);
538     GenerateRestoreName(miss, name);
539     TailCallBuiltin(masm(), MissBuiltin(kind()));
540     __ bind(&success);
541   }
542 }
543
544
545 void NamedLoadHandlerCompiler::GenerateLoadCallback(
546     Register reg, Handle<ExecutableAccessorInfo> callback) {
547   // Insert additional parameters into the stack frame above return address.
548   DCHECK(!scratch4().is(reg));
549   __ PopReturnAddressTo(scratch4());
550
551   STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
552   STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
553   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
554   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
555   STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
556   STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
557   STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
558   __ Push(receiver());  // receiver
559   Handle<Object> data(callback->data(), isolate());
560   if (data->IsUndefined() || data->IsSmi()) {
561     __ Push(data);
562   } else {
563     DCHECK(!scratch2().is(reg));
564     Handle<WeakCell> cell =
565         isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
566     // The callback is alive if this instruction is executed,
567     // so the weak cell is not cleared and points to data.
568     __ GetWeakValue(scratch2(), cell);
569     __ Push(scratch2());
570   }
571   DCHECK(!kScratchRegister.is(reg));
572   __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
573   __ Push(kScratchRegister);  // return value
574   __ Push(kScratchRegister);  // return value default
575   __ PushAddress(ExternalReference::isolate_address(isolate()));
576   __ Push(reg);     // holder
577   __ Push(name());  // name
578   // Save a pointer to where we pushed the arguments pointer.  This will be
579   // passed as the const PropertyAccessorInfo& to the C++ callback.
580
581   __ PushReturnAddressFrom(scratch4());
582
583   // Abi for CallApiGetter
584   Register api_function_address = ApiGetterDescriptor::function_address();
585   Address getter_address = v8::ToCData<Address>(callback->getter());
586   __ Move(api_function_address, getter_address, RelocInfo::EXTERNAL_REFERENCE);
587
588   CallApiGetterStub stub(isolate());
589   __ TailCallStub(&stub);
590 }
591
592
593 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
594   // Return the constant value.
595   __ Move(rax, value);
596   __ ret(0);
597 }
598
599
600 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
601     LookupIterator* it, Register holder_reg) {
602   DCHECK(holder()->HasNamedInterceptor());
603   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
604
605   // Compile the interceptor call, followed by inline code to load the
606   // property from further up the prototype chain if the call fails.
607   // Check that the maps haven't changed.
608   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
609
610   // Preserve the receiver register explicitly whenever it is different from the
611   // holder and it is needed should the interceptor return without any result.
612   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
613   // case might cause a miss during the prototype check.
614   bool must_perform_prototype_check =
615       !holder().is_identical_to(it->GetHolder<JSObject>());
616   bool must_preserve_receiver_reg =
617       !receiver().is(holder_reg) &&
618       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
619
620   // Save necessary data before invoking an interceptor.
621   // Requires a frame to make GC aware of pushed pointers.
622   {
623     FrameScope frame_scope(masm(), StackFrame::INTERNAL);
624
625     if (must_preserve_receiver_reg) {
626       __ Push(receiver());
627     }
628     __ Push(holder_reg);
629     __ Push(this->name());
630     InterceptorVectorSlotPush(holder_reg);
631
632     // Invoke an interceptor.  Note: map checks from receiver to
633     // interceptor's holder has been compiled before (see a caller
634     // of this method.)
635     CompileCallLoadPropertyWithInterceptor(
636         masm(), receiver(), holder_reg, this->name(), holder(),
637         IC::kLoadPropertyWithInterceptorOnly);
638
639     // Check if interceptor provided a value for property.  If it's
640     // the case, return immediately.
641     Label interceptor_failed;
642     __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
643     __ j(equal, &interceptor_failed);
644     frame_scope.GenerateLeaveFrame();
645     __ ret(0);
646
647     __ bind(&interceptor_failed);
648     InterceptorVectorSlotPop(holder_reg);
649     __ Pop(this->name());
650     __ Pop(holder_reg);
651     if (must_preserve_receiver_reg) {
652       __ Pop(receiver());
653     }
654
655     // Leave the internal frame.
656   }
657
658   GenerateLoadPostInterceptor(it, holder_reg);
659 }
660
661
662 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
663   // Call the runtime system to load the interceptor.
664   DCHECK(holder()->HasNamedInterceptor());
665   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
666   __ PopReturnAddressTo(scratch2());
667   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
668                            holder());
669   __ PushReturnAddressFrom(scratch2());
670
671   ExternalReference ref = ExternalReference(
672       IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
673   __ TailCallExternalReference(
674       ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
675 }
676
677
678 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
679     Handle<JSObject> object, Handle<Name> name,
680     Handle<ExecutableAccessorInfo> callback) {
681   Register holder_reg = Frontend(name);
682
683   __ PopReturnAddressTo(scratch1());
684   __ Push(receiver());
685   __ Push(holder_reg);
686   // If the callback cannot leak, then push the callback directly,
687   // otherwise wrap it in a weak cell.
688   if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
689     __ Push(callback);
690   } else {
691     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
692     __ Push(cell);
693   }
694   __ Push(name);
695   __ Push(value());
696   __ PushReturnAddressFrom(scratch1());
697
698   // Do tail-call to the runtime system.
699   ExternalReference store_callback_property =
700       ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
701   __ TailCallExternalReference(store_callback_property, 5, 1);
702
703   // Return the generated code.
704   return GetCode(kind(), Code::FAST, name);
705 }
706
707
708 Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
709     Handle<Name> name) {
710   __ PopReturnAddressTo(scratch1());
711   __ Push(receiver());
712   __ Push(this->name());
713   __ Push(value());
714   __ PushReturnAddressFrom(scratch1());
715
716   // Do tail-call to the runtime system.
717   ExternalReference store_ic_property = ExternalReference(
718       IC_Utility(IC::kStorePropertyWithInterceptor), isolate());
719   __ TailCallExternalReference(store_ic_property, 3, 1);
720
721   // Return the generated code.
722   return GetCode(kind(), Code::FAST, name);
723 }
724
725
726 Register NamedStoreHandlerCompiler::value() {
727   return StoreDescriptor::ValueRegister();
728 }
729
730
731 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
732     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
733   Label miss;
734   if (IC::ICUseVector(kind())) {
735     PushVectorAndSlot();
736   }
737   FrontendHeader(receiver(), name, &miss);
738
739   // Get the value from the cell.
740   Register result = StoreDescriptor::ValueRegister();
741   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
742   __ LoadWeakValue(result, weak_cell, &miss);
743   __ movp(result, FieldOperand(result, PropertyCell::kValueOffset));
744
745   // Check for deleted property if property can actually be deleted.
746   if (is_configurable) {
747     __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
748     __ j(equal, &miss);
749   } else if (FLAG_debug_code) {
750     __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
751     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
752   }
753
754   Counters* counters = isolate()->counters();
755   __ IncrementCounter(counters->named_load_global_stub(), 1);
756   if (IC::ICUseVector(kind())) {
757     DiscardVectorAndSlot();
758   }
759   __ ret(0);
760
761   FrontendFooter(name, &miss);
762
763   // Return the generated code.
764   return GetCode(kind(), Code::NORMAL, name);
765 }
766
767
768 #undef __
769 }
770 }  // namespace v8::internal
771
772 #endif  // V8_TARGET_ARCH_X64