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