handler-compiler-x87.cc revision f2e3994fa5148cc3d9946666f0b0596290192b0e
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
12namespace v8 {
13namespace internal {
14
15#define __ ACCESS_MASM(masm)
16
17
18void 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
53void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
54                                                Register slot) {
55  MacroAssembler* masm = this->masm();
56  __ push(vector);
57  __ push(slot);
58}
59
60
61void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
62  MacroAssembler* masm = this->masm();
63  __ pop(slot);
64  __ pop(vector);
65}
66
67
68void PropertyHandlerCompiler::DiscardVectorAndSlot() {
69  MacroAssembler* masm = this->masm();
70  // Remove vector and slot.
71  __ add(esp, Immediate(2 * kPointerSize));
72}
73
74
75void 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
115void 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
126void 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.
139void 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.
225void 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
239void 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
284static 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
297static 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
307static 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
323void 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
332void 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
345void 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
354void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
355  __ mov(this->name(), Immediate(name));
356}
357
358
359void 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
372void 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
387void 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
403void 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
429Register 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
568void 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
583void 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
595void 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
645void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
646  // Return the constant value.
647  __ LoadObject(eax, value);
648  __ ret(0);
649}
650
651
652void 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
720void 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
733Handle<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
761Handle<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
777Register NamedStoreHandlerCompiler::value() {
778  return StoreDescriptor::ValueRegister();
779}
780
781
782Handle<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