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