Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / v8 / src / ic / x87 / handler-compiler-x87.cc
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 #include "src/v8.h"
6
7 #if V8_TARGET_ARCH_X87
8
9 #include "src/ic/call-optimization.h"
10 #include "src/ic/handler-compiler.h"
11 #include "src/ic/ic.h"
12
13 namespace v8 {
14 namespace internal {
15
16 #define __ ACCESS_MASM(masm)
17
18
19 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
20     MacroAssembler* masm, Handle<HeapType> type, Register receiver,
21     Handle<JSFunction> getter) {
22   {
23     FrameScope scope(masm, StackFrame::INTERNAL);
24
25     if (!getter.is_null()) {
26       // Call the JavaScript getter with the receiver on the stack.
27       if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
28         // Swap in the global receiver.
29         __ mov(receiver,
30                FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
31       }
32       __ push(receiver);
33       ParameterCount actual(0);
34       ParameterCount expected(getter);
35       __ InvokeFunction(getter, expected, actual, CALL_FUNCTION,
36                         NullCallWrapper());
37     } else {
38       // If we generate a global code snippet for deoptimization only, remember
39       // the place to continue after deoptimization.
40       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
41     }
42
43     // Restore context register.
44     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
45   }
46   __ ret(0);
47 }
48
49
50 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
51     MacroAssembler* masm, Label* miss_label, Register receiver,
52     Handle<Name> name, Register scratch0, Register scratch1) {
53   DCHECK(name->IsUniqueName());
54   DCHECK(!receiver.is(scratch0));
55   Counters* counters = masm->isolate()->counters();
56   __ IncrementCounter(counters->negative_lookups(), 1);
57   __ IncrementCounter(counters->negative_lookups_miss(), 1);
58
59   __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
60
61   const int kInterceptorOrAccessCheckNeededMask =
62       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
63
64   // Bail out if the receiver has a named interceptor or requires access checks.
65   __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset),
66             kInterceptorOrAccessCheckNeededMask);
67   __ j(not_zero, miss_label);
68
69   // Check that receiver is a JSObject.
70   __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
71   __ j(below, miss_label);
72
73   // Load properties array.
74   Register properties = scratch0;
75   __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
76
77   // Check that the properties array is a dictionary.
78   __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
79          Immediate(masm->isolate()->factory()->hash_table_map()));
80   __ j(not_equal, miss_label);
81
82   Label done;
83   NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
84                                                    properties, name, scratch1);
85   __ bind(&done);
86   __ DecrementCounter(counters->negative_lookups_miss(), 1);
87 }
88
89
90 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
91     MacroAssembler* masm, int index, Register prototype, Label* miss) {
92   // Get the global function with the given index.
93   Handle<JSFunction> function(
94       JSFunction::cast(masm->isolate()->native_context()->get(index)));
95   // Check we're still in the same context.
96   Register scratch = prototype;
97   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
98   __ mov(scratch, Operand(esi, offset));
99   __ mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
100   __ cmp(Operand(scratch, Context::SlotOffset(index)), function);
101   __ j(not_equal, miss);
102
103   // Load its initial map. The global functions all have initial maps.
104   __ Move(prototype, Immediate(Handle<Map>(function->initial_map())));
105   // Load the prototype from the initial map.
106   __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
107 }
108
109
110 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
111     MacroAssembler* masm, Register receiver, Register scratch1,
112     Register scratch2, Label* miss_label) {
113   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
114   __ mov(eax, scratch1);
115   __ ret(0);
116 }
117
118
119 // Generate call to api function.
120 // This function uses push() to generate smaller, faster code than
121 // the version above. It is an optimization that should will be removed
122 // when api call ICs are generated in hydrogen.
123 void PropertyHandlerCompiler::GenerateFastApiCall(
124     MacroAssembler* masm, const CallOptimization& optimization,
125     Handle<Map> receiver_map, Register receiver, Register scratch_in,
126     bool is_store, int argc, Register* values) {
127   // Copy return value.
128   __ pop(scratch_in);
129   // receiver
130   __ push(receiver);
131   // Write the arguments to stack frame.
132   for (int i = 0; i < argc; i++) {
133     Register arg = values[argc - 1 - i];
134     DCHECK(!receiver.is(arg));
135     DCHECK(!scratch_in.is(arg));
136     __ push(arg);
137   }
138   __ push(scratch_in);
139   // Stack now matches JSFunction abi.
140   DCHECK(optimization.is_simple_api_call());
141
142   // Abi for CallApiFunctionStub.
143   Register callee = eax;
144   Register call_data = ebx;
145   Register holder = ecx;
146   Register api_function_address = edx;
147   Register scratch = edi;  // scratch_in is no longer valid.
148
149   // Put holder in place.
150   CallOptimization::HolderLookup holder_lookup;
151   Handle<JSObject> api_holder =
152       optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
153   switch (holder_lookup) {
154     case CallOptimization::kHolderIsReceiver:
155       __ Move(holder, receiver);
156       break;
157     case CallOptimization::kHolderFound:
158       __ LoadHeapObject(holder, api_holder);
159       break;
160     case CallOptimization::kHolderNotFound:
161       UNREACHABLE();
162       break;
163   }
164
165   Isolate* isolate = masm->isolate();
166   Handle<JSFunction> function = optimization.constant_function();
167   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
168   Handle<Object> call_data_obj(api_call_info->data(), isolate);
169
170   // Put callee in place.
171   __ LoadHeapObject(callee, function);
172
173   bool call_data_undefined = false;
174   // Put call_data in place.
175   if (isolate->heap()->InNewSpace(*call_data_obj)) {
176     __ mov(scratch, api_call_info);
177     __ mov(call_data, FieldOperand(scratch, CallHandlerInfo::kDataOffset));
178   } else if (call_data_obj->IsUndefined()) {
179     call_data_undefined = true;
180     __ mov(call_data, Immediate(isolate->factory()->undefined_value()));
181   } else {
182     __ mov(call_data, call_data_obj);
183   }
184
185   // Put api_function_address in place.
186   Address function_address = v8::ToCData<Address>(api_call_info->callback());
187   __ mov(api_function_address, Immediate(function_address));
188
189   // Jump to stub.
190   CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
191   __ TailCallStub(&stub);
192 }
193
194
195 // Generate code to check that a global property cell is empty. Create
196 // the property cell at compilation time if no cell exists for the
197 // property.
198 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
199     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
200     Register scratch, Label* miss) {
201   Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
202   DCHECK(cell->value()->IsTheHole());
203   Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
204   if (masm->serializer_enabled()) {
205     __ mov(scratch, Immediate(cell));
206     __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
207            Immediate(the_hole));
208   } else {
209     __ cmp(Operand::ForCell(cell), Immediate(the_hole));
210   }
211   __ j(not_equal, miss);
212 }
213
214
215 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
216     MacroAssembler* masm, Handle<HeapType> type, Register receiver,
217     Handle<JSFunction> setter) {
218   // ----------- S t a t e -------------
219   //  -- esp[0] : return address
220   // -----------------------------------
221   {
222     FrameScope scope(masm, StackFrame::INTERNAL);
223
224     // Save value register, so we can restore it later.
225     __ push(value());
226
227     if (!setter.is_null()) {
228       // Call the JavaScript setter with receiver and value on the stack.
229       if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
230         // Swap in the global receiver.
231         __ mov(receiver,
232                FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
233       }
234       __ push(receiver);
235       __ push(value());
236       ParameterCount actual(1);
237       ParameterCount expected(setter);
238       __ InvokeFunction(setter, expected, actual, CALL_FUNCTION,
239                         NullCallWrapper());
240     } else {
241       // If we generate a global code snippet for deoptimization only, remember
242       // the place to continue after deoptimization.
243       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
244     }
245
246     // We have to return the passed value, not the return value of the setter.
247     __ pop(eax);
248
249     // Restore context register.
250     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
251   }
252   __ ret(0);
253 }
254
255
256 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
257                                      Register holder, Register name,
258                                      Handle<JSObject> holder_obj) {
259   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
260   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1);
261   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2);
262   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3);
263   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4);
264   __ push(name);
265   Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
266   DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor));
267   Register scratch = name;
268   __ mov(scratch, Immediate(interceptor));
269   __ push(scratch);
270   __ push(receiver);
271   __ push(holder);
272 }
273
274
275 static void CompileCallLoadPropertyWithInterceptor(
276     MacroAssembler* masm, Register receiver, Register holder, Register name,
277     Handle<JSObject> holder_obj, IC::UtilityId id) {
278   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
279   __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()),
280                            NamedLoadHandlerCompiler::kInterceptorArgsLength);
281 }
282
283
284 static void StoreIC_PushArgs(MacroAssembler* masm) {
285   Register receiver = StoreDescriptor::ReceiverRegister();
286   Register name = StoreDescriptor::NameRegister();
287   Register value = StoreDescriptor::ValueRegister();
288
289   DCHECK(!ebx.is(receiver) && !ebx.is(name) && !ebx.is(value));
290
291   __ pop(ebx);
292   __ push(receiver);
293   __ push(name);
294   __ push(value);
295   __ push(ebx);
296 }
297
298
299 void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
300   // Return address is on the stack.
301   StoreIC_PushArgs(masm);
302
303   // Do tail-call to runtime routine.
304   ExternalReference ref(IC_Utility(IC::kStoreIC_Slow), masm->isolate());
305   __ TailCallExternalReference(ref, 3, 1);
306 }
307
308
309 void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
310   // Return address is on the stack.
311   StoreIC_PushArgs(masm);
312
313   // Do tail-call to runtime routine.
314   ExternalReference ref(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate());
315   __ TailCallExternalReference(ref, 3, 1);
316 }
317
318
319 #undef __
320 #define __ ACCESS_MASM(masm())
321
322
323 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
324                                                     Handle<Name> name) {
325   if (!label->is_unused()) {
326     __ bind(label);
327     __ mov(this->name(), Immediate(name));
328   }
329 }
330
331
332 void NamedStoreHandlerCompiler::GenerateRestoreNameAndMap(
333     Handle<Name> name, Handle<Map> transition) {
334   __ mov(this->name(), Immediate(name));
335   __ mov(StoreTransitionDescriptor::MapRegister(), Immediate(transition));
336 }
337
338
339 void NamedStoreHandlerCompiler::GenerateConstantCheck(Object* constant,
340                                                       Register value_reg,
341                                                       Label* miss_label) {
342   __ CmpObject(value_reg, handle(constant, isolate()));
343   __ j(not_equal, miss_label);
344 }
345
346
347 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
348                                                         Register value_reg,
349                                                         Label* miss_label) {
350   __ JumpIfSmi(value_reg, miss_label);
351   HeapType::Iterator<Map> it = field_type->Classes();
352   if (!it.Done()) {
353     Label do_store;
354     while (true) {
355       __ CompareMap(value_reg, it.Current());
356       it.Advance();
357       if (it.Done()) {
358         __ j(not_equal, miss_label);
359         break;
360       }
361       __ j(equal, &do_store, Label::kNear);
362     }
363     __ bind(&do_store);
364   }
365 }
366
367
368 Register PropertyHandlerCompiler::CheckPrototypes(
369     Register object_reg, Register holder_reg, Register scratch1,
370     Register scratch2, Handle<Name> name, Label* miss,
371     PrototypeCheckType check) {
372   Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
373
374   // Make sure there's no overlap between holder and object registers.
375   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
376   DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
377          !scratch2.is(scratch1));
378
379   // Keep track of the current object in register reg.
380   Register reg = object_reg;
381   int depth = 0;
382
383   Handle<JSObject> current = Handle<JSObject>::null();
384   if (type()->IsConstant())
385     current = Handle<JSObject>::cast(type()->AsConstant()->Value());
386   Handle<JSObject> prototype = Handle<JSObject>::null();
387   Handle<Map> current_map = receiver_map;
388   Handle<Map> holder_map(holder()->map());
389   // Traverse the prototype chain and check the maps in the prototype chain for
390   // fast and global objects or do negative lookup for normal objects.
391   while (!current_map.is_identical_to(holder_map)) {
392     ++depth;
393
394     // Only global objects and objects that do not require access
395     // checks are allowed in stubs.
396     DCHECK(current_map->IsJSGlobalProxyMap() ||
397            !current_map->is_access_check_needed());
398
399     prototype = handle(JSObject::cast(current_map->prototype()));
400     if (current_map->is_dictionary_map() &&
401         !current_map->IsJSGlobalObjectMap()) {
402       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
403       if (!name->IsUniqueName()) {
404         DCHECK(name->IsString());
405         name = factory()->InternalizeString(Handle<String>::cast(name));
406       }
407       DCHECK(current.is_null() ||
408              current->property_dictionary()->FindEntry(name) ==
409                  NameDictionary::kNotFound);
410
411       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
412                                        scratch2);
413
414       __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
415       reg = holder_reg;  // From now on the object will be in holder_reg.
416       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
417     } else {
418       bool in_new_space = heap()->InNewSpace(*prototype);
419       // Two possible reasons for loading the prototype from the map:
420       // (1) Can't store references to new space in code.
421       // (2) Handler is shared for all receivers with the same prototype
422       //     map (but not necessarily the same prototype instance).
423       bool load_prototype_from_map = in_new_space || depth == 1;
424       if (depth != 1 || check == CHECK_ALL_MAPS) {
425         __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
426       }
427
428       // Check access rights to the global object.  This has to happen after
429       // the map check so that we know that the object is actually a global
430       // object.
431       // This allows us to install generated handlers for accesses to the
432       // global proxy (as opposed to using slow ICs). See corresponding code
433       // in LookupForRead().
434       if (current_map->IsJSGlobalProxyMap()) {
435         __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
436       } else if (current_map->IsJSGlobalObjectMap()) {
437         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
438                                   name, scratch2, miss);
439       }
440
441       if (load_prototype_from_map) {
442         // Save the map in scratch1 for later.
443         __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
444       }
445
446       reg = holder_reg;  // From now on the object will be in holder_reg.
447
448       if (load_prototype_from_map) {
449         __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
450       } else {
451         __ mov(reg, prototype);
452       }
453     }
454
455     // Go to the next object in the prototype chain.
456     current = prototype;
457     current_map = handle(current->map());
458   }
459
460   // Log the check depth.
461   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
462
463   if (depth != 0 || check == CHECK_ALL_MAPS) {
464     // Check the holder map.
465     __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
466   }
467
468   // Perform security check for access to the global object.
469   DCHECK(current_map->IsJSGlobalProxyMap() ||
470          !current_map->is_access_check_needed());
471   if (current_map->IsJSGlobalProxyMap()) {
472     __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
473   }
474
475   // Return the register containing the holder.
476   return reg;
477 }
478
479
480 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
481   if (!miss->is_unused()) {
482     Label success;
483     __ jmp(&success);
484     __ bind(miss);
485     TailCallBuiltin(masm(), MissBuiltin(kind()));
486     __ bind(&success);
487   }
488 }
489
490
491 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
492   if (!miss->is_unused()) {
493     Label success;
494     __ jmp(&success);
495     GenerateRestoreName(miss, name);
496     TailCallBuiltin(masm(), MissBuiltin(kind()));
497     __ bind(&success);
498   }
499 }
500
501
502 void NamedLoadHandlerCompiler::GenerateLoadCallback(
503     Register reg, Handle<ExecutableAccessorInfo> callback) {
504   // Insert additional parameters into the stack frame above return address.
505   DCHECK(!scratch3().is(reg));
506   __ pop(scratch3());  // Get return address to place it below.
507
508   STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
509   STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
510   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
511   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
512   STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
513   STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
514   __ push(receiver());  // receiver
515   // Push data from ExecutableAccessorInfo.
516   if (isolate()->heap()->InNewSpace(callback->data())) {
517     DCHECK(!scratch2().is(reg));
518     __ mov(scratch2(), Immediate(callback));
519     __ push(FieldOperand(scratch2(), ExecutableAccessorInfo::kDataOffset));
520   } else {
521     __ push(Immediate(Handle<Object>(callback->data(), isolate())));
522   }
523   __ push(Immediate(isolate()->factory()->undefined_value()));  // ReturnValue
524   // ReturnValue default value
525   __ push(Immediate(isolate()->factory()->undefined_value()));
526   __ push(Immediate(reinterpret_cast<int>(isolate())));
527   __ push(reg);  // holder
528
529   // Save a pointer to where we pushed the arguments. This will be
530   // passed as the const PropertyAccessorInfo& to the C++ callback.
531   __ push(esp);
532
533   __ push(name());  // name
534
535   __ push(scratch3());  // Restore return address.
536
537   // Abi for CallApiGetter
538   Register getter_address = ApiGetterDescriptor::function_address();
539   Address function_address = v8::ToCData<Address>(callback->getter());
540   __ mov(getter_address, Immediate(function_address));
541
542   CallApiGetterStub stub(isolate());
543   __ TailCallStub(&stub);
544 }
545
546
547 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
548   // Return the constant value.
549   __ LoadObject(eax, value);
550   __ ret(0);
551 }
552
553
554 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
555     LookupIterator* it, Register holder_reg) {
556   DCHECK(holder()->HasNamedInterceptor());
557   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
558
559   // Compile the interceptor call, followed by inline code to load the
560   // property from further up the prototype chain if the call fails.
561   // Check that the maps haven't changed.
562   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
563
564   // Preserve the receiver register explicitly whenever it is different from the
565   // holder and it is needed should the interceptor return without any result.
566   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
567   // case might cause a miss during the prototype check.
568   bool must_perform_prototype_check =
569       !holder().is_identical_to(it->GetHolder<JSObject>());
570   bool must_preserve_receiver_reg =
571       !receiver().is(holder_reg) &&
572       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
573
574   // Save necessary data before invoking an interceptor.
575   // Requires a frame to make GC aware of pushed pointers.
576   {
577     FrameScope frame_scope(masm(), StackFrame::INTERNAL);
578
579     if (must_preserve_receiver_reg) {
580       __ push(receiver());
581     }
582     __ push(holder_reg);
583     __ push(this->name());
584
585     // Invoke an interceptor.  Note: map checks from receiver to
586     // interceptor's holder has been compiled before (see a caller
587     // of this method.)
588     CompileCallLoadPropertyWithInterceptor(
589         masm(), receiver(), holder_reg, this->name(), holder(),
590         IC::kLoadPropertyWithInterceptorOnly);
591
592     // Check if interceptor provided a value for property.  If it's
593     // the case, return immediately.
594     Label interceptor_failed;
595     __ cmp(eax, factory()->no_interceptor_result_sentinel());
596     __ j(equal, &interceptor_failed);
597     frame_scope.GenerateLeaveFrame();
598     __ ret(0);
599
600     // Clobber registers when generating debug-code to provoke errors.
601     __ bind(&interceptor_failed);
602     if (FLAG_debug_code) {
603       __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
604       __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
605       __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
606     }
607
608     __ pop(this->name());
609     __ pop(holder_reg);
610     if (must_preserve_receiver_reg) {
611       __ pop(receiver());
612     }
613
614     // Leave the internal frame.
615   }
616
617   GenerateLoadPostInterceptor(it, holder_reg);
618 }
619
620
621 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
622   DCHECK(holder()->HasNamedInterceptor());
623   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
624   // Call the runtime system to load the interceptor.
625   __ pop(scratch2());  // save old return address
626   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
627                            holder());
628   __ push(scratch2());  // restore old return address
629
630   ExternalReference ref = ExternalReference(
631       IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
632   __ TailCallExternalReference(
633       ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
634 }
635
636
637 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
638     Handle<JSObject> object, Handle<Name> name,
639     Handle<ExecutableAccessorInfo> callback) {
640   Register holder_reg = Frontend(receiver(), name);
641
642   __ pop(scratch1());  // remove the return address
643   __ push(receiver());
644   __ push(holder_reg);
645   __ Push(callback);
646   __ Push(name);
647   __ push(value());
648   __ push(scratch1());  // restore return address
649
650   // Do tail-call to the runtime system.
651   ExternalReference store_callback_property =
652       ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
653   __ TailCallExternalReference(store_callback_property, 5, 1);
654
655   // Return the generated code.
656   return GetCode(kind(), Code::FAST, name);
657 }
658
659
660 Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
661     Handle<Name> name) {
662   __ pop(scratch1());  // remove the return address
663   __ push(receiver());
664   __ push(this->name());
665   __ push(value());
666   __ push(scratch1());  // restore return address
667
668   // Do tail-call to the runtime system.
669   ExternalReference store_ic_property = ExternalReference(
670       IC_Utility(IC::kStorePropertyWithInterceptor), isolate());
671   __ TailCallExternalReference(store_ic_property, 3, 1);
672
673   // Return the generated code.
674   return GetCode(kind(), Code::FAST, name);
675 }
676
677
678 Register NamedStoreHandlerCompiler::value() {
679   return StoreDescriptor::ValueRegister();
680 }
681
682
683 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
684     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
685   Label miss;
686
687   FrontendHeader(receiver(), name, &miss);
688   // Get the value from the cell.
689   Register result = StoreDescriptor::ValueRegister();
690   if (masm()->serializer_enabled()) {
691     __ mov(result, Immediate(cell));
692     __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
693   } else {
694     __ mov(result, Operand::ForCell(cell));
695   }
696
697   // Check for deleted property if property can actually be deleted.
698   if (is_configurable) {
699     __ cmp(result, factory()->the_hole_value());
700     __ j(equal, &miss);
701   } else if (FLAG_debug_code) {
702     __ cmp(result, factory()->the_hole_value());
703     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
704   }
705
706   Counters* counters = isolate()->counters();
707   __ IncrementCounter(counters->named_load_global_stub(), 1);
708   // The code above already loads the result into the return register.
709   __ ret(0);
710
711   FrontendFooter(name, &miss);
712
713   // Return the generated code.
714   return GetCode(kind(), Code::NORMAL, name);
715 }
716
717
718 #undef __
719 }
720 }  // namespace v8::internal
721
722 #endif  // V8_TARGET_ARCH_X87