deps: update v8 to 4.3.61.21
[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<PropertyCell> 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, PropertyCell::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
432   // Check access rights to the global object.  This has to happen after
433   // the map check so that we know that the object is actually a global
434   // object.
435   // This allows us to install generated handlers for accesses to the
436   // global proxy (as opposed to using slow ICs). See corresponding code
437   // in LookupForRead().
438   if (receiver_map->IsJSGlobalProxyMap()) {
439     __ CheckAccessGlobalProxy(reg, scratch2, miss);
440   }
441
442   Handle<JSObject> prototype = Handle<JSObject>::null();
443   Handle<Map> current_map = receiver_map;
444   Handle<Map> holder_map(holder()->map());
445   // Traverse the prototype chain and check the maps in the prototype chain for
446   // fast and global objects or do negative lookup for normal objects.
447   while (!current_map.is_identical_to(holder_map)) {
448     ++depth;
449
450     // Only global objects and objects that do not require access
451     // checks are allowed in stubs.
452     DCHECK(current_map->IsJSGlobalProxyMap() ||
453            !current_map->is_access_check_needed());
454
455     prototype = handle(JSObject::cast(current_map->prototype()));
456     if (current_map->is_dictionary_map() &&
457         !current_map->IsJSGlobalObjectMap()) {
458       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
459       if (!name->IsUniqueName()) {
460         DCHECK(name->IsString());
461         name = factory()->InternalizeString(Handle<String>::cast(name));
462       }
463       DCHECK(current.is_null() ||
464              current->property_dictionary()->FindEntry(name) ==
465                  NameDictionary::kNotFound);
466
467       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
468                                        scratch2);
469
470       __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
471       reg = holder_reg;  // From now on the object will be in holder_reg.
472       __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
473     } else {
474       Register map_reg = scratch1;
475       __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
476
477       if (current_map->IsJSGlobalObjectMap()) {
478         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
479                                   name, scratch2, miss);
480       } else if (depth != 1 || check == CHECK_ALL_MAPS) {
481         Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
482         __ CmpWeakValue(map_reg, cell, scratch2);
483         __ b(ne, miss);
484       }
485
486       reg = holder_reg;  // From now on the object will be in holder_reg.
487
488       __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
489     }
490
491     // Go to the next object in the prototype chain.
492     current = prototype;
493     current_map = handle(current->map());
494   }
495
496   DCHECK(!current_map->IsJSGlobalProxyMap());
497
498   // Log the check depth.
499   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
500
501   if (depth != 0 || check == CHECK_ALL_MAPS) {
502     // Check the holder map.
503     __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
504     Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
505     __ CmpWeakValue(scratch1, cell, scratch2);
506     __ b(ne, miss);
507   }
508
509   // Return the register containing the holder.
510   return reg;
511 }
512
513
514 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
515   if (!miss->is_unused()) {
516     Label success;
517     __ b(&success);
518     __ bind(miss);
519     if (IC::ICUseVector(kind())) {
520       DCHECK(kind() == Code::LOAD_IC);
521       PopVectorAndSlot();
522     }
523     TailCallBuiltin(masm(), MissBuiltin(kind()));
524     __ bind(&success);
525   }
526 }
527
528
529 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
530   if (!miss->is_unused()) {
531     Label success;
532     __ b(&success);
533     GenerateRestoreName(miss, name);
534     TailCallBuiltin(masm(), MissBuiltin(kind()));
535     __ bind(&success);
536   }
537 }
538
539
540 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
541   // Return the constant value.
542   __ Move(r0, value);
543   __ Ret();
544 }
545
546
547 void NamedLoadHandlerCompiler::GenerateLoadCallback(
548     Register reg, Handle<ExecutableAccessorInfo> callback) {
549   // Build AccessorInfo::args_ list on the stack and push property name below
550   // the exit frame to make GC aware of them and store pointers to them.
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   DCHECK(!scratch2().is(reg));
559   DCHECK(!scratch3().is(reg));
560   DCHECK(!scratch4().is(reg));
561   __ push(receiver());
562   // Push data from ExecutableAccessorInfo.
563   Handle<Object> data(callback->data(), isolate());
564   if (data->IsUndefined() || data->IsSmi()) {
565     __ Move(scratch3(), data);
566   } else {
567     Handle<WeakCell> cell =
568         isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
569     // The callback is alive if this instruction is executed,
570     // so the weak cell is not cleared and points to data.
571     __ GetWeakValue(scratch3(), cell);
572   }
573   __ push(scratch3());
574   __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
575   __ mov(scratch4(), scratch3());
576   __ Push(scratch3(), scratch4());
577   __ mov(scratch4(), Operand(ExternalReference::isolate_address(isolate())));
578   __ Push(scratch4(), reg);
579   __ mov(scratch2(), sp);  // scratch2 = PropertyAccessorInfo::args_
580   __ push(name());
581
582   // Abi for CallApiGetter
583   Register getter_address_reg = ApiGetterDescriptor::function_address();
584
585   Address getter_address = v8::ToCData<Address>(callback->getter());
586   ApiFunction fun(getter_address);
587   ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
588   ExternalReference ref = ExternalReference(&fun, type, isolate());
589   __ mov(getter_address_reg, Operand(ref));
590
591   CallApiGetterStub stub(isolate());
592   __ TailCallStub(&stub);
593 }
594
595
596 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
597     LookupIterator* it, Register holder_reg) {
598   DCHECK(holder()->HasNamedInterceptor());
599   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
600
601   // Compile the interceptor call, followed by inline code to load the
602   // property from further up the prototype chain if the call fails.
603   // Check that the maps haven't changed.
604   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
605
606   // Preserve the receiver register explicitly whenever it is different from the
607   // holder and it is needed should the interceptor return without any result.
608   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
609   // case might cause a miss during the prototype check.
610   bool must_perform_prototype_check =
611       !holder().is_identical_to(it->GetHolder<JSObject>());
612   bool must_preserve_receiver_reg =
613       !receiver().is(holder_reg) &&
614       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
615
616   // Save necessary data before invoking an interceptor.
617   // Requires a frame to make GC aware of pushed pointers.
618   {
619     FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
620     if (must_preserve_receiver_reg) {
621       __ Push(receiver(), holder_reg, this->name());
622     } else {
623       __ Push(holder_reg, this->name());
624     }
625     InterceptorVectorSlotPush(holder_reg);
626     // Invoke an interceptor.  Note: map checks from receiver to
627     // interceptor's holder has been compiled before (see a caller
628     // of this method.)
629     CompileCallLoadPropertyWithInterceptor(
630         masm(), receiver(), holder_reg, this->name(), holder(),
631         IC::kLoadPropertyWithInterceptorOnly);
632
633     // Check if interceptor provided a value for property.  If it's
634     // the case, return immediately.
635     Label interceptor_failed;
636     __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
637     __ cmp(r0, scratch1());
638     __ b(eq, &interceptor_failed);
639     frame_scope.GenerateLeaveFrame();
640     __ Ret();
641
642     __ bind(&interceptor_failed);
643     InterceptorVectorSlotPop(holder_reg);
644     __ pop(this->name());
645     __ pop(holder_reg);
646     if (must_preserve_receiver_reg) {
647       __ pop(receiver());
648     }
649     // Leave the internal frame.
650   }
651
652   GenerateLoadPostInterceptor(it, holder_reg);
653 }
654
655
656 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
657   // Call the runtime system to load the interceptor.
658   DCHECK(holder()->HasNamedInterceptor());
659   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
660   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
661                            holder());
662
663   ExternalReference ref = ExternalReference(
664       IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
665   __ TailCallExternalReference(
666       ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
667 }
668
669
670 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
671     Handle<JSObject> object, Handle<Name> name,
672     Handle<ExecutableAccessorInfo> callback) {
673   Register holder_reg = Frontend(name);
674
675   __ push(receiver());  // receiver
676   __ push(holder_reg);
677
678   // If the callback cannot leak, then push the callback directly,
679   // otherwise wrap it in a weak cell.
680   if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
681     __ mov(ip, Operand(callback));
682   } else {
683     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
684     __ mov(ip, Operand(cell));
685   }
686   __ push(ip);
687   __ mov(ip, Operand(name));
688   __ Push(ip, value());
689
690   // Do tail-call to the runtime system.
691   ExternalReference store_callback_property =
692       ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
693   __ TailCallExternalReference(store_callback_property, 5, 1);
694
695   // Return the generated code.
696   return GetCode(kind(), Code::FAST, name);
697 }
698
699
700 Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
701     Handle<Name> name) {
702   __ Push(receiver(), this->name(), value());
703
704   // Do tail-call to the runtime system.
705   ExternalReference store_ic_property = ExternalReference(
706       IC_Utility(IC::kStorePropertyWithInterceptor), isolate());
707   __ TailCallExternalReference(store_ic_property, 3, 1);
708
709   // Return the generated code.
710   return GetCode(kind(), Code::FAST, name);
711 }
712
713
714 Register NamedStoreHandlerCompiler::value() {
715   return StoreDescriptor::ValueRegister();
716 }
717
718
719 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
720     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
721   Label miss;
722   if (IC::ICUseVector(kind())) {
723     PushVectorAndSlot();
724   }
725   FrontendHeader(receiver(), name, &miss);
726
727   // Get the value from the cell.
728   Register result = StoreDescriptor::ValueRegister();
729   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
730   __ LoadWeakValue(result, weak_cell, &miss);
731   __ ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
732
733   // Check for deleted property if property can actually be deleted.
734   if (is_configurable) {
735     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
736     __ cmp(result, ip);
737     __ b(eq, &miss);
738   }
739
740   Counters* counters = isolate()->counters();
741   __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
742   if (IC::ICUseVector(kind())) {
743     DiscardVectorAndSlot();
744   }
745   __ Ret();
746
747   FrontendFooter(name, &miss);
748
749   // Return the generated code.
750   return GetCode(kind(), Code::NORMAL, name);
751 }
752
753
754 #undef __
755 }
756 }  // namespace v8::internal
757
758 #endif  // V8_TARGET_ARCH_ARM