• 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_IA32
6 
7 #include "src/ic/handler-compiler.h"
8 
9 #include "src/api-arguments.h"
10 #include "src/field-type.h"
11 #include "src/ic/call-optimization.h"
12 #include "src/ic/ic.h"
13 #include "src/isolate-inl.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 #define __ ACCESS_MASM(masm)
19 
20 
GenerateLoadViaGetter(MacroAssembler * masm,Handle<Map> map,Register receiver,Register holder,int accessor_index,int expected_arguments,Register scratch)21 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
22     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
23     int accessor_index, int expected_arguments, Register scratch) {
24   {
25     FrameScope scope(masm, StackFrame::INTERNAL);
26 
27     // Save context register
28     __ push(esi);
29 
30     if (accessor_index >= 0) {
31       DCHECK(!holder.is(scratch));
32       DCHECK(!receiver.is(scratch));
33       // Call the JavaScript getter with the receiver on the stack.
34       if (map->IsJSGlobalObjectMap()) {
35         // Swap in the global receiver.
36         __ mov(scratch,
37                FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
38         receiver = scratch;
39       }
40       __ push(receiver);
41       __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_GETTER);
42       __ Set(eax, 0);
43       __ Call(masm->isolate()->builtins()->CallFunction(
44                   ConvertReceiverMode::kNotNullOrUndefined),
45               RelocInfo::CODE_TARGET);
46     } else {
47       // If we generate a global code snippet for deoptimization only, remember
48       // the place to continue after deoptimization.
49       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
50     }
51 
52     // Restore context register.
53     __ pop(esi);
54   }
55   __ ret(0);
56 }
57 
58 
PushVectorAndSlot(Register vector,Register slot)59 void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
60                                                 Register slot) {
61   MacroAssembler* masm = this->masm();
62   STATIC_ASSERT(LoadWithVectorDescriptor::kSlot <
63                 LoadWithVectorDescriptor::kVector);
64   STATIC_ASSERT(StoreWithVectorDescriptor::kSlot <
65                 StoreWithVectorDescriptor::kVector);
66   STATIC_ASSERT(StoreTransitionDescriptor::kSlot <
67                 StoreTransitionDescriptor::kVector);
68   __ push(slot);
69   __ push(vector);
70 }
71 
72 
PopVectorAndSlot(Register vector,Register slot)73 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
74   MacroAssembler* masm = this->masm();
75   __ pop(vector);
76   __ pop(slot);
77 }
78 
79 
DiscardVectorAndSlot()80 void PropertyHandlerCompiler::DiscardVectorAndSlot() {
81   MacroAssembler* masm = this->masm();
82   // Remove vector and slot.
83   __ add(esp, Immediate(2 * kPointerSize));
84 }
85 
PushReturnAddress(Register tmp)86 void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
87   MacroAssembler* masm = this->masm();
88   __ push(tmp);
89 }
90 
PopReturnAddress(Register tmp)91 void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
92   MacroAssembler* masm = this->masm();
93   __ pop(tmp);
94 }
95 
GenerateDictionaryNegativeLookup(MacroAssembler * masm,Label * miss_label,Register receiver,Handle<Name> name,Register scratch0,Register scratch1)96 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
97     MacroAssembler* masm, Label* miss_label, Register receiver,
98     Handle<Name> name, Register scratch0, Register scratch1) {
99   DCHECK(name->IsUniqueName());
100   DCHECK(!receiver.is(scratch0));
101   Counters* counters = masm->isolate()->counters();
102   __ IncrementCounter(counters->negative_lookups(), 1);
103   __ IncrementCounter(counters->negative_lookups_miss(), 1);
104 
105   __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
106 
107   const int kInterceptorOrAccessCheckNeededMask =
108       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
109 
110   // Bail out if the receiver has a named interceptor or requires access checks.
111   __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset),
112             Immediate(kInterceptorOrAccessCheckNeededMask));
113   __ j(not_zero, miss_label);
114 
115   // Check that receiver is a JSObject.
116   __ CmpInstanceType(scratch0, FIRST_JS_RECEIVER_TYPE);
117   __ j(below, miss_label);
118 
119   // Load properties array.
120   Register properties = scratch0;
121   __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
122 
123   // Check that the properties array is a dictionary.
124   __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
125          Immediate(masm->isolate()->factory()->hash_table_map()));
126   __ j(not_equal, miss_label);
127 
128   Label done;
129   NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
130                                                    properties, name, scratch1);
131   __ bind(&done);
132   __ DecrementCounter(counters->negative_lookups_miss(), 1);
133 }
134 
135 
GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler * masm,int index,Register result,Label * miss)136 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
137     MacroAssembler* masm, int index, Register result, Label* miss) {
138   __ LoadGlobalFunction(index, result);
139   // Load its initial map. The global functions all have initial maps.
140   __ mov(result,
141          FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
142   // Load the prototype from the initial map.
143   __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
144 }
145 
146 
GenerateLoadFunctionPrototype(MacroAssembler * masm,Register receiver,Register scratch1,Register scratch2,Label * miss_label)147 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
148     MacroAssembler* masm, Register receiver, Register scratch1,
149     Register scratch2, Label* miss_label) {
150   // TODO(mvstanton): This isn't used on ia32. Move all the other
151   // platform implementations into a code stub so this method can be removed.
152   UNREACHABLE();
153 }
154 
155 
156 // Generate call to api function.
157 // This function uses push() to generate smaller, faster code than
158 // the version above. It is an optimization that should will be removed
159 // 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)160 void PropertyHandlerCompiler::GenerateApiAccessorCall(
161     MacroAssembler* masm, const CallOptimization& optimization,
162     Handle<Map> receiver_map, Register receiver, Register scratch,
163     bool is_store, Register store_parameter, Register accessor_holder,
164     int accessor_index) {
165   DCHECK(!accessor_holder.is(scratch));
166   // Copy return value.
167   __ pop(scratch);
168 
169   if (is_store) {
170     // Discard stack arguments.
171     __ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
172                           kPointerSize));
173   }
174   // Write the receiver and arguments to stack frame.
175   __ push(receiver);
176   if (is_store) {
177     DCHECK(!AreAliased(receiver, scratch, store_parameter));
178     __ push(store_parameter);
179   }
180   __ push(scratch);
181   // Stack now matches JSFunction abi.
182   DCHECK(optimization.is_simple_api_call());
183 
184   // Abi for CallApiCallbackStub.
185   Register callee = edi;
186   Register data = ebx;
187   Register holder = ecx;
188   Register api_function_address = edx;
189   scratch = no_reg;
190 
191   // Put callee in place.
192   __ LoadAccessor(callee, accessor_holder, accessor_index,
193                   is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
194 
195   // Put holder in place.
196   CallOptimization::HolderLookup holder_lookup;
197   int holder_depth = 0;
198   optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
199                                           &holder_depth);
200   switch (holder_lookup) {
201     case CallOptimization::kHolderIsReceiver:
202       __ Move(holder, receiver);
203       break;
204     case CallOptimization::kHolderFound:
205       __ mov(holder, FieldOperand(receiver, HeapObject::kMapOffset));
206       __ mov(holder, FieldOperand(holder, Map::kPrototypeOffset));
207       for (int i = 1; i < holder_depth; i++) {
208         __ mov(holder, FieldOperand(holder, HeapObject::kMapOffset));
209         __ mov(holder, FieldOperand(holder, Map::kPrototypeOffset));
210       }
211       break;
212     case CallOptimization::kHolderNotFound:
213       UNREACHABLE();
214       break;
215   }
216 
217   Isolate* isolate = masm->isolate();
218   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
219   bool call_data_undefined = false;
220   // Put call data in place.
221   if (api_call_info->data()->IsUndefined(isolate)) {
222     call_data_undefined = true;
223     __ mov(data, Immediate(isolate->factory()->undefined_value()));
224   } else {
225     if (optimization.is_constant_call()) {
226       __ mov(data, FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
227       __ mov(data, FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
228       __ mov(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
229     } else {
230       __ mov(data, FieldOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
231     }
232     __ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
233   }
234 
235   if (api_call_info->fast_handler()->IsCode()) {
236     // Just tail call into the code.
237     __ Jump(handle(Code::cast(api_call_info->fast_handler())),
238             RelocInfo::CODE_TARGET);
239     return;
240   }
241   // Put api_function_address in place.
242   Address function_address = v8::ToCData<Address>(api_call_info->callback());
243   __ mov(api_function_address, Immediate(function_address));
244 
245   // Jump to stub.
246   CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
247                            !optimization.is_constant_call());
248   __ TailCallStub(&stub);
249 }
250 
251 
252 // Generate code to check that a global property cell is empty. Create
253 // the property cell at compilation time if no cell exists for the
254 // property.
GenerateCheckPropertyCell(MacroAssembler * masm,Handle<JSGlobalObject> global,Handle<Name> name,Register scratch,Label * miss)255 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
256     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
257     Register scratch, Label* miss) {
258   Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
259       global, name, PropertyCellType::kInvalidated);
260   Isolate* isolate = masm->isolate();
261   DCHECK(cell->value()->IsTheHole(isolate));
262   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
263   __ LoadWeakValue(scratch, weak_cell, miss);
264   __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
265          Immediate(isolate->factory()->the_hole_value()));
266   __ j(not_equal, miss);
267 }
268 
269 
GenerateStoreViaSetter(MacroAssembler * masm,Handle<Map> map,Register receiver,Register holder,int accessor_index,int expected_arguments,Register scratch)270 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
271     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
272     int accessor_index, int expected_arguments, Register scratch) {
273   // ----------- S t a t e -------------
274   //  -- esp[12] : value
275   //  -- esp[8]  : slot
276   //  -- esp[4]  : vector
277   //  -- esp[0]  : return address
278   // -----------------------------------
279   __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
280 
281   {
282     FrameScope scope(masm, StackFrame::INTERNAL);
283 
284     // Save context register
285     __ push(esi);
286     // Save value register, so we can restore it later.
287     __ push(value());
288 
289     if (accessor_index >= 0) {
290       DCHECK(!holder.is(scratch));
291       DCHECK(!receiver.is(scratch));
292       DCHECK(!value().is(scratch));
293       // Call the JavaScript setter with receiver and value on the stack.
294       if (map->IsJSGlobalObjectMap()) {
295         __ mov(scratch,
296                FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
297         receiver = scratch;
298       }
299       __ push(receiver);
300       __ push(value());
301       __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_SETTER);
302       __ Set(eax, 1);
303       __ Call(masm->isolate()->builtins()->CallFunction(
304                   ConvertReceiverMode::kNotNullOrUndefined),
305               RelocInfo::CODE_TARGET);
306     } else {
307       // If we generate a global code snippet for deoptimization only, remember
308       // the place to continue after deoptimization.
309       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
310     }
311 
312     // We have to return the passed value, not the return value of the setter.
313     __ pop(eax);
314     // Restore context register.
315     __ pop(esi);
316   }
317   if (accessor_index >= 0) {
318     __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
319   } else {
320     // If we generate a global code snippet for deoptimization only, don't try
321     // to drop stack arguments for the StoreIC because they are not a part of
322     // expression stack and deoptimizer does not reconstruct them.
323     __ ret(0);
324   }
325 }
326 
327 
PushInterceptorArguments(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj)328 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
329                                      Register holder, Register name,
330                                      Handle<JSObject> holder_obj) {
331   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
332   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
333   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
334   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
335   __ push(name);
336   __ push(receiver);
337   __ push(holder);
338 }
339 
340 
CompileCallLoadPropertyWithInterceptor(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj,Runtime::FunctionId id)341 static void CompileCallLoadPropertyWithInterceptor(
342     MacroAssembler* masm, Register receiver, Register holder, Register name,
343     Handle<JSObject> holder_obj, Runtime::FunctionId id) {
344   DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
345          Runtime::FunctionForId(id)->nargs);
346   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
347   __ CallRuntime(id);
348 }
349 
350 #undef __
351 #define __ ACCESS_MASM(masm())
352 
353 
GenerateRestoreName(Label * label,Handle<Name> name)354 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
355                                                     Handle<Name> name) {
356   if (!label->is_unused()) {
357     __ bind(label);
358     __ mov(this->name(), Immediate(name));
359   }
360 }
361 
362 
GenerateRestoreName(Handle<Name> name)363 void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
364   __ mov(this->name(), Immediate(name));
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     __ mov(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
377     __ and_(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   __ mov(scratch,
393          FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
394   __ cmp(value_reg, scratch);
395   __ j(not_equal, miss_label);
396 }
397 
GenerateFieldTypeChecks(FieldType * field_type,Register value_reg,Label * miss_label)398 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
399                                                         Register value_reg,
400                                                         Label* miss_label) {
401   Register map_reg = scratch1();
402   Register scratch = scratch2();
403   DCHECK(!value_reg.is(map_reg));
404   DCHECK(!value_reg.is(scratch));
405   __ JumpIfSmi(value_reg, miss_label);
406   if (field_type->IsClass()) {
407     __ mov(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
408     __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
409                     scratch);
410     __ j(not_equal, miss_label);
411   }
412 }
413 
GenerateAccessCheck(Handle<WeakCell> native_context_cell,Register scratch1,Register scratch2,Label * miss,bool compare_native_contexts_only)414 void PropertyHandlerCompiler::GenerateAccessCheck(
415     Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
416     Label* miss, bool compare_native_contexts_only) {
417   Label done;
418   // Load current native context.
419   __ mov(scratch1, NativeContextOperand());
420   // Load expected native context.
421   __ LoadWeakValue(scratch2, native_context_cell, miss);
422   __ cmp(scratch1, scratch2);
423 
424   if (!compare_native_contexts_only) {
425     __ j(equal, &done);
426 
427     // Compare security tokens of current and expected native contexts.
428     __ mov(scratch1, ContextOperand(scratch1, Context::SECURITY_TOKEN_INDEX));
429     __ mov(scratch2, ContextOperand(scratch2, Context::SECURITY_TOKEN_INDEX));
430     __ cmp(scratch1, scratch2);
431   }
432   __ j(not_equal, miss);
433 
434   __ bind(&done);
435 }
436 
CheckPrototypes(Register object_reg,Register holder_reg,Register scratch1,Register scratch2,Handle<Name> name,Label * miss,ReturnHolder return_what)437 Register PropertyHandlerCompiler::CheckPrototypes(
438     Register object_reg, Register holder_reg, Register scratch1,
439     Register scratch2, Handle<Name> name, Label* miss,
440     ReturnHolder return_what) {
441   Handle<Map> receiver_map = map();
442 
443   // Make sure there's no overlap between holder and object registers.
444   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
445   DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
446          !scratch2.is(scratch1));
447 
448   Handle<Cell> validity_cell =
449       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
450   if (!validity_cell.is_null()) {
451     DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
452     // Operand::ForCell(...) points to the cell's payload!
453     __ cmp(Operand::ForCell(validity_cell),
454            Immediate(Smi::FromInt(Map::kPrototypeChainValid)));
455     __ j(not_equal, miss);
456   }
457 
458   // Keep track of the current object in register reg.
459   Register reg = object_reg;
460   int depth = 0;
461 
462   Handle<JSObject> current = Handle<JSObject>::null();
463   if (receiver_map->IsJSGlobalObjectMap()) {
464     current = isolate()->global_object();
465   }
466 
467   Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
468                           isolate());
469   Handle<Map> holder_map(holder()->map());
470   // Traverse the prototype chain and check the maps in the prototype chain for
471   // fast and global objects or do negative lookup for normal objects.
472   while (!current_map.is_identical_to(holder_map)) {
473     ++depth;
474 
475     if (current_map->IsJSGlobalObjectMap()) {
476       GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
477                                 name, scratch2, miss);
478     } else if (current_map->is_dictionary_map()) {
479       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
480       DCHECK(name->IsUniqueName());
481       DCHECK(current.is_null() ||
482              current->property_dictionary()->FindEntry(name) ==
483                  NameDictionary::kNotFound);
484 
485       if (depth > 1) {
486         Handle<WeakCell> weak_cell =
487             Map::GetOrCreatePrototypeWeakCell(current, isolate());
488         __ LoadWeakValue(reg, weak_cell, miss);
489       }
490       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
491                                        scratch2);
492     }
493 
494     reg = holder_reg;  // From now on the object will be in holder_reg.
495     // Go to the next object in the prototype chain.
496     current = handle(JSObject::cast(current_map->prototype()));
497     current_map = handle(current->map());
498   }
499 
500   DCHECK(!current_map->IsJSGlobalProxyMap());
501 
502   // Log the check depth.
503   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
504 
505   bool return_holder = return_what == RETURN_HOLDER;
506   if (return_holder && depth != 0) {
507     Handle<WeakCell> weak_cell =
508         Map::GetOrCreatePrototypeWeakCell(current, isolate());
509     __ LoadWeakValue(reg, weak_cell, miss);
510   }
511 
512   // Return the register containing the holder.
513   return return_holder ? reg : no_reg;
514 }
515 
516 
FrontendFooter(Handle<Name> name,Label * miss)517 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
518   if (!miss->is_unused()) {
519     Label success;
520     __ jmp(&success);
521     __ bind(miss);
522     if (IC::ShouldPushPopSlotAndVector(kind())) {
523       DCHECK(kind() == Code::LOAD_IC);
524       PopVectorAndSlot();
525     }
526     TailCallBuiltin(masm(), MissBuiltin(kind()));
527     __ bind(&success);
528   }
529 }
530 
531 
FrontendFooter(Handle<Name> name,Label * miss)532 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
533   if (!miss->is_unused()) {
534     Label success;
535     __ jmp(&success);
536     GenerateRestoreName(miss, name);
537     DCHECK(!IC::ShouldPushPopSlotAndVector(kind()));
538     TailCallBuiltin(masm(), MissBuiltin(kind()));
539     __ bind(&success);
540   }
541 }
542 
543 
GenerateLoadConstant(Handle<Object> value)544 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
545   // Return the constant value.
546   __ LoadObject(eax, value);
547   __ ret(0);
548 }
549 
550 
GenerateLoadInterceptorWithFollowup(LookupIterator * it,Register holder_reg)551 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
552     LookupIterator* it, Register holder_reg) {
553   DCHECK(holder()->HasNamedInterceptor());
554   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
555 
556   // Compile the interceptor call, followed by inline code to load the
557   // property from further up the prototype chain if the call fails.
558   // Check that the maps haven't changed.
559   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
560 
561   // Preserve the receiver register explicitly whenever it is different from the
562   // holder and it is needed should the interceptor return without any result.
563   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
564   // case might cause a miss during the prototype check.
565   bool must_perform_prototype_check =
566       !holder().is_identical_to(it->GetHolder<JSObject>());
567   bool must_preserve_receiver_reg =
568       !receiver().is(holder_reg) &&
569       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
570 
571   // Save necessary data before invoking an interceptor.
572   // Requires a frame to make GC aware of pushed pointers.
573   {
574     FrameScope frame_scope(masm(), StackFrame::INTERNAL);
575 
576     if (must_preserve_receiver_reg) {
577       __ push(receiver());
578     }
579     __ push(holder_reg);
580     __ push(this->name());
581     InterceptorVectorSlotPush(holder_reg);
582     // Invoke an interceptor.  Note: map checks from receiver to
583     // interceptor's holder has been compiled before (see a caller
584     // of this method.)
585     CompileCallLoadPropertyWithInterceptor(
586         masm(), receiver(), holder_reg, this->name(), holder(),
587         Runtime::kLoadPropertyWithInterceptorOnly);
588 
589     // Check if interceptor provided a value for property.  If it's
590     // the case, return immediately.
591     Label interceptor_failed;
592     __ cmp(eax, factory()->no_interceptor_result_sentinel());
593     __ j(equal, &interceptor_failed);
594     frame_scope.GenerateLeaveFrame();
595     __ ret(0);
596 
597     // Clobber registers when generating debug-code to provoke errors.
598     __ bind(&interceptor_failed);
599     if (FLAG_debug_code) {
600       __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
601       __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
602       __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
603     }
604 
605     InterceptorVectorSlotPop(holder_reg);
606     __ pop(this->name());
607     __ pop(holder_reg);
608     if (must_preserve_receiver_reg) {
609       __ pop(receiver());
610     }
611 
612     // Leave the internal frame.
613   }
614 
615   GenerateLoadPostInterceptor(it, holder_reg);
616 }
617 
618 
GenerateLoadInterceptor(Register holder_reg)619 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
620   DCHECK(holder()->HasNamedInterceptor());
621   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
622   // Call the runtime system to load the interceptor.
623   __ pop(scratch2());  // save old return address
624   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
625                            holder());
626   __ push(scratch2());  // restore old return address
627 
628   __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
629 }
630 
ZapStackArgumentsRegisterAliases()631 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
632   // Zap register aliases of the arguments passed on the stack to ensure they
633   // are properly loaded by the handler (debug-only).
634   STATIC_ASSERT(Descriptor::kPassLastArgsOnStack);
635   STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3);
636   __ mov(Descriptor::ValueRegister(), Immediate(kDebugZapValue));
637   __ mov(Descriptor::SlotRegister(), Immediate(kDebugZapValue));
638   __ mov(Descriptor::VectorRegister(), Immediate(kDebugZapValue));
639 }
640 
CompileStoreCallback(Handle<JSObject> object,Handle<Name> name,Handle<AccessorInfo> callback,LanguageMode language_mode)641 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
642     Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
643     LanguageMode language_mode) {
644   Register holder_reg = Frontend(name);
645   __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
646 
647   __ pop(scratch1());  // remove the return address
648   // Discard stack arguments.
649   __ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
650                         kPointerSize));
651   __ push(receiver());
652   __ push(holder_reg);
653   // If the callback cannot leak, then push the callback directly,
654   // otherwise wrap it in a weak cell.
655   if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
656     __ Push(callback);
657   } else {
658     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
659     __ Push(cell);
660   }
661   __ Push(name);
662   __ push(value());
663   __ push(Immediate(Smi::FromInt(language_mode)));
664   __ push(scratch1());  // restore return address
665 
666   // Do tail-call to the runtime system.
667   __ TailCallRuntime(Runtime::kStoreCallbackProperty);
668 
669   // Return the generated code.
670   return GetCode(kind(), name);
671 }
672 
673 
value()674 Register NamedStoreHandlerCompiler::value() {
675   return StoreDescriptor::ValueRegister();
676 }
677 
678 
CompileLoadGlobal(Handle<PropertyCell> cell,Handle<Name> name,bool is_configurable)679 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
680     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
681   Label miss;
682   if (IC::ShouldPushPopSlotAndVector(kind())) {
683     PushVectorAndSlot();
684   }
685   FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
686   // Get the value from the cell.
687   Register result = StoreDescriptor::ValueRegister();
688   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
689   __ LoadWeakValue(result, weak_cell, &miss);
690   __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
691 
692   // Check for deleted property if property can actually be deleted.
693   if (is_configurable) {
694     __ cmp(result, factory()->the_hole_value());
695     __ j(equal, &miss);
696   } else if (FLAG_debug_code) {
697     __ cmp(result, factory()->the_hole_value());
698     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
699   }
700 
701   Counters* counters = isolate()->counters();
702   __ IncrementCounter(counters->ic_named_load_global_stub(), 1);
703   // The code above already loads the result into the return register.
704   if (IC::ShouldPushPopSlotAndVector(kind())) {
705     DiscardVectorAndSlot();
706   }
707   __ ret(0);
708 
709   FrontendFooter(name, &miss);
710 
711   // Return the generated code.
712   return GetCode(kind(), name);
713 }
714 
715 
716 #undef __
717 }  // namespace internal
718 }  // namespace v8
719 
720 #endif  // V8_TARGET_ARCH_IA32
721