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