• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #if V8_TARGET_ARCH_ARM
6 
7 #include "src/ic/handler-compiler.h"
8 
9 #include "src/api-arguments.h"
10 #include "src/field-type.h"
11 #include "src/ic/call-optimization.h"
12 #include "src/ic/ic.h"
13 #include "src/isolate-inl.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 #define __ ACCESS_MASM(masm)
19 
20 
GenerateLoadViaGetter(MacroAssembler * masm,Handle<Map> map,Register receiver,Register holder,int accessor_index,int expected_arguments,Register scratch)21 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
22     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
23     int accessor_index, int expected_arguments, Register scratch) {
24   // ----------- S t a t e -------------
25   //  -- r0    : receiver
26   //  -- r2    : name
27   //  -- lr    : return address
28   // -----------------------------------
29   {
30     FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
31 
32     // Save context register
33     __ push(cp);
34 
35     if (accessor_index >= 0) {
36       DCHECK(!holder.is(scratch));
37       DCHECK(!receiver.is(scratch));
38       // Call the JavaScript getter with the receiver on the stack.
39       if (map->IsJSGlobalObjectMap()) {
40         // Swap in the global receiver.
41         __ ldr(scratch,
42                FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
43         receiver = scratch;
44       }
45       __ push(receiver);
46       __ LoadAccessor(r1, holder, accessor_index, ACCESSOR_GETTER);
47       __ mov(r0, Operand(0));
48       __ Call(masm->isolate()->builtins()->CallFunction(
49                   ConvertReceiverMode::kNotNullOrUndefined),
50               RelocInfo::CODE_TARGET);
51     } else {
52       // If we generate a global code snippet for deoptimization only, remember
53       // the place to continue after deoptimization.
54       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
55     }
56 
57     // Restore context register.
58     __ pop(cp);
59   }
60   __ Ret();
61 }
62 
63 
GenerateStoreViaSetter(MacroAssembler * masm,Handle<Map> map,Register receiver,Register holder,int accessor_index,int expected_arguments,Register scratch)64 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
65     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
66     int accessor_index, int expected_arguments, Register scratch) {
67   // ----------- S t a t e -------------
68   //  -- lr    : return address
69   // -----------------------------------
70   {
71     FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
72 
73     // Save context register
74     __ push(cp);
75     // Save value register, so we can restore it later.
76     __ push(value());
77 
78     if (accessor_index >= 0) {
79       DCHECK(!holder.is(scratch));
80       DCHECK(!receiver.is(scratch));
81       DCHECK(!value().is(scratch));
82       // Call the JavaScript setter with receiver and value on the stack.
83       if (map->IsJSGlobalObjectMap()) {
84         // Swap in the global receiver.
85         __ ldr(scratch,
86                FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
87         receiver = scratch;
88       }
89       __ Push(receiver, value());
90       __ LoadAccessor(r1, holder, accessor_index, ACCESSOR_SETTER);
91       __ mov(r0, Operand(1));
92       __ Call(masm->isolate()->builtins()->CallFunction(
93                   ConvertReceiverMode::kNotNullOrUndefined),
94               RelocInfo::CODE_TARGET);
95     } else {
96       // If we generate a global code snippet for deoptimization only, remember
97       // the place to continue after deoptimization.
98       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
99     }
100 
101     // We have to return the passed value, not the return value of the setter.
102     __ pop(r0);
103 
104     // Restore context register.
105     __ pop(cp);
106   }
107   __ Ret();
108 }
109 
110 
PushVectorAndSlot(Register vector,Register slot)111 void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
112                                                 Register slot) {
113   MacroAssembler* masm = this->masm();
114   STATIC_ASSERT(LoadWithVectorDescriptor::kSlot <
115                 LoadWithVectorDescriptor::kVector);
116   STATIC_ASSERT(StoreWithVectorDescriptor::kSlot <
117                 StoreWithVectorDescriptor::kVector);
118   STATIC_ASSERT(StoreTransitionDescriptor::kSlot <
119                 StoreTransitionDescriptor::kVector);
120   __ push(slot);
121   __ push(vector);
122 }
123 
124 
PopVectorAndSlot(Register vector,Register slot)125 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
126   MacroAssembler* masm = this->masm();
127   __ pop(vector);
128   __ pop(slot);
129 }
130 
131 
DiscardVectorAndSlot()132 void PropertyHandlerCompiler::DiscardVectorAndSlot() {
133   MacroAssembler* masm = this->masm();
134   // Remove vector and slot.
135   __ add(sp, sp, Operand(2 * kPointerSize));
136 }
137 
PushReturnAddress(Register tmp)138 void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
139   // No-op. Return address is in lr register.
140 }
141 
PopReturnAddress(Register tmp)142 void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
143   // No-op. Return address is in lr register.
144 }
145 
GenerateDictionaryNegativeLookup(MacroAssembler * masm,Label * miss_label,Register receiver,Handle<Name> name,Register scratch0,Register scratch1)146 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
147     MacroAssembler* masm, Label* miss_label, Register receiver,
148     Handle<Name> name, Register scratch0, Register scratch1) {
149   DCHECK(name->IsUniqueName());
150   DCHECK(!receiver.is(scratch0));
151   Counters* counters = masm->isolate()->counters();
152   __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
153   __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
154 
155   Label done;
156 
157   const int kInterceptorOrAccessCheckNeededMask =
158       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
159 
160   // Bail out if the receiver has a named interceptor or requires access checks.
161   Register map = scratch1;
162   __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
163   __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
164   __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
165   __ b(ne, miss_label);
166 
167   // Check that receiver is a JSObject.
168   __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
169   __ cmp(scratch0, Operand(FIRST_JS_RECEIVER_TYPE));
170   __ b(lt, miss_label);
171 
172   // Load properties array.
173   Register properties = scratch0;
174   __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
175   // Check that the properties array is a dictionary.
176   __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
177   Register tmp = properties;
178   __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
179   __ cmp(map, tmp);
180   __ b(ne, miss_label);
181 
182   // Restore the temporarily used register.
183   __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
184 
185 
186   NameDictionaryLookupStub::GenerateNegativeLookup(
187       masm, miss_label, &done, receiver, properties, name, scratch1);
188   __ bind(&done);
189   __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
190 }
191 
192 
GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler * masm,int index,Register result,Label * miss)193 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
194     MacroAssembler* masm, int index, Register result, Label* miss) {
195   __ LoadNativeContextSlot(index, result);
196   // Load its initial map. The global functions all have initial maps.
197   __ ldr(result,
198          FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
199   // Load the prototype from the initial map.
200   __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
201 }
202 
203 
GenerateLoadFunctionPrototype(MacroAssembler * masm,Register receiver,Register scratch1,Register scratch2,Label * miss_label)204 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
205     MacroAssembler* masm, Register receiver, Register scratch1,
206     Register scratch2, Label* miss_label) {
207   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
208   __ mov(r0, scratch1);
209   __ Ret();
210 }
211 
212 
213 // Generate code to check that a global property cell is empty. Create
214 // the property cell at compilation time if no cell exists for the
215 // property.
GenerateCheckPropertyCell(MacroAssembler * masm,Handle<JSGlobalObject> global,Handle<Name> name,Register scratch,Label * miss)216 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
217     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
218     Register scratch, Label* miss) {
219   Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
220       global, name, PropertyCellType::kInvalidated);
221   Isolate* isolate = masm->isolate();
222   DCHECK(cell->value()->IsTheHole(isolate));
223   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
224   __ LoadWeakValue(scratch, weak_cell, miss);
225   __ ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
226   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
227   __ cmp(scratch, ip);
228   __ b(ne, miss);
229 }
230 
231 
PushInterceptorArguments(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj)232 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
233                                      Register holder, Register name,
234                                      Handle<JSObject> holder_obj) {
235   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
236   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
237   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
238   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
239   __ push(name);
240   __ push(receiver);
241   __ push(holder);
242 }
243 
244 
CompileCallLoadPropertyWithInterceptor(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj,Runtime::FunctionId id)245 static void CompileCallLoadPropertyWithInterceptor(
246     MacroAssembler* masm, Register receiver, Register holder, Register name,
247     Handle<JSObject> holder_obj, Runtime::FunctionId id) {
248   DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
249          Runtime::FunctionForId(id)->nargs);
250   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
251   __ CallRuntime(id);
252 }
253 
254 
255 // Generate call to api function.
GenerateApiAccessorCall(MacroAssembler * masm,const CallOptimization & optimization,Handle<Map> receiver_map,Register receiver,Register scratch_in,bool is_store,Register store_parameter,Register accessor_holder,int accessor_index)256 void PropertyHandlerCompiler::GenerateApiAccessorCall(
257     MacroAssembler* masm, const CallOptimization& optimization,
258     Handle<Map> receiver_map, Register receiver, Register scratch_in,
259     bool is_store, Register store_parameter, Register accessor_holder,
260     int accessor_index) {
261   DCHECK(!accessor_holder.is(scratch_in));
262   DCHECK(!receiver.is(scratch_in));
263   __ push(receiver);
264   // Write the arguments to stack frame.
265   if (is_store) {
266     DCHECK(!receiver.is(store_parameter));
267     DCHECK(!scratch_in.is(store_parameter));
268     __ push(store_parameter);
269   }
270   DCHECK(optimization.is_simple_api_call());
271 
272   // Abi for CallApiCallbackStub.
273   Register callee = r0;
274   Register data = r4;
275   Register holder = r2;
276   Register api_function_address = r1;
277 
278   // Put callee in place.
279   __ LoadAccessor(callee, accessor_holder, accessor_index,
280                   is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
281 
282   // Put holder in place.
283   CallOptimization::HolderLookup holder_lookup;
284   int holder_depth = 0;
285   optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
286                                           &holder_depth);
287   switch (holder_lookup) {
288     case CallOptimization::kHolderIsReceiver:
289       __ Move(holder, receiver);
290       break;
291     case CallOptimization::kHolderFound:
292       __ ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
293       __ ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
294       for (int i = 1; i < holder_depth; i++) {
295         __ ldr(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
296         __ ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
297       }
298       break;
299     case CallOptimization::kHolderNotFound:
300       UNREACHABLE();
301       break;
302   }
303 
304   Isolate* isolate = masm->isolate();
305   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
306   bool call_data_undefined = false;
307   // Put call data in place.
308   if (api_call_info->data()->IsUndefined(isolate)) {
309     call_data_undefined = true;
310     __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
311   } else {
312     if (optimization.is_constant_call()) {
313       __ ldr(data,
314              FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
315       __ ldr(data,
316              FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
317       __ ldr(data,
318              FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
319     } else {
320       __ ldr(data,
321              FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
322     }
323     __ ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
324   }
325 
326   if (api_call_info->fast_handler()->IsCode()) {
327     // Just tail call into the fast handler if present.
328     __ Jump(handle(Code::cast(api_call_info->fast_handler())),
329             RelocInfo::CODE_TARGET);
330     return;
331   }
332 
333   // Put api_function_address in place.
334   Address function_address = v8::ToCData<Address>(api_call_info->callback());
335   ApiFunction fun(function_address);
336   ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
337   ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
338   __ mov(api_function_address, Operand(ref));
339 
340   // Jump to stub.
341   CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
342                            !optimization.is_constant_call());
343   __ TailCallStub(&stub);
344 }
345 
346 #undef __
347 #define __ ACCESS_MASM(masm())
348 
349 
GenerateRestoreName(Label * label,Handle<Name> name)350 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
351                                                     Handle<Name> name) {
352   if (!label->is_unused()) {
353     __ bind(label);
354     __ mov(this->name(), Operand(name));
355   }
356 }
357 
358 
GenerateRestoreName(Handle<Name> name)359 void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
360   __ mov(this->name(), Operand(name));
361 }
362 
363 
GenerateRestoreMap(Handle<Map> transition,Register map_reg,Register scratch,Label * miss)364 void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
365                                                    Register map_reg,
366                                                    Register scratch,
367                                                    Label* miss) {
368   Handle<WeakCell> cell = Map::WeakCellForMap(transition);
369   DCHECK(!map_reg.is(scratch));
370   __ LoadWeakValue(map_reg, cell, miss);
371   if (transition->CanBeDeprecated()) {
372     __ ldr(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
373     __ tst(scratch, Operand(Map::Deprecated::kMask));
374     __ b(ne, miss);
375   }
376 }
377 
378 
GenerateConstantCheck(Register map_reg,int descriptor,Register value_reg,Register scratch,Label * miss_label)379 void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
380                                                       int descriptor,
381                                                       Register value_reg,
382                                                       Register scratch,
383                                                       Label* miss_label) {
384   DCHECK(!map_reg.is(scratch));
385   DCHECK(!map_reg.is(value_reg));
386   DCHECK(!value_reg.is(scratch));
387   __ LoadInstanceDescriptors(map_reg, scratch);
388   __ ldr(scratch,
389          FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
390   __ cmp(value_reg, scratch);
391   __ b(ne, miss_label);
392 }
393 
GenerateFieldTypeChecks(FieldType * field_type,Register value_reg,Label * miss_label)394 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
395                                                         Register value_reg,
396                                                         Label* miss_label) {
397   Register map_reg = scratch1();
398   Register scratch = scratch2();
399   DCHECK(!value_reg.is(map_reg));
400   DCHECK(!value_reg.is(scratch));
401   __ JumpIfSmi(value_reg, miss_label);
402   if (field_type->IsClass()) {
403     __ ldr(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
404     __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
405                     scratch);
406     __ b(ne, miss_label);
407   }
408 }
409 
GenerateAccessCheck(Handle<WeakCell> native_context_cell,Register scratch1,Register scratch2,Label * miss,bool compare_native_contexts_only)410 void PropertyHandlerCompiler::GenerateAccessCheck(
411     Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
412     Label* miss, bool compare_native_contexts_only) {
413   Label done;
414   // Load current native context.
415   __ ldr(scratch1, NativeContextMemOperand());
416   // Load expected native context.
417   __ LoadWeakValue(scratch2, native_context_cell, miss);
418   __ cmp(scratch1, scratch2);
419 
420   if (!compare_native_contexts_only) {
421     __ b(eq, &done);
422 
423     // Compare security tokens of current and expected native contexts.
424     __ ldr(scratch1,
425            ContextMemOperand(scratch1, Context::SECURITY_TOKEN_INDEX));
426     __ ldr(scratch2,
427            ContextMemOperand(scratch2, Context::SECURITY_TOKEN_INDEX));
428     __ cmp(scratch1, scratch2);
429   }
430   __ b(ne, miss);
431 
432   __ bind(&done);
433 }
434 
CheckPrototypes(Register object_reg,Register holder_reg,Register scratch1,Register scratch2,Handle<Name> name,Label * miss,ReturnHolder return_what)435 Register PropertyHandlerCompiler::CheckPrototypes(
436     Register object_reg, Register holder_reg, Register scratch1,
437     Register scratch2, Handle<Name> name, Label* miss,
438     ReturnHolder return_what) {
439   Handle<Map> receiver_map = map();
440 
441   // Make sure there's no overlap between holder and object registers.
442   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
443   DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
444          !scratch2.is(scratch1));
445 
446   Handle<Cell> validity_cell =
447       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
448   if (!validity_cell.is_null()) {
449     DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
450     __ mov(scratch1, Operand(validity_cell));
451     __ ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
452     __ cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid)));
453     __ b(ne, miss);
454   }
455 
456   // Keep track of the current object in register reg.
457   Register reg = object_reg;
458   int depth = 0;
459 
460   Handle<JSObject> current = Handle<JSObject>::null();
461   if (receiver_map->IsJSGlobalObjectMap()) {
462     current = isolate()->global_object();
463   }
464 
465   Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
466                           isolate());
467   Handle<Map> holder_map(holder()->map());
468   // Traverse the prototype chain and check the maps in the prototype chain for
469   // fast and global objects or do negative lookup for normal objects.
470   while (!current_map.is_identical_to(holder_map)) {
471     ++depth;
472 
473     if (current_map->IsJSGlobalObjectMap()) {
474       GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
475                                 name, scratch2, miss);
476     } else if (current_map->is_dictionary_map()) {
477       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
478       DCHECK(name->IsUniqueName());
479       DCHECK(current.is_null() ||
480              current->property_dictionary()->FindEntry(name) ==
481                  NameDictionary::kNotFound);
482 
483       if (depth > 1) {
484         Handle<WeakCell> weak_cell =
485             Map::GetOrCreatePrototypeWeakCell(current, isolate());
486         __ LoadWeakValue(reg, weak_cell, miss);
487       }
488       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
489                                        scratch2);
490     }
491 
492     reg = holder_reg;  // From now on the object will be in holder_reg.
493     // Go to the next object in the prototype chain.
494     current = handle(JSObject::cast(current_map->prototype()));
495     current_map = handle(current->map());
496   }
497 
498   DCHECK(!current_map->IsJSGlobalProxyMap());
499 
500   // Log the check depth.
501   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
502 
503   bool return_holder = return_what == RETURN_HOLDER;
504   if (return_holder && depth != 0) {
505     Handle<WeakCell> weak_cell =
506         Map::GetOrCreatePrototypeWeakCell(current, isolate());
507     __ LoadWeakValue(reg, weak_cell, miss);
508   }
509 
510   // Return the register containing the holder.
511   return return_holder ? reg : no_reg;
512 }
513 
514 
FrontendFooter(Handle<Name> name,Label * miss)515 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
516   if (!miss->is_unused()) {
517     Label success;
518     __ b(&success);
519     __ bind(miss);
520     if (IC::ICUseVector(kind())) {
521       DCHECK(kind() == Code::LOAD_IC);
522       PopVectorAndSlot();
523     }
524     TailCallBuiltin(masm(), MissBuiltin(kind()));
525     __ bind(&success);
526   }
527 }
528 
529 
FrontendFooter(Handle<Name> name,Label * miss)530 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
531   if (!miss->is_unused()) {
532     Label success;
533     __ b(&success);
534     GenerateRestoreName(miss, name);
535     if (IC::ICUseVector(kind())) PopVectorAndSlot();
536     TailCallBuiltin(masm(), MissBuiltin(kind()));
537     __ bind(&success);
538   }
539 }
540 
541 
GenerateLoadConstant(Handle<Object> value)542 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
543   // Return the constant value.
544   __ Move(r0, value);
545   __ Ret();
546 }
547 
GenerateLoadInterceptorWithFollowup(LookupIterator * it,Register holder_reg)548 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
549     LookupIterator* it, Register holder_reg) {
550   DCHECK(holder()->HasNamedInterceptor());
551   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
552 
553   // Compile the interceptor call, followed by inline code to load the
554   // property from further up the prototype chain if the call fails.
555   // Check that the maps haven't changed.
556   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
557 
558   // Preserve the receiver register explicitly whenever it is different from the
559   // holder and it is needed should the interceptor return without any result.
560   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
561   // case might cause a miss during the prototype check.
562   bool must_perform_prototype_check =
563       !holder().is_identical_to(it->GetHolder<JSObject>());
564   bool must_preserve_receiver_reg =
565       !receiver().is(holder_reg) &&
566       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
567 
568   // Save necessary data before invoking an interceptor.
569   // Requires a frame to make GC aware of pushed pointers.
570   {
571     FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
572     if (must_preserve_receiver_reg) {
573       __ Push(receiver(), holder_reg, this->name());
574     } else {
575       __ Push(holder_reg, this->name());
576     }
577     InterceptorVectorSlotPush(holder_reg);
578     // Invoke an interceptor.  Note: map checks from receiver to
579     // interceptor's holder has been compiled before (see a caller
580     // of this method.)
581     CompileCallLoadPropertyWithInterceptor(
582         masm(), receiver(), holder_reg, this->name(), holder(),
583         Runtime::kLoadPropertyWithInterceptorOnly);
584 
585     // Check if interceptor provided a value for property.  If it's
586     // the case, return immediately.
587     Label interceptor_failed;
588     __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
589     __ cmp(r0, scratch1());
590     __ b(eq, &interceptor_failed);
591     frame_scope.GenerateLeaveFrame();
592     __ Ret();
593 
594     __ bind(&interceptor_failed);
595     InterceptorVectorSlotPop(holder_reg);
596     __ pop(this->name());
597     __ pop(holder_reg);
598     if (must_preserve_receiver_reg) {
599       __ pop(receiver());
600     }
601     // Leave the internal frame.
602   }
603 
604   GenerateLoadPostInterceptor(it, holder_reg);
605 }
606 
607 
GenerateLoadInterceptor(Register holder_reg)608 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
609   // Call the runtime system to load the interceptor.
610   DCHECK(holder()->HasNamedInterceptor());
611   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
612   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
613                            holder());
614 
615   __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
616 }
617 
ZapStackArgumentsRegisterAliases()618 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
619   STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
620 }
621 
CompileStoreCallback(Handle<JSObject> object,Handle<Name> name,Handle<AccessorInfo> callback,LanguageMode language_mode)622 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
623     Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
624     LanguageMode language_mode) {
625   Register holder_reg = Frontend(name);
626 
627   __ push(receiver());  // receiver
628   __ push(holder_reg);
629 
630   // If the callback cannot leak, then push the callback directly,
631   // otherwise wrap it in a weak cell.
632   if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
633     __ mov(ip, Operand(callback));
634   } else {
635     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
636     __ mov(ip, Operand(cell));
637   }
638   __ push(ip);
639   __ mov(ip, Operand(name));
640   __ Push(ip, value());
641   __ Push(Smi::FromInt(language_mode));
642 
643   // Do tail-call to the runtime system.
644   __ TailCallRuntime(Runtime::kStoreCallbackProperty);
645 
646   // Return the generated code.
647   return GetCode(kind(), name);
648 }
649 
650 
value()651 Register NamedStoreHandlerCompiler::value() {
652   return StoreDescriptor::ValueRegister();
653 }
654 
655 
CompileLoadGlobal(Handle<PropertyCell> cell,Handle<Name> name,bool is_configurable)656 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
657     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
658   Label miss;
659   if (IC::ICUseVector(kind())) {
660     PushVectorAndSlot();
661   }
662   FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
663 
664   // Get the value from the cell.
665   Register result = StoreDescriptor::ValueRegister();
666   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
667   __ LoadWeakValue(result, weak_cell, &miss);
668   __ ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
669 
670   // Check for deleted property if property can actually be deleted.
671   if (is_configurable) {
672     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
673     __ cmp(result, ip);
674     __ b(eq, &miss);
675   }
676 
677   Counters* counters = isolate()->counters();
678   __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r1, r3);
679   if (IC::ICUseVector(kind())) {
680     DiscardVectorAndSlot();
681   }
682   __ Ret();
683 
684   FrontendFooter(name, &miss);
685 
686   // Return the generated code.
687   return GetCode(kind(), name);
688 }
689 
690 
691 #undef __
692 }  // namespace internal
693 }  // namespace v8
694 
695 #endif  // V8_TARGET_ARCH_ARM
696