V8 Project
handler-compiler-arm.cc
Go to the documentation of this file.
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 
11 #include "src/ic/ic.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 #define __ ACCESS_MASM(masm)
17 
18 
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,
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.
50  }
51  __ Ret();
52 }
53 
54 
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,
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.
90  }
91  __ Ret();
92 }
93 
94 
96  MacroAssembler* masm, Label* miss_label, Register receiver,
97  Handle<Name> name, Register scratch0, Register scratch1) {
98  DCHECK(name->IsUniqueName());
99  DCHECK(!receiver.is(scratch0));
100  Counters* counters = masm->isolate()->counters();
101  __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
102  __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
103 
104  Label done;
105 
106  const int kInterceptorOrAccessCheckNeededMask =
108 
109  // Bail out if the receiver has a named interceptor or requires access checks.
110  Register map = scratch1;
111  __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
112  __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
113  __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
114  __ b(ne, miss_label);
115 
116  // Check that receiver is a JSObject.
118  __ cmp(scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
119  __ b(lt, miss_label);
120 
121  // Load properties array.
122  Register properties = scratch0;
123  __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
124  // Check that the properties array is a dictionary.
125  __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
126  Register tmp = properties;
127  __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
128  __ cmp(map, tmp);
129  __ b(ne, miss_label);
130 
131  // Restore the temporarily used register.
132  __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
133 
134 
136  masm, miss_label, &done, receiver, properties, name, scratch1);
137  __ bind(&done);
138  __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
139 }
140 
141 
143  MacroAssembler* masm, int index, Register prototype, Label* miss) {
144  Isolate* isolate = masm->isolate();
145  // Get the global function with the given index.
146  Handle<JSFunction> function(
147  JSFunction::cast(isolate->native_context()->get(index)));
148 
149  // Check we're still in the same context.
150  Register scratch = prototype;
152  __ ldr(scratch, MemOperand(cp, offset));
153  __ ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
154  __ ldr(scratch, MemOperand(scratch, Context::SlotOffset(index)));
155  __ Move(ip, function);
156  __ cmp(ip, scratch);
157  __ b(ne, miss);
158 
159  // Load its initial map. The global functions all have initial maps.
160  __ Move(prototype, Handle<Map>(function->initial_map()));
161  // Load the prototype from the initial map.
162  __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
163 }
164 
165 
167  MacroAssembler* masm, Register receiver, Register scratch1,
168  Register scratch2, Label* miss_label) {
169  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
170  __ mov(r0, scratch1);
171  __ Ret();
172 }
173 
174 
175 // Generate code to check that a global property cell is empty. Create
176 // the property cell at compilation time if no cell exists for the
177 // property.
179  MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
180  Register scratch, Label* miss) {
181  Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
182  DCHECK(cell->value()->IsTheHole());
183  __ mov(scratch, Operand(cell));
184  __ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
185  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
186  __ cmp(scratch, ip);
187  __ b(ne, miss);
188 }
189 
190 
191 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
192  Register holder, Register name,
193  Handle<JSObject> holder_obj) {
199  __ push(name);
200  Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
201  DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor));
202  Register scratch = name;
203  __ mov(scratch, Operand(interceptor));
204  __ push(scratch);
205  __ push(receiver);
206  __ push(holder);
207 }
208 
209 
210 static void CompileCallLoadPropertyWithInterceptor(
211  MacroAssembler* masm, Register receiver, Register holder, Register name,
212  Handle<JSObject> holder_obj, IC::UtilityId id) {
213  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
214  __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()),
216 }
217 
218 
219 // Generate call to api function.
221  MacroAssembler* masm, const CallOptimization& optimization,
222  Handle<Map> receiver_map, Register receiver, Register scratch_in,
223  bool is_store, int argc, Register* values) {
224  DCHECK(!receiver.is(scratch_in));
225  __ push(receiver);
226  // Write the arguments to stack frame.
227  for (int i = 0; i < argc; i++) {
228  Register arg = values[argc - 1 - i];
229  DCHECK(!receiver.is(arg));
230  DCHECK(!scratch_in.is(arg));
231  __ push(arg);
232  }
233  DCHECK(optimization.is_simple_api_call());
234 
235  // Abi for CallApiFunctionStub.
236  Register callee = r0;
237  Register call_data = r4;
238  Register holder = r2;
239  Register api_function_address = r1;
240 
241  // Put holder in place.
242  CallOptimization::HolderLookup holder_lookup;
243  Handle<JSObject> api_holder =
244  optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
245  switch (holder_lookup) {
246  case CallOptimization::kHolderIsReceiver:
247  __ Move(holder, receiver);
248  break;
249  case CallOptimization::kHolderFound:
250  __ Move(holder, api_holder);
251  break;
252  case CallOptimization::kHolderNotFound:
253  UNREACHABLE();
254  break;
255  }
256 
257  Isolate* isolate = masm->isolate();
258  Handle<JSFunction> function = optimization.constant_function();
259  Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
260  Handle<Object> call_data_obj(api_call_info->data(), isolate);
261 
262  // Put callee in place.
263  __ Move(callee, function);
264 
265  bool call_data_undefined = false;
266  // Put call_data in place.
267  if (isolate->heap()->InNewSpace(*call_data_obj)) {
268  __ Move(call_data, api_call_info);
269  __ ldr(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset));
270  } else if (call_data_obj->IsUndefined()) {
271  call_data_undefined = true;
272  __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
273  } else {
274  __ Move(call_data, call_data_obj);
275  }
276 
277  // Put api_function_address in place.
278  Address function_address = v8::ToCData<Address>(api_call_info->callback());
279  ApiFunction fun(function_address);
280  ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
281  ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
282  __ mov(api_function_address, Operand(ref));
283 
284  // Jump to stub.
285  CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
286  __ TailCallStub(&stub);
287 }
288 
289 
290 void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
291  // Push receiver, key and value for runtime call.
294 
295  // The slow case calls into the runtime to complete the store without causing
296  // an IC miss that would otherwise cause a transition to the generic stub.
297  ExternalReference ref =
298  ExternalReference(IC_Utility(IC::kStoreIC_Slow), masm->isolate());
299  __ TailCallExternalReference(ref, 3, 1);
300 }
301 
302 
303 void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
304  // Push receiver, key and value for runtime call.
307 
308  // The slow case calls into the runtime to complete the store without causing
309  // an IC miss that would otherwise cause a transition to the generic stub.
310  ExternalReference ref =
311  ExternalReference(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate());
312  __ TailCallExternalReference(ref, 3, 1);
313 }
314 
315 
316 #undef __
317 #define __ ACCESS_MASM(masm())
318 
319 
321  Handle<Name> name) {
322  if (!label->is_unused()) {
323  __ bind(label);
324  __ mov(this->name(), Operand(name));
325  }
326 }
327 
328 
329 // Generate StoreTransition code, value is passed in r0 register.
330 // When leaving generated code after success, the receiver_reg and name_reg
331 // may be clobbered. Upon branch to miss_label, the receiver and name
332 // registers have their original values.
334  Handle<Map> transition, Handle<Name> name, Register receiver_reg,
335  Register storage_reg, Register value_reg, Register scratch1,
336  Register scratch2, Register scratch3, Label* miss_label, Label* slow) {
337  // r0 : value
338  Label exit;
339 
340  int descriptor = transition->LastAdded();
341  DescriptorArray* descriptors = transition->instance_descriptors();
342  PropertyDetails details = descriptors->GetDetails(descriptor);
343  Representation representation = details.representation();
344  DCHECK(!representation.IsNone());
345 
346  if (details.type() == CONSTANT) {
347  Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
348  __ Move(scratch1, constant);
349  __ cmp(value_reg, scratch1);
350  __ b(ne, miss_label);
351  } else if (representation.IsSmi()) {
352  __ JumpIfNotSmi(value_reg, miss_label);
353  } else if (representation.IsHeapObject()) {
354  __ JumpIfSmi(value_reg, miss_label);
355  HeapType* field_type = descriptors->GetFieldType(descriptor);
356  HeapType::Iterator<Map> it = field_type->Classes();
357  if (!it.Done()) {
358  __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
359  Label do_store;
360  while (true) {
361  __ CompareMap(scratch1, it.Current(), &do_store);
362  it.Advance();
363  if (it.Done()) {
364  __ b(ne, miss_label);
365  break;
366  }
367  __ b(eq, &do_store);
368  }
369  __ bind(&do_store);
370  }
371  } else if (representation.IsDouble()) {
372  Label do_store, heap_number;
373  __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex);
374  __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow,
376 
377  __ JumpIfNotSmi(value_reg, &heap_number);
378  __ SmiUntag(scratch1, value_reg);
379  __ vmov(s0, scratch1);
380  __ vcvt_f64_s32(d0, s0);
381  __ jmp(&do_store);
382 
383  __ bind(&heap_number);
384  __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label,
386  __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
387 
388  __ bind(&do_store);
389  __ vstr(d0, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
390  }
391 
392  // Stub never generated for objects that require access checks.
393  DCHECK(!transition->is_access_check_needed());
394 
395  // Perform map transition for the receiver if necessary.
396  if (details.type() == FIELD &&
397  Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
398  // The properties must be extended before we can store the value.
399  // We jump to a runtime call that extends the properties array.
400  __ push(receiver_reg);
401  __ mov(r2, Operand(transition));
402  __ Push(r2, r0);
403  __ TailCallExternalReference(
404  ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
405  isolate()),
406  3, 1);
407  return;
408  }
409 
410  // Update the map of the object.
411  __ mov(scratch1, Operand(transition));
412  __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
413 
414  // Update the write barrier for the map field.
415  __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
418 
419  if (details.type() == CONSTANT) {
420  DCHECK(value_reg.is(r0));
421  __ Ret();
422  return;
423  }
424 
425  int index = transition->instance_descriptors()->GetFieldIndex(
426  transition->LastAdded());
427 
428  // Adjust for the number of properties stored in the object. Even in the
429  // face of a transition we can use the old map here because the size of the
430  // object and the number of in-object properties is not going to change.
431  index -= transition->inobject_properties();
432 
433  // TODO(verwaest): Share this code as a code stub.
434  SmiCheck smi_check =
435  representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
436  if (index < 0) {
437  // Set the property straight into the object.
438  int offset = transition->instance_size() + (index * kPointerSize);
439  if (representation.IsDouble()) {
440  __ str(storage_reg, FieldMemOperand(receiver_reg, offset));
441  } else {
442  __ str(value_reg, FieldMemOperand(receiver_reg, offset));
443  }
444 
445  if (!representation.IsSmi()) {
446  // Update the write barrier for the array address.
447  if (!representation.IsDouble()) {
448  __ mov(storage_reg, value_reg);
449  }
450  __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
452  EMIT_REMEMBERED_SET, smi_check);
453  }
454  } else {
455  // Write to the properties array.
456  int offset = index * kPointerSize + FixedArray::kHeaderSize;
457  // Get the properties array
458  __ ldr(scratch1,
460  if (representation.IsDouble()) {
461  __ str(storage_reg, FieldMemOperand(scratch1, offset));
462  } else {
463  __ str(value_reg, FieldMemOperand(scratch1, offset));
464  }
465 
466  if (!representation.IsSmi()) {
467  // Update the write barrier for the array address.
468  if (!representation.IsDouble()) {
469  __ mov(storage_reg, value_reg);
470  }
471  __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
473  EMIT_REMEMBERED_SET, smi_check);
474  }
475  }
476 
477  // Return the value (register r0).
478  DCHECK(value_reg.is(r0));
479  __ bind(&exit);
480  __ Ret();
481 }
482 
483 
484 void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
485  Register value_reg,
486  Label* miss_label) {
487  DCHECK(lookup->representation().IsHeapObject());
488  __ JumpIfSmi(value_reg, miss_label);
489  HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
490  __ ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
491  Label do_store;
492  while (true) {
493  __ CompareMap(scratch1(), it.Current(), &do_store);
494  it.Advance();
495  if (it.Done()) {
496  __ b(ne, miss_label);
497  break;
498  }
499  __ b(eq, &do_store);
500  }
501  __ bind(&do_store);
502 
503  StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
504  lookup->representation());
505  GenerateTailCall(masm(), stub.GetCode());
506 }
507 
508 
510  Register object_reg, Register holder_reg, Register scratch1,
511  Register scratch2, Handle<Name> name, Label* miss,
512  PrototypeCheckType check) {
513  Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
514 
515  // Make sure there's no overlap between holder and object registers.
516  DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
517  DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
518  !scratch2.is(scratch1));
519 
520  // Keep track of the current object in register reg.
521  Register reg = object_reg;
522  int depth = 0;
523 
524  Handle<JSObject> current = Handle<JSObject>::null();
525  if (type()->IsConstant()) {
526  current = Handle<JSObject>::cast(type()->AsConstant()->Value());
527  }
528  Handle<JSObject> prototype = Handle<JSObject>::null();
529  Handle<Map> current_map = receiver_map;
530  Handle<Map> holder_map(holder()->map());
531  // Traverse the prototype chain and check the maps in the prototype chain for
532  // fast and global objects or do negative lookup for normal objects.
533  while (!current_map.is_identical_to(holder_map)) {
534  ++depth;
535 
536  // Only global objects and objects that do not require access
537  // checks are allowed in stubs.
538  DCHECK(current_map->IsJSGlobalProxyMap() ||
539  !current_map->is_access_check_needed());
540 
541  prototype = handle(JSObject::cast(current_map->prototype()));
542  if (current_map->is_dictionary_map() &&
543  !current_map->IsJSGlobalObjectMap()) {
544  DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
545  if (!name->IsUniqueName()) {
546  DCHECK(name->IsString());
547  name = factory()->InternalizeString(Handle<String>::cast(name));
548  }
549  DCHECK(current.is_null() ||
550  current->property_dictionary()->FindEntry(name) ==
552 
553  GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
554  scratch2);
555 
556  __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
557  reg = holder_reg; // From now on the object will be in holder_reg.
558  __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
559  } else {
560  Register map_reg = scratch1;
561  if (depth != 1 || check == CHECK_ALL_MAPS) {
562  // CheckMap implicitly loads the map of |reg| into |map_reg|.
563  __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
564  } else {
565  __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
566  }
567 
568  // Check access rights to the global object. This has to happen after
569  // the map check so that we know that the object is actually a global
570  // object.
571  // This allows us to install generated handlers for accesses to the
572  // global proxy (as opposed to using slow ICs). See corresponding code
573  // in LookupForRead().
574  if (current_map->IsJSGlobalProxyMap()) {
575  __ CheckAccessGlobalProxy(reg, scratch2, miss);
576  } else if (current_map->IsJSGlobalObjectMap()) {
578  name, scratch2, miss);
579  }
580 
581  reg = holder_reg; // From now on the object will be in holder_reg.
582 
583  // Two possible reasons for loading the prototype from the map:
584  // (1) Can't store references to new space in code.
585  // (2) Handler is shared for all receivers with the same prototype
586  // map (but not necessarily the same prototype instance).
587  bool load_prototype_from_map =
588  heap()->InNewSpace(*prototype) || depth == 1;
589  if (load_prototype_from_map) {
590  __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
591  } else {
592  __ mov(reg, Operand(prototype));
593  }
594  }
595 
596  // Go to the next object in the prototype chain.
597  current = prototype;
598  current_map = handle(current->map());
599  }
600 
601  // Log the check depth.
602  LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
603 
604  if (depth != 0 || check == CHECK_ALL_MAPS) {
605  // Check the holder map.
606  __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
607  }
608 
609  // Perform security check for access to the global object.
610  DCHECK(current_map->IsJSGlobalProxyMap() ||
611  !current_map->is_access_check_needed());
612  if (current_map->IsJSGlobalProxyMap()) {
613  __ CheckAccessGlobalProxy(reg, scratch1, miss);
614  }
615 
616  // Return the register containing the holder.
617  return reg;
618 }
619 
620 
621 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
622  if (!miss->is_unused()) {
623  Label success;
624  __ b(&success);
625  __ bind(miss);
626  TailCallBuiltin(masm(), MissBuiltin(kind()));
627  __ bind(&success);
628  }
629 }
630 
631 
632 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
633  if (!miss->is_unused()) {
634  Label success;
635  __ b(&success);
636  GenerateRestoreName(miss, name);
637  TailCallBuiltin(masm(), MissBuiltin(kind()));
638  __ bind(&success);
639  }
640 }
641 
642 
643 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
644  // Return the constant value.
645  __ Move(r0, value);
646  __ Ret();
647 }
648 
649 
651  Register reg, Handle<ExecutableAccessorInfo> callback) {
652  // Build AccessorInfo::args_ list on the stack and push property name below
653  // the exit frame to make GC aware of them and store pointers to them.
661  DCHECK(!scratch2().is(reg));
662  DCHECK(!scratch3().is(reg));
663  DCHECK(!scratch4().is(reg));
664  __ push(receiver());
665  if (heap()->InNewSpace(callback->data())) {
666  __ Move(scratch3(), callback);
667  __ ldr(scratch3(),
669  } else {
670  __ Move(scratch3(), Handle<Object>(callback->data(), isolate()));
671  }
672  __ push(scratch3());
673  __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
674  __ mov(scratch4(), scratch3());
675  __ Push(scratch3(), scratch4());
676  __ mov(scratch4(), Operand(ExternalReference::isolate_address(isolate())));
677  __ Push(scratch4(), reg);
678  __ mov(scratch2(), sp); // scratch2 = PropertyAccessorInfo::args_
679  __ push(name());
680 
681  // Abi for CallApiGetter
682  Register getter_address_reg = ApiGetterDescriptor::function_address();
683 
684  Address getter_address = v8::ToCData<Address>(callback->getter());
685  ApiFunction fun(getter_address);
686  ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
687  ExternalReference ref = ExternalReference(&fun, type, isolate());
688  __ mov(getter_address_reg, Operand(ref));
689 
690  CallApiGetterStub stub(isolate());
691  __ TailCallStub(&stub);
692 }
693 
694 
696  LookupIterator* it, Register holder_reg) {
697  DCHECK(holder()->HasNamedInterceptor());
698  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
699 
700  // Compile the interceptor call, followed by inline code to load the
701  // property from further up the prototype chain if the call fails.
702  // Check that the maps haven't changed.
703  DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
704 
705  // Preserve the receiver register explicitly whenever it is different from the
706  // holder and it is needed should the interceptor return without any result.
707  // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
708  // case might cause a miss during the prototype check.
709  bool must_perform_prototype_check =
710  !holder().is_identical_to(it->GetHolder<JSObject>());
711  bool must_preserve_receiver_reg =
712  !receiver().is(holder_reg) &&
713  (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
714 
715  // Save necessary data before invoking an interceptor.
716  // Requires a frame to make GC aware of pushed pointers.
717  {
718  FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
719  if (must_preserve_receiver_reg) {
720  __ Push(receiver(), holder_reg, this->name());
721  } else {
722  __ Push(holder_reg, this->name());
723  }
724  // Invoke an interceptor. Note: map checks from receiver to
725  // interceptor's holder has been compiled before (see a caller
726  // of this method.)
727  CompileCallLoadPropertyWithInterceptor(
728  masm(), receiver(), holder_reg, this->name(), holder(),
729  IC::kLoadPropertyWithInterceptorOnly);
730 
731  // Check if interceptor provided a value for property. If it's
732  // the case, return immediately.
733  Label interceptor_failed;
734  __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
735  __ cmp(r0, scratch1());
736  __ b(eq, &interceptor_failed);
737  frame_scope.GenerateLeaveFrame();
738  __ Ret();
739 
740  __ bind(&interceptor_failed);
741  __ pop(this->name());
742  __ pop(holder_reg);
743  if (must_preserve_receiver_reg) {
744  __ pop(receiver());
745  }
746  // Leave the internal frame.
747  }
748 
749  GenerateLoadPostInterceptor(it, holder_reg);
750 }
751 
752 
753 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
754  // Call the runtime system to load the interceptor.
755  DCHECK(holder()->HasNamedInterceptor());
756  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
757  PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
758  holder());
759 
760  ExternalReference ref = ExternalReference(
761  IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
762  __ TailCallExternalReference(
764 }
765 
766 
768  Handle<JSObject> object, Handle<Name> name,
769  Handle<ExecutableAccessorInfo> callback) {
770  Register holder_reg = Frontend(receiver(), name);
771 
772  __ push(receiver()); // receiver
773  __ push(holder_reg);
774  __ mov(ip, Operand(callback)); // callback info
775  __ push(ip);
776  __ mov(ip, Operand(name));
777  __ Push(ip, value());
778 
779  // Do tail-call to the runtime system.
780  ExternalReference store_callback_property =
781  ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
782  __ TailCallExternalReference(store_callback_property, 5, 1);
783 
784  // Return the generated code.
785  return GetCode(kind(), Code::FAST, name);
786 }
787 
788 
790  Handle<Name> name) {
791  __ Push(receiver(), this->name(), value());
792 
793  // Do tail-call to the runtime system.
794  ExternalReference store_ic_property = ExternalReference(
795  IC_Utility(IC::kStorePropertyWithInterceptor), isolate());
796  __ TailCallExternalReference(store_ic_property, 3, 1);
797 
798  // Return the generated code.
799  return GetCode(kind(), Code::FAST, name);
800 }
801 
802 
805 }
806 
807 
809  Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
810  Label miss;
811  FrontendHeader(receiver(), name, &miss);
812 
813  // Get the value from the cell.
814  Register result = StoreDescriptor::ValueRegister();
815  __ mov(result, Operand(cell));
816  __ ldr(result, FieldMemOperand(result, Cell::kValueOffset));
817 
818  // Check for deleted property if property can actually be deleted.
819  if (is_configurable) {
820  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
821  __ cmp(result, ip);
822  __ b(eq, &miss);
823  }
824 
825  Counters* counters = isolate()->counters();
826  __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
827  __ Ret();
828 
829  FrontendFooter(name, &miss);
830 
831  // Return the generated code.
832  return GetCode(kind(), Code::NORMAL, name);
833 }
834 
835 
836 #undef __
837 }
838 } // namespace v8::internal
839 
840 #endif // V8_TARGET_ARCH_ARM
static const Register function_address()
static const int kDataOffset
Definition: objects.h:10420
static const int kValueOffset
Definition: objects.h:9446
static int SlotOffset(int index)
Definition: contexts.h:552
static void GenerateStoreSlow(MacroAssembler *masm)
static const int kHeaderSize
Definition: objects.h:2393
static const int kNativeContextOffset
Definition: objects.h:7459
static const int kGlobalProxyOffset
Definition: objects.h:7461
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
static Handle< T > null()
Definition: handles.h:123
static const int kNotFound
Definition: objects.h:3283
static const int kValueOffset
Definition: objects.h:1506
static const int kMapOffset
Definition: objects.h:1427
static Handle< Map > TypeToMap(HeapType *type, Isolate *isolate)
Definition: ic.cc:719
static Handle< PropertyCell > EnsurePropertyCell(Handle< JSGlobalObject > global, Handle< Name > name)
Definition: objects.cc:14576
static const int kPropertiesOffset
Definition: objects.h:2193
static const int kBitFieldOffset
Definition: objects.h:6228
static const int kIsAccessCheckNeeded
Definition: objects.h:6246
static const int kInstanceTypeOffset
Definition: objects.h:6229
static const int kHasNamedInterceptor
Definition: objects.h:6242
static const int kPrototypeOffset
Definition: objects.h:6190
static void GenerateNegativeLookup(MacroAssembler *masm, Label *miss, Label *done, Register receiver, Register properties, Handle< Name > name, Register scratch0)
Handle< Code > CompileLoadGlobal(Handle< PropertyCell > cell, Handle< Name > name, bool is_configurable)
virtual void FrontendFooter(Handle< Name > name, Label *miss)
static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler *masm, int index, Register prototype, Label *miss)
void GenerateLoadInterceptorWithFollowup(LookupIterator *it, Register holder_reg)
virtual Register FrontendHeader(Register object_reg, Handle< Name > name, Label *miss)
void GenerateLoadConstant(Handle< Object > value)
void GenerateLoadInterceptor(Register holder_reg)
static void GenerateLoadFunctionPrototype(MacroAssembler *masm, Register receiver, Register scratch1, Register scratch2, Label *miss_label)
void GenerateLoadPostInterceptor(LookupIterator *it, Register reg)
static void GenerateLoadViaGetter(MacroAssembler *masm, Handle< HeapType > type, Register receiver, Handle< JSFunction > getter)
void GenerateLoadCallback(Register reg, Handle< ExecutableAccessorInfo > callback)
Handle< Code > CompileStoreInterceptor(Handle< Name > name)
virtual void FrontendFooter(Handle< Name > name, Label *miss)
void GenerateStoreField(LookupIterator *lookup, Register value_reg, Label *miss_label)
Handle< Code > CompileStoreCallback(Handle< JSObject > object, Handle< Name > name, Handle< ExecutableAccessorInfo > callback)
static void GenerateSlow(MacroAssembler *masm)
void GenerateRestoreName(Label *label, Handle< Name > name)
void GenerateStoreTransition(Handle< Map > transition, Handle< Name > name, Register receiver_reg, Register name_reg, Register value_reg, Register scratch1, Register scratch2, Register scratch3, Label *miss_label, Label *slow)
static void GenerateStoreViaSetter(MacroAssembler *masm, Handle< HeapType > type, Register receiver, Handle< JSFunction > setter)
static const int kReturnValueDefaultValueIndex
Definition: arguments.h:160
Handle< JSObject > holder() const
Register CheckPrototypes(Register object_reg, Register holder_reg, Register scratch1, Register scratch2, Handle< Name > name, Label *miss, PrototypeCheckType check=CHECK_ALL_MAPS)
Handle< Code > GetCode(Code::Kind kind, Code::StubType type, Handle< Name > name)
Handle< HeapType > type() const
static void GenerateDictionaryNegativeLookup(MacroAssembler *masm, Label *miss_label, Register receiver, Handle< Name > name, Register r0, Register r1)
static void GenerateFastApiCall(MacroAssembler *masm, const CallOptimization &optimization, Handle< Map > receiver_map, Register receiver, Register scratch, bool is_store, int argc, Register *values)
Register Frontend(Register object_reg, Handle< Name > name)
static void GenerateCheckPropertyCell(MacroAssembler *masm, Handle< JSGlobalObject > global, Handle< Name > name, Register scratch, Label *miss)
static const int kContextOffset
Definition: frames.h:162
static const Register ReceiverRegister()
static const Register NameRegister()
static const Register ValueRegister()
#define __
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
#define LOG(isolate, Call)
Definition: log.h:69
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
@ CALL_FUNCTION
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Definition: scheduler.cc:773
const int kPointerSize
Definition: globals.h:129
const Register r2
@ DONT_DO_SMI_CHECK
Definition: globals.h:640
const Register cp
TypeImpl< ZoneTypeConfig > Type
const Register r0
const LowDwVfpRegister d0
const Register ip
const SwVfpRegister s0
const Register r3
const Register fp
const Register sp
TypeImpl< HeapTypeConfig > HeapType
Definition: list.h:191
@ FIRST_SPEC_OBJECT_TYPE
Definition: objects.h:781
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:146
const Register r4
MemOperand FieldMemOperand(Register object, int offset)
byte * Address
Definition: globals.h:101
const Register r1
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20