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