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