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