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