V8 Project
handler-compiler-arm64.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_ARM64
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, Label* miss_label, Register receiver,
21  Handle<Name> name, Register scratch0, Register scratch1) {
22  DCHECK(!AreAliased(receiver, scratch0, scratch1));
23  DCHECK(name->IsUniqueName());
24  Counters* counters = masm->isolate()->counters();
25  __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
26  __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
27 
28  Label done;
29 
30  const int kInterceptorOrAccessCheckNeededMask =
32 
33  // Bail out if the receiver has a named interceptor or requires access checks.
34  Register map = scratch1;
36  __ Ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
37  __ Tst(scratch0, kInterceptorOrAccessCheckNeededMask);
38  __ B(ne, miss_label);
39 
40  // Check that receiver is a JSObject.
42  __ Cmp(scratch0, FIRST_SPEC_OBJECT_TYPE);
43  __ B(lt, miss_label);
44 
45  // Load properties array.
46  Register properties = scratch0;
47  __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
48  // Check that the properties array is a dictionary.
49  __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
50  __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label);
51 
53  masm, miss_label, &done, receiver, properties, name, scratch1);
54  __ Bind(&done);
55  __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
56 }
57 
58 
60  MacroAssembler* masm, int index, Register prototype, Label* miss) {
61  Isolate* isolate = masm->isolate();
62  // Get the global function with the given index.
63  Handle<JSFunction> function(
64  JSFunction::cast(isolate->native_context()->get(index)));
65 
66  // Check we're still in the same context.
67  Register scratch = prototype;
68  __ Ldr(scratch, GlobalObjectMemOperand());
70  __ Ldr(scratch, ContextMemOperand(scratch, index));
71  __ Cmp(scratch, Operand(function));
72  __ B(ne, miss);
73 
74  // Load its initial map. The global functions all have initial maps.
75  __ Mov(prototype, Operand(Handle<Map>(function->initial_map())));
76  // Load the prototype from the initial map.
77  __ Ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
78 }
79 
80 
82  MacroAssembler* masm, Register receiver, Register scratch1,
83  Register scratch2, Label* miss_label) {
84  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
85  // TryGetFunctionPrototype can't put the result directly in x0 because the
86  // 3 inputs registers can't alias and we call this function from
87  // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly
88  // move the result in x0.
89  __ Mov(x0, scratch1);
90  __ Ret();
91 }
92 
93 
94 // Generate code to check that a global property cell is empty. Create
95 // the property cell at compilation time if no cell exists for the
96 // property.
98  MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
99  Register scratch, Label* miss) {
100  Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
101  DCHECK(cell->value()->IsTheHole());
102  __ Mov(scratch, Operand(cell));
103  __ Ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
104  __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
105 }
106 
107 
108 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
109  Register holder, Register name,
110  Handle<JSObject> holder_obj) {
116 
117  __ Push(name);
118  Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
119  DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor));
120  Register scratch = name;
121  __ Mov(scratch, Operand(interceptor));
122  __ Push(scratch, receiver, holder);
123 }
124 
125 
126 static void CompileCallLoadPropertyWithInterceptor(
127  MacroAssembler* masm, Register receiver, Register holder, Register name,
128  Handle<JSObject> holder_obj, IC::UtilityId id) {
129  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
130 
131  __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()),
133 }
134 
135 
136 // Generate call to api function.
138  MacroAssembler* masm, const CallOptimization& optimization,
139  Handle<Map> receiver_map, Register receiver, Register scratch,
140  bool is_store, int argc, Register* values) {
141  DCHECK(!AreAliased(receiver, scratch));
142 
143  MacroAssembler::PushPopQueue queue(masm);
144  queue.Queue(receiver);
145  // Write the arguments to the stack frame.
146  for (int i = 0; i < argc; i++) {
147  Register arg = values[argc - 1 - i];
148  DCHECK(!AreAliased(receiver, scratch, arg));
149  queue.Queue(arg);
150  }
151  queue.PushQueued();
152 
153  DCHECK(optimization.is_simple_api_call());
154 
155  // Abi for CallApiFunctionStub.
156  Register callee = x0;
157  Register call_data = x4;
158  Register holder = x2;
159  Register api_function_address = x1;
160 
161  // Put holder in place.
162  CallOptimization::HolderLookup holder_lookup;
163  Handle<JSObject> api_holder =
164  optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
165  switch (holder_lookup) {
166  case CallOptimization::kHolderIsReceiver:
167  __ Mov(holder, receiver);
168  break;
169  case CallOptimization::kHolderFound:
170  __ LoadObject(holder, api_holder);
171  break;
172  case CallOptimization::kHolderNotFound:
173  UNREACHABLE();
174  break;
175  }
176 
177  Isolate* isolate = masm->isolate();
178  Handle<JSFunction> function = optimization.constant_function();
179  Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
180  Handle<Object> call_data_obj(api_call_info->data(), isolate);
181 
182  // Put callee in place.
183  __ LoadObject(callee, function);
184 
185  bool call_data_undefined = false;
186  // Put call_data in place.
187  if (isolate->heap()->InNewSpace(*call_data_obj)) {
188  __ LoadObject(call_data, api_call_info);
189  __ Ldr(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset));
190  } else if (call_data_obj->IsUndefined()) {
191  call_data_undefined = true;
192  __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
193  } else {
194  __ LoadObject(call_data, call_data_obj);
195  }
196 
197  // Put api_function_address in place.
198  Address function_address = v8::ToCData<Address>(api_call_info->callback());
199  ApiFunction fun(function_address);
200  ExternalReference ref = ExternalReference(
201  &fun, ExternalReference::DIRECT_API_CALL, masm->isolate());
202  __ Mov(api_function_address, ref);
203 
204  // Jump to stub.
205  CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
206  __ TailCallStub(&stub);
207 }
208 
209 
211  MacroAssembler* masm, Handle<HeapType> type, Register receiver,
212  Handle<JSFunction> setter) {
213  // ----------- S t a t e -------------
214  // -- lr : return address
215  // -----------------------------------
216  Label miss;
217 
218  {
219  FrameScope scope(masm, StackFrame::INTERNAL);
220 
221  // Save value register, so we can restore it later.
222  __ Push(value());
223 
224  if (!setter.is_null()) {
225  // Call the JavaScript setter with receiver and value on the stack.
226  if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
227  // Swap in the global receiver.
228  __ Ldr(receiver,
230  }
231  __ Push(receiver, value());
232  ParameterCount actual(1);
233  ParameterCount expected(setter);
234  __ InvokeFunction(setter, expected, actual, CALL_FUNCTION,
235  NullCallWrapper());
236  } else {
237  // If we generate a global code snippet for deoptimization only, remember
238  // the place to continue after deoptimization.
239  masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
240  }
241 
242  // We have to return the passed value, not the return value of the setter.
243  __ Pop(x0);
244 
245  // Restore context register.
247  }
248  __ Ret();
249 }
250 
251 
253  MacroAssembler* masm, Handle<HeapType> type, Register receiver,
254  Handle<JSFunction> getter) {
255  {
256  FrameScope scope(masm, StackFrame::INTERNAL);
257 
258  if (!getter.is_null()) {
259  // Call the JavaScript getter with the receiver on the stack.
260  if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
261  // Swap in the global receiver.
262  __ Ldr(receiver,
264  }
265  __ Push(receiver);
266  ParameterCount actual(0);
267  ParameterCount expected(getter);
268  __ InvokeFunction(getter, expected, actual, CALL_FUNCTION,
269  NullCallWrapper());
270  } else {
271  // If we generate a global code snippet for deoptimization only, remember
272  // the place to continue after deoptimization.
273  masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
274  }
275 
276  // Restore context register.
278  }
279  __ Ret();
280 }
281 
282 
283 void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
284  // Push receiver, name and value for runtime call.
287 
288  // The slow case calls into the runtime to complete the store without causing
289  // an IC miss that would otherwise cause a transition to the generic stub.
290  ExternalReference ref =
291  ExternalReference(IC_Utility(IC::kStoreIC_Slow), masm->isolate());
292  __ TailCallExternalReference(ref, 3, 1);
293 }
294 
295 
296 void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
297  ASM_LOCATION("ElementHandlerCompiler::GenerateStoreSlow");
298 
299  // Push receiver, key and value for runtime call.
302 
303  // The slow case calls into the runtime to complete the store without causing
304  // an IC miss that would otherwise cause a transition to the generic stub.
305  ExternalReference ref =
306  ExternalReference(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate());
307  __ TailCallExternalReference(ref, 3, 1);
308 }
309 
310 
311 #undef __
312 #define __ ACCESS_MASM(masm())
313 
314 
316  Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
317  Label miss;
318  FrontendHeader(receiver(), name, &miss);
319 
320  // Get the value from the cell.
321  Register result = StoreDescriptor::ValueRegister();
322  __ Mov(result, Operand(cell));
323  __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
324 
325  // Check for deleted property if property can actually be deleted.
326  if (is_configurable) {
327  __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
328  }
329 
330  Counters* counters = isolate()->counters();
331  __ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3);
332  __ Ret();
333 
334  FrontendFooter(name, &miss);
335 
336  // Return the generated code.
337  return GetCode(kind(), Code::NORMAL, name);
338 }
339 
340 
342  Handle<Name> name) {
343  Label miss;
344 
345  ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreInterceptor");
346 
347  __ Push(receiver(), this->name(), value());
348 
349  // Do tail-call to the runtime system.
350  ExternalReference store_ic_property = ExternalReference(
351  IC_Utility(IC::kStorePropertyWithInterceptor), isolate());
352  __ TailCallExternalReference(store_ic_property, 3, 1);
353 
354  // Return the generated code.
355  return GetCode(kind(), Code::FAST, name);
356 }
357 
358 
361 }
362 
363 
365  Handle<Name> name) {
366  if (!label->is_unused()) {
367  __ Bind(label);
368  __ Mov(this->name(), Operand(name));
369  }
370 }
371 
372 
373 // Generate StoreTransition code, value is passed in x0 register.
374 // When leaving generated code after success, the receiver_reg and storage_reg
375 // may be clobbered. Upon branch to miss_label, the receiver and name registers
376 // have their original values.
378  Handle<Map> transition, Handle<Name> name, Register receiver_reg,
379  Register storage_reg, Register value_reg, Register scratch1,
380  Register scratch2, Register scratch3, Label* miss_label, Label* slow) {
381  Label exit;
382 
383  DCHECK(!AreAliased(receiver_reg, storage_reg, value_reg, scratch1, scratch2,
384  scratch3));
385 
386  // We don't need scratch3.
387  scratch3 = NoReg;
388 
389  int descriptor = transition->LastAdded();
390  DescriptorArray* descriptors = transition->instance_descriptors();
391  PropertyDetails details = descriptors->GetDetails(descriptor);
392  Representation representation = details.representation();
393  DCHECK(!representation.IsNone());
394 
395  if (details.type() == CONSTANT) {
396  Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
397  __ LoadObject(scratch1, constant);
398  __ Cmp(value_reg, scratch1);
399  __ B(ne, miss_label);
400  } else if (representation.IsSmi()) {
401  __ JumpIfNotSmi(value_reg, miss_label);
402  } else if (representation.IsHeapObject()) {
403  __ JumpIfSmi(value_reg, miss_label);
404  HeapType* field_type = descriptors->GetFieldType(descriptor);
405  HeapType::Iterator<Map> it = field_type->Classes();
406  if (!it.Done()) {
407  __ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
408  Label do_store;
409  while (true) {
410  __ CompareMap(scratch1, it.Current());
411  it.Advance();
412  if (it.Done()) {
413  __ B(ne, miss_label);
414  break;
415  }
416  __ B(eq, &do_store);
417  }
418  __ Bind(&do_store);
419  }
420  } else if (representation.IsDouble()) {
421  UseScratchRegisterScope temps(masm());
422  DoubleRegister temp_double = temps.AcquireD();
423  __ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag);
424 
425  Label do_store;
426  __ JumpIfSmi(value_reg, &do_store);
427 
428  __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label,
430  __ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
431 
432  __ Bind(&do_store);
433  __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double,
434  NoReg, MUTABLE);
435  }
436 
437  // Stub never generated for objects that require access checks.
438  DCHECK(!transition->is_access_check_needed());
439 
440  // Perform map transition for the receiver if necessary.
441  if (details.type() == FIELD &&
442  Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
443  // The properties must be extended before we can store the value.
444  // We jump to a runtime call that extends the properties array.
445  __ Mov(scratch1, Operand(transition));
446  __ Push(receiver_reg, scratch1, value_reg);
447  __ TailCallExternalReference(
448  ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
449  isolate()),
450  3, 1);
451  return;
452  }
453 
454  // Update the map of the object.
455  __ Mov(scratch1, Operand(transition));
456  __ Str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
457 
458  // Update the write barrier for the map field.
459  __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
462 
463  if (details.type() == CONSTANT) {
464  DCHECK(value_reg.is(x0));
465  __ Ret();
466  return;
467  }
468 
469  int index = transition->instance_descriptors()->GetFieldIndex(
470  transition->LastAdded());
471 
472  // Adjust for the number of properties stored in the object. Even in the
473  // face of a transition we can use the old map here because the size of the
474  // object and the number of in-object properties is not going to change.
475  index -= transition->inobject_properties();
476 
477  // TODO(verwaest): Share this code as a code stub.
478  SmiCheck smi_check =
479  representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
480  Register prop_reg = representation.IsDouble() ? storage_reg : value_reg;
481  if (index < 0) {
482  // Set the property straight into the object.
483  int offset = transition->instance_size() + (index * kPointerSize);
484  __ Str(prop_reg, FieldMemOperand(receiver_reg, offset));
485 
486  if (!representation.IsSmi()) {
487  // Update the write barrier for the array address.
488  if (!representation.IsDouble()) {
489  __ Mov(storage_reg, value_reg);
490  }
491  __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
493  EMIT_REMEMBERED_SET, smi_check);
494  }
495  } else {
496  // Write to the properties array.
497  int offset = index * kPointerSize + FixedArray::kHeaderSize;
498  // Get the properties array
499  __ Ldr(scratch1,
501  __ Str(prop_reg, FieldMemOperand(scratch1, offset));
502 
503  if (!representation.IsSmi()) {
504  // Update the write barrier for the array address.
505  if (!representation.IsDouble()) {
506  __ Mov(storage_reg, value_reg);
507  }
508  __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
510  EMIT_REMEMBERED_SET, smi_check);
511  }
512  }
513 
514  __ Bind(&exit);
515  // Return the value (register x0).
516  DCHECK(value_reg.is(x0));
517  __ Ret();
518 }
519 
520 
521 void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
522  Register value_reg,
523  Label* miss_label) {
524  DCHECK(lookup->representation().IsHeapObject());
525  __ JumpIfSmi(value_reg, miss_label);
526  HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
527  __ Ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
528  Label do_store;
529  while (true) {
530  __ CompareMap(scratch1(), it.Current());
531  it.Advance();
532  if (it.Done()) {
533  __ B(ne, miss_label);
534  break;
535  }
536  __ B(eq, &do_store);
537  }
538  __ Bind(&do_store);
539 
540  StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
541  lookup->representation());
542  GenerateTailCall(masm(), stub.GetCode());
543 }
544 
545 
547  Register object_reg, Register holder_reg, Register scratch1,
548  Register scratch2, Handle<Name> name, Label* miss,
549  PrototypeCheckType check) {
550  Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
551 
552  // object_reg and holder_reg registers can alias.
553  DCHECK(!AreAliased(object_reg, scratch1, scratch2));
554  DCHECK(!AreAliased(holder_reg, scratch1, scratch2));
555 
556  // Keep track of the current object in register reg.
557  Register reg = object_reg;
558  int depth = 0;
559 
560  Handle<JSObject> current = Handle<JSObject>::null();
561  if (type()->IsConstant()) {
562  current = Handle<JSObject>::cast(type()->AsConstant()->Value());
563  }
564  Handle<JSObject> prototype = Handle<JSObject>::null();
565  Handle<Map> current_map = receiver_map;
566  Handle<Map> holder_map(holder()->map());
567  // Traverse the prototype chain and check the maps in the prototype chain for
568  // fast and global objects or do negative lookup for normal objects.
569  while (!current_map.is_identical_to(holder_map)) {
570  ++depth;
571 
572  // Only global objects and objects that do not require access
573  // checks are allowed in stubs.
574  DCHECK(current_map->IsJSGlobalProxyMap() ||
575  !current_map->is_access_check_needed());
576 
577  prototype = handle(JSObject::cast(current_map->prototype()));
578  if (current_map->is_dictionary_map() &&
579  !current_map->IsJSGlobalObjectMap()) {
580  DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
581  if (!name->IsUniqueName()) {
582  DCHECK(name->IsString());
583  name = factory()->InternalizeString(Handle<String>::cast(name));
584  }
585  DCHECK(current.is_null() || (current->property_dictionary()->FindEntry(
587 
588  GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
589  scratch2);
590 
591  __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
592  reg = holder_reg; // From now on the object will be in holder_reg.
593  __ Ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
594  } else {
595  // Two possible reasons for loading the prototype from the map:
596  // (1) Can't store references to new space in code.
597  // (2) Handler is shared for all receivers with the same prototype
598  // map (but not necessarily the same prototype instance).
599  bool load_prototype_from_map =
600  heap()->InNewSpace(*prototype) || depth == 1;
601  Register map_reg = scratch1;
602  __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
603 
604  if (depth != 1 || check == CHECK_ALL_MAPS) {
605  __ CheckMap(map_reg, current_map, miss, DONT_DO_SMI_CHECK);
606  }
607 
608  // Check access rights to the global object. This has to happen after
609  // the map check so that we know that the object is actually a global
610  // object.
611  // This allows us to install generated handlers for accesses to the
612  // global proxy (as opposed to using slow ICs). See corresponding code
613  // in LookupForRead().
614  if (current_map->IsJSGlobalProxyMap()) {
615  UseScratchRegisterScope temps(masm());
616  __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss);
617  } else if (current_map->IsJSGlobalObjectMap()) {
619  name, scratch2, miss);
620  }
621 
622  reg = holder_reg; // From now on the object will be in holder_reg.
623 
624  if (load_prototype_from_map) {
625  __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
626  } else {
627  __ Mov(reg, Operand(prototype));
628  }
629  }
630 
631  // Go to the next object in the prototype chain.
632  current = prototype;
633  current_map = handle(current->map());
634  }
635 
636  // Log the check depth.
637  LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
638 
639  // Check the holder map.
640  if (depth != 0 || check == CHECK_ALL_MAPS) {
641  // Check the holder map.
642  __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
643  }
644 
645  // Perform security check for access to the global object.
646  DCHECK(current_map->IsJSGlobalProxyMap() ||
647  !current_map->is_access_check_needed());
648  if (current_map->IsJSGlobalProxyMap()) {
649  __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
650  }
651 
652  // Return the register containing the holder.
653  return reg;
654 }
655 
656 
657 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
658  if (!miss->is_unused()) {
659  Label success;
660  __ B(&success);
661 
662  __ Bind(miss);
663  TailCallBuiltin(masm(), MissBuiltin(kind()));
664 
665  __ Bind(&success);
666  }
667 }
668 
669 
670 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
671  if (!miss->is_unused()) {
672  Label success;
673  __ B(&success);
674 
675  GenerateRestoreName(miss, name);
676  TailCallBuiltin(masm(), MissBuiltin(kind()));
677 
678  __ Bind(&success);
679  }
680 }
681 
682 
683 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
684  // Return the constant value.
685  __ LoadObject(x0, value);
686  __ Ret();
687 }
688 
689 
691  Register reg, Handle<ExecutableAccessorInfo> callback) {
692  DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
693 
694  // Build ExecutableAccessorInfo::args_ list on the stack and push property
695  // name below the exit frame to make GC aware of them and store pointers to
696  // them.
704 
705  __ Push(receiver());
706 
707  if (heap()->InNewSpace(callback->data())) {
708  __ Mov(scratch3(), Operand(callback));
709  __ Ldr(scratch3(),
711  } else {
712  __ Mov(scratch3(), Operand(Handle<Object>(callback->data(), isolate())));
713  }
714  __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex);
715  __ Mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
716  __ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg, name());
717 
718  Register args_addr = scratch2();
719  __ Add(args_addr, __ StackPointer(), kPointerSize);
720 
721  // Stack at this point:
722  // sp[40] callback data
723  // sp[32] undefined
724  // sp[24] undefined
725  // sp[16] isolate
726  // args_addr -> sp[8] reg
727  // sp[0] name
728 
729  // Abi for CallApiGetter.
730  Register getter_address_reg = x2;
731 
732  // Set up the call.
733  Address getter_address = v8::ToCData<Address>(callback->getter());
734  ApiFunction fun(getter_address);
735  ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
736  ExternalReference ref = ExternalReference(&fun, type, isolate());
737  __ Mov(getter_address_reg, ref);
738 
739  CallApiGetterStub stub(isolate());
740  __ TailCallStub(&stub);
741 }
742 
743 
745  LookupIterator* it, Register holder_reg) {
746  DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
747  scratch3()));
748  DCHECK(holder()->HasNamedInterceptor());
749  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
750 
751  // Compile the interceptor call, followed by inline code to load the
752  // property from further up the prototype chain if the call fails.
753  // Check that the maps haven't changed.
754  DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
755 
756  // Preserve the receiver register explicitly whenever it is different from the
757  // holder and it is needed should the interceptor return without any result.
758  // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
759  // case might cause a miss during the prototype check.
760  bool must_perform_prototype_check =
761  !holder().is_identical_to(it->GetHolder<JSObject>());
762  bool must_preserve_receiver_reg =
763  !receiver().is(holder_reg) &&
764  (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
765 
766  // Save necessary data before invoking an interceptor.
767  // Requires a frame to make GC aware of pushed pointers.
768  {
769  FrameScope frame_scope(masm(), StackFrame::INTERNAL);
770  if (must_preserve_receiver_reg) {
771  __ Push(receiver(), holder_reg, this->name());
772  } else {
773  __ Push(holder_reg, this->name());
774  }
775  // Invoke an interceptor. Note: map checks from receiver to
776  // interceptor's holder has been compiled before (see a caller
777  // of this method.)
778  CompileCallLoadPropertyWithInterceptor(
779  masm(), receiver(), holder_reg, this->name(), holder(),
780  IC::kLoadPropertyWithInterceptorOnly);
781 
782  // Check if interceptor provided a value for property. If it's
783  // the case, return immediately.
784  Label interceptor_failed;
785  __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex,
786  &interceptor_failed);
787  frame_scope.GenerateLeaveFrame();
788  __ Ret();
789 
790  __ Bind(&interceptor_failed);
791  if (must_preserve_receiver_reg) {
792  __ Pop(this->name(), holder_reg, receiver());
793  } else {
794  __ Pop(this->name(), holder_reg);
795  }
796  // Leave the internal frame.
797  }
798 
799  GenerateLoadPostInterceptor(it, holder_reg);
800 }
801 
802 
803 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
804  // Call the runtime system to load the interceptor.
805  DCHECK(holder()->HasNamedInterceptor());
806  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
807  PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
808  holder());
809 
810  ExternalReference ref = ExternalReference(
811  IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
812  __ TailCallExternalReference(
814 }
815 
816 
818  Handle<JSObject> object, Handle<Name> name,
819  Handle<ExecutableAccessorInfo> callback) {
820  ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback");
821  Register holder_reg = Frontend(receiver(), name);
822 
823  // Stub never generated for non-global objects that require access checks.
824  DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded());
825 
826  // receiver() and holder_reg can alias.
827  DCHECK(!AreAliased(receiver(), scratch1(), scratch2(), value()));
828  DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value()));
829  __ Mov(scratch1(), Operand(callback));
830  __ Mov(scratch2(), Operand(name));
831  __ Push(receiver(), holder_reg, scratch1(), scratch2(), value());
832 
833  // Do tail-call to the runtime system.
834  ExternalReference store_callback_property =
835  ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
836  __ TailCallExternalReference(store_callback_property, 5, 1);
837 
838  // Return the generated code.
839  return GetCode(kind(), Code::FAST, name);
840 }
841 
842 
843 #undef __
844 }
845 } // namespace v8::internal
846 
847 #endif // V8_TARGET_ARCH_IA32
static const int kDataOffset
Definition: objects.h:10420
static const int kValueOffset
Definition: objects.h:9446
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
#define ASM_LOCATION(message)
@ CALL_FUNCTION
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Definition: scheduler.cc:773
const int kPointerSize
Definition: globals.h:129
@ DONT_DO_SMI_CHECK
Definition: globals.h:640
bool AreAliased(const CPURegister &reg1, const CPURegister &reg2, const CPURegister &reg3=NoReg, const CPURegister &reg4=NoReg, const CPURegister &reg5=NoReg, const CPURegister &reg6=NoReg, const CPURegister &reg7=NoReg, const CPURegister &reg8=NoReg)
const Register cp
TypeImpl< ZoneTypeConfig > Type
MemOperand GlobalObjectMemOperand()
const Register fp
DwVfpRegister DoubleRegister
TypeImpl< HeapTypeConfig > HeapType
Definition: list.h:191
MemOperand ContextMemOperand(Register context, int index)
@ FIRST_SPEC_OBJECT_TYPE
Definition: objects.h:781
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:146
MemOperand FieldMemOperand(Register object, int offset)
byte * Address
Definition: globals.h:101
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20