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