deps: update v8 to 4.3.61.21
[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, PropertyCell::kValueOffset),
213          factory->the_hole_value());
214   __ j(not_equal, miss);
215 }
216
217
218 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
219     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
220     int accessor_index, int expected_arguments, Register scratch) {
221   // ----------- S t a t e -------------
222   //  -- rsp[0] : return address
223   // -----------------------------------
224   {
225     FrameScope scope(masm, StackFrame::INTERNAL);
226
227     // Save value register, so we can restore it later.
228     __ Push(value());
229
230     if (accessor_index >= 0) {
231       DCHECK(!holder.is(scratch));
232       DCHECK(!receiver.is(scratch));
233       DCHECK(!value().is(scratch));
234       // Call the JavaScript setter with receiver and value on the stack.
235       if (map->IsJSGlobalObjectMap()) {
236         // Swap in the global receiver.
237         __ movp(scratch,
238                 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
239         receiver = scratch;
240       }
241       __ Push(receiver);
242       __ Push(value());
243       ParameterCount actual(1);
244       ParameterCount expected(expected_arguments);
245       __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_SETTER);
246       __ InvokeFunction(rdi, expected, actual, CALL_FUNCTION,
247                         NullCallWrapper());
248     } else {
249       // If we generate a global code snippet for deoptimization only, remember
250       // the place to continue after deoptimization.
251       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
252     }
253
254     // We have to return the passed value, not the return value of the setter.
255     __ Pop(rax);
256
257     // Restore context register.
258     __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
259   }
260   __ ret(0);
261 }
262
263
264 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
265     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
266     int accessor_index, int expected_arguments, Register scratch) {
267   // ----------- S t a t e -------------
268   //  -- rax    : receiver
269   //  -- rcx    : name
270   //  -- rsp[0] : return address
271   // -----------------------------------
272   {
273     FrameScope scope(masm, StackFrame::INTERNAL);
274
275     if (accessor_index >= 0) {
276       DCHECK(!holder.is(scratch));
277       DCHECK(!receiver.is(scratch));
278       // Call the JavaScript getter with the receiver on the stack.
279       if (map->IsJSGlobalObjectMap()) {
280         // Swap in the global receiver.
281         __ movp(scratch,
282                 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
283         receiver = scratch;
284       }
285       __ Push(receiver);
286       ParameterCount actual(0);
287       ParameterCount expected(expected_arguments);
288       __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_GETTER);
289       __ InvokeFunction(rdi, expected, actual, CALL_FUNCTION,
290                         NullCallWrapper());
291     } else {
292       // If we generate a global code snippet for deoptimization only, remember
293       // the place to continue after deoptimization.
294       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
295     }
296
297     // Restore context register.
298     __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
299   }
300   __ ret(0);
301 }
302
303
304 static void StoreIC_PushArgs(MacroAssembler* masm) {
305   Register receiver = StoreDescriptor::ReceiverRegister();
306   Register name = StoreDescriptor::NameRegister();
307   Register value = StoreDescriptor::ValueRegister();
308
309   DCHECK(!rbx.is(receiver) && !rbx.is(name) && !rbx.is(value));
310
311   __ PopReturnAddressTo(rbx);
312   __ Push(receiver);
313   __ Push(name);
314   __ Push(value);
315   __ PushReturnAddressFrom(rbx);
316 }
317
318
319 void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
320   // Return address is on the stack.
321   StoreIC_PushArgs(masm);
322
323   // Do tail-call to runtime routine.
324   ExternalReference ref(IC_Utility(IC::kStoreIC_Slow), masm->isolate());
325   __ TailCallExternalReference(ref, 3, 1);
326 }
327
328
329 void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
330   // Return address is on the stack.
331   StoreIC_PushArgs(masm);
332
333   // Do tail-call to runtime routine.
334   ExternalReference ref(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate());
335   __ TailCallExternalReference(ref, 3, 1);
336 }
337
338
339 #undef __
340 #define __ ACCESS_MASM((masm()))
341
342
343 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
344                                                     Handle<Name> name) {
345   if (!label->is_unused()) {
346     __ bind(label);
347     __ Move(this->name(), name);
348   }
349 }
350
351
352 void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
353   __ Move(this->name(), name);
354 }
355
356
357 void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
358                                                    Register scratch,
359                                                    Label* miss) {
360   Handle<WeakCell> cell = Map::WeakCellForMap(transition);
361   Register map_reg = StoreTransitionDescriptor::MapRegister();
362   DCHECK(!map_reg.is(scratch));
363   __ LoadWeakValue(map_reg, cell, miss);
364   if (transition->CanBeDeprecated()) {
365     __ movl(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
366     __ andl(scratch, Immediate(Map::Deprecated::kMask));
367     __ j(not_zero, miss);
368   }
369 }
370
371
372 void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
373                                                       int descriptor,
374                                                       Register value_reg,
375                                                       Register scratch,
376                                                       Label* miss_label) {
377   DCHECK(!map_reg.is(scratch));
378   DCHECK(!map_reg.is(value_reg));
379   DCHECK(!value_reg.is(scratch));
380   __ LoadInstanceDescriptors(map_reg, scratch);
381   __ movp(scratch,
382           FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
383   __ cmpp(value_reg, scratch);
384   __ j(not_equal, miss_label);
385 }
386
387
388 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
389                                                         Register value_reg,
390                                                         Label* miss_label) {
391   Register map_reg = scratch1();
392   Register scratch = scratch2();
393   DCHECK(!value_reg.is(map_reg));
394   DCHECK(!value_reg.is(scratch));
395   __ JumpIfSmi(value_reg, miss_label);
396   HeapType::Iterator<Map> it = field_type->Classes();
397   if (!it.Done()) {
398     Label do_store;
399     __ movp(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
400     while (true) {
401       __ CmpWeakValue(map_reg, Map::WeakCellForMap(it.Current()), scratch);
402       it.Advance();
403       if (it.Done()) {
404         __ j(not_equal, miss_label);
405         break;
406       }
407       __ j(equal, &do_store, Label::kNear);
408     }
409     __ bind(&do_store);
410   }
411 }
412
413
414 Register PropertyHandlerCompiler::CheckPrototypes(
415     Register object_reg, Register holder_reg, Register scratch1,
416     Register scratch2, Handle<Name> name, Label* miss,
417     PrototypeCheckType check) {
418   Handle<Map> receiver_map = map();
419
420   // Make sure there's no overlap between holder and object registers.
421   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
422   DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
423          !scratch2.is(scratch1));
424
425   // Keep track of the current object in register reg.  On the first
426   // iteration, reg is an alias for object_reg, on later iterations,
427   // it is an alias for holder_reg.
428   Register reg = object_reg;
429   int depth = 0;
430
431   Handle<JSObject> current = Handle<JSObject>::null();
432   if (receiver_map->IsJSGlobalObjectMap()) {
433     current = isolate()->global_object();
434   }
435
436   // Check access rights to the global object.  This has to happen after
437   // the map check so that we know that the object is actually a global
438   // object.
439   // This allows us to install generated handlers for accesses to the
440   // global proxy (as opposed to using slow ICs). See corresponding code
441   // in LookupForRead().
442   if (receiver_map->IsJSGlobalProxyMap()) {
443     __ CheckAccessGlobalProxy(reg, scratch2, miss);
444   }
445
446   Handle<JSObject> prototype = Handle<JSObject>::null();
447   Handle<Map> current_map = receiver_map;
448   Handle<Map> holder_map(holder()->map());
449   // Traverse the prototype chain and check the maps in the prototype chain for
450   // fast and global objects or do negative lookup for normal objects.
451   while (!current_map.is_identical_to(holder_map)) {
452     ++depth;
453
454     // Only global objects and objects that do not require access
455     // checks are allowed in stubs.
456     DCHECK(current_map->IsJSGlobalProxyMap() ||
457            !current_map->is_access_check_needed());
458
459     prototype = handle(JSObject::cast(current_map->prototype()));
460     if (current_map->is_dictionary_map() &&
461         !current_map->IsJSGlobalObjectMap()) {
462       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
463       if (!name->IsUniqueName()) {
464         DCHECK(name->IsString());
465         name = factory()->InternalizeString(Handle<String>::cast(name));
466       }
467       DCHECK(current.is_null() ||
468              current->property_dictionary()->FindEntry(name) ==
469                  NameDictionary::kNotFound);
470
471       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
472                                        scratch2);
473
474       __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
475       reg = holder_reg;  // From now on the object will be in holder_reg.
476       __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
477     } else {
478       Register map_reg = scratch1;
479       __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
480
481       if (current_map->IsJSGlobalObjectMap()) {
482         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
483                                   name, scratch2, miss);
484       } else if (depth != 1 || check == CHECK_ALL_MAPS) {
485         Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
486         __ CmpWeakValue(map_reg, cell, scratch2);
487         __ j(not_equal, miss);
488       }
489
490       reg = holder_reg;  // From now on the object will be in holder_reg.
491
492       __ movp(reg, FieldOperand(map_reg, Map::kPrototypeOffset));
493     }
494
495     // Go to the next object in the prototype chain.
496     current = prototype;
497     current_map = handle(current->map());
498   }
499
500   DCHECK(!current_map->IsJSGlobalProxyMap());
501
502   // Log the check depth.
503   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
504
505   if (depth != 0 || check == CHECK_ALL_MAPS) {
506     __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
507     Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
508     __ CmpWeakValue(scratch1, cell, scratch2);
509     __ j(not_equal, miss);
510   }
511
512   // Return the register containing the holder.
513   return reg;
514 }
515
516
517 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
518   if (!miss->is_unused()) {
519     Label success;
520     __ jmp(&success);
521     __ bind(miss);
522     if (IC::ICUseVector(kind())) {
523       DCHECK(kind() == Code::LOAD_IC);
524       PopVectorAndSlot();
525     }
526     TailCallBuiltin(masm(), MissBuiltin(kind()));
527     __ bind(&success);
528   }
529 }
530
531
532 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
533   if (!miss->is_unused()) {
534     Label success;
535     __ jmp(&success);
536     GenerateRestoreName(miss, name);
537     TailCallBuiltin(masm(), MissBuiltin(kind()));
538     __ bind(&success);
539   }
540 }
541
542
543 void NamedLoadHandlerCompiler::GenerateLoadCallback(
544     Register reg, Handle<ExecutableAccessorInfo> callback) {
545   // Insert additional parameters into the stack frame above return address.
546   DCHECK(!scratch4().is(reg));
547   __ PopReturnAddressTo(scratch4());
548
549   STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
550   STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
551   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
552   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
553   STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
554   STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
555   STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
556   __ Push(receiver());  // receiver
557   Handle<Object> data(callback->data(), isolate());
558   if (data->IsUndefined() || data->IsSmi()) {
559     __ Push(data);
560   } else {
561     DCHECK(!scratch2().is(reg));
562     Handle<WeakCell> cell =
563         isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
564     // The callback is alive if this instruction is executed,
565     // so the weak cell is not cleared and points to data.
566     __ GetWeakValue(scratch2(), cell);
567     __ Push(scratch2());
568   }
569   DCHECK(!kScratchRegister.is(reg));
570   __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
571   __ Push(kScratchRegister);  // return value
572   __ Push(kScratchRegister);  // return value default
573   __ PushAddress(ExternalReference::isolate_address(isolate()));
574   __ Push(reg);     // holder
575   __ Push(name());  // name
576   // Save a pointer to where we pushed the arguments pointer.  This will be
577   // passed as the const PropertyAccessorInfo& to the C++ callback.
578
579   __ PushReturnAddressFrom(scratch4());
580
581   // Abi for CallApiGetter
582   Register api_function_address = ApiGetterDescriptor::function_address();
583   Address getter_address = v8::ToCData<Address>(callback->getter());
584   __ Move(api_function_address, getter_address, RelocInfo::EXTERNAL_REFERENCE);
585
586   CallApiGetterStub stub(isolate());
587   __ TailCallStub(&stub);
588 }
589
590
591 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
592   // Return the constant value.
593   __ Move(rax, value);
594   __ ret(0);
595 }
596
597
598 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
599     LookupIterator* it, Register holder_reg) {
600   DCHECK(holder()->HasNamedInterceptor());
601   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
602
603   // Compile the interceptor call, followed by inline code to load the
604   // property from further up the prototype chain if the call fails.
605   // Check that the maps haven't changed.
606   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
607
608   // Preserve the receiver register explicitly whenever it is different from the
609   // holder and it is needed should the interceptor return without any result.
610   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
611   // case might cause a miss during the prototype check.
612   bool must_perform_prototype_check =
613       !holder().is_identical_to(it->GetHolder<JSObject>());
614   bool must_preserve_receiver_reg =
615       !receiver().is(holder_reg) &&
616       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
617
618   // Save necessary data before invoking an interceptor.
619   // Requires a frame to make GC aware of pushed pointers.
620   {
621     FrameScope frame_scope(masm(), StackFrame::INTERNAL);
622
623     if (must_preserve_receiver_reg) {
624       __ Push(receiver());
625     }
626     __ Push(holder_reg);
627     __ Push(this->name());
628     InterceptorVectorSlotPush(holder_reg);
629
630     // Invoke an interceptor.  Note: map checks from receiver to
631     // interceptor's holder has been compiled before (see a caller
632     // of this method.)
633     CompileCallLoadPropertyWithInterceptor(
634         masm(), receiver(), holder_reg, this->name(), holder(),
635         IC::kLoadPropertyWithInterceptorOnly);
636
637     // Check if interceptor provided a value for property.  If it's
638     // the case, return immediately.
639     Label interceptor_failed;
640     __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
641     __ j(equal, &interceptor_failed);
642     frame_scope.GenerateLeaveFrame();
643     __ ret(0);
644
645     __ bind(&interceptor_failed);
646     InterceptorVectorSlotPop(holder_reg);
647     __ Pop(this->name());
648     __ Pop(holder_reg);
649     if (must_preserve_receiver_reg) {
650       __ Pop(receiver());
651     }
652
653     // Leave the internal frame.
654   }
655
656   GenerateLoadPostInterceptor(it, holder_reg);
657 }
658
659
660 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
661   // Call the runtime system to load the interceptor.
662   DCHECK(holder()->HasNamedInterceptor());
663   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
664   __ PopReturnAddressTo(scratch2());
665   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
666                            holder());
667   __ PushReturnAddressFrom(scratch2());
668
669   ExternalReference ref = ExternalReference(
670       IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
671   __ TailCallExternalReference(
672       ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
673 }
674
675
676 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
677     Handle<JSObject> object, Handle<Name> name,
678     Handle<ExecutableAccessorInfo> callback) {
679   Register holder_reg = Frontend(name);
680
681   __ PopReturnAddressTo(scratch1());
682   __ Push(receiver());
683   __ Push(holder_reg);
684   // If the callback cannot leak, then push the callback directly,
685   // otherwise wrap it in a weak cell.
686   if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
687     __ Push(callback);
688   } else {
689     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
690     __ Push(cell);
691   }
692   __ Push(name);
693   __ Push(value());
694   __ PushReturnAddressFrom(scratch1());
695
696   // Do tail-call to the runtime system.
697   ExternalReference store_callback_property =
698       ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
699   __ TailCallExternalReference(store_callback_property, 5, 1);
700
701   // Return the generated code.
702   return GetCode(kind(), Code::FAST, name);
703 }
704
705
706 Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
707     Handle<Name> name) {
708   __ PopReturnAddressTo(scratch1());
709   __ Push(receiver());
710   __ Push(this->name());
711   __ Push(value());
712   __ PushReturnAddressFrom(scratch1());
713
714   // Do tail-call to the runtime system.
715   ExternalReference store_ic_property = ExternalReference(
716       IC_Utility(IC::kStorePropertyWithInterceptor), isolate());
717   __ TailCallExternalReference(store_ic_property, 3, 1);
718
719   // Return the generated code.
720   return GetCode(kind(), Code::FAST, name);
721 }
722
723
724 Register NamedStoreHandlerCompiler::value() {
725   return StoreDescriptor::ValueRegister();
726 }
727
728
729 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
730     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
731   Label miss;
732   if (IC::ICUseVector(kind())) {
733     PushVectorAndSlot();
734   }
735   FrontendHeader(receiver(), name, &miss);
736
737   // Get the value from the cell.
738   Register result = StoreDescriptor::ValueRegister();
739   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
740   __ LoadWeakValue(result, weak_cell, &miss);
741   __ movp(result, FieldOperand(result, PropertyCell::kValueOffset));
742
743   // Check for deleted property if property can actually be deleted.
744   if (is_configurable) {
745     __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
746     __ j(equal, &miss);
747   } else if (FLAG_debug_code) {
748     __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
749     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
750   }
751
752   Counters* counters = isolate()->counters();
753   __ IncrementCounter(counters->named_load_global_stub(), 1);
754   if (IC::ICUseVector(kind())) {
755     DiscardVectorAndSlot();
756   }
757   __ ret(0);
758
759   FrontendFooter(name, &miss);
760
761   // Return the generated code.
762   return GetCode(kind(), Code::NORMAL, name);
763 }
764
765
766 #undef __
767 }
768 }  // namespace v8::internal
769
770 #endif  // V8_TARGET_ARCH_X64