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_PPC
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  // ----------- S t a t e -------------
25  //  -- r3    : receiver
26  //  -- r5    : name
27  //  -- lr    : return address
28  // -----------------------------------
29  {
30    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
31
32    // Save context register
33    __ push(cp);
34
35    if (accessor_index >= 0) {
36      DCHECK(!holder.is(scratch));
37      DCHECK(!receiver.is(scratch));
38      // Call the JavaScript getter with the receiver on the stack.
39      if (map->IsJSGlobalObjectMap()) {
40        // Swap in the global receiver.
41        __ LoadP(scratch,
42                 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
43        receiver = scratch;
44      }
45      __ push(receiver);
46      __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_GETTER);
47      __ li(r3, Operand::Zero());
48      __ Call(masm->isolate()->builtins()->CallFunction(
49                  ConvertReceiverMode::kNotNullOrUndefined),
50              RelocInfo::CODE_TARGET);
51    } else {
52      // If we generate a global code snippet for deoptimization only, remember
53      // the place to continue after deoptimization.
54      masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
55    }
56
57    // Restore context register.
58    __ pop(cp);
59  }
60  __ Ret();
61}
62
63
64void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
65    MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
66    int accessor_index, int expected_arguments, Register scratch) {
67  // ----------- S t a t e -------------
68  //  -- lr    : return address
69  // -----------------------------------
70  {
71    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
72
73    // Save context register
74    // Save value register, so we can restore it later.
75    __ Push(cp, value());
76
77    if (accessor_index >= 0) {
78      DCHECK(!holder.is(scratch));
79      DCHECK(!receiver.is(scratch));
80      DCHECK(!value().is(scratch));
81      // Call the JavaScript setter with receiver and value on the stack.
82      if (map->IsJSGlobalObjectMap()) {
83        // Swap in the global receiver.
84        __ LoadP(scratch,
85                 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
86        receiver = scratch;
87      }
88      __ Push(receiver, value());
89      __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_SETTER);
90      __ li(r3, Operand(1));
91      __ Call(masm->isolate()->builtins()->CallFunction(
92                  ConvertReceiverMode::kNotNullOrUndefined),
93              RelocInfo::CODE_TARGET);
94    } else {
95      // If we generate a global code snippet for deoptimization only, remember
96      // the place to continue after deoptimization.
97      masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
98    }
99
100    // We have to return the passed value, not the return value of the setter.
101    // Restore context register.
102    __ Pop(cp, r3);
103  }
104  __ Ret();
105}
106
107
108void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
109                                                Register slot) {
110  MacroAssembler* masm = this->masm();
111  __ Push(vector, slot);
112}
113
114
115void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
116  MacroAssembler* masm = this->masm();
117  __ Pop(vector, slot);
118}
119
120
121void PropertyHandlerCompiler::DiscardVectorAndSlot() {
122  MacroAssembler* masm = this->masm();
123  // Remove vector and slot.
124  __ addi(sp, sp, Operand(2 * kPointerSize));
125}
126
127
128void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
129    MacroAssembler* masm, Label* miss_label, Register receiver,
130    Handle<Name> name, Register scratch0, Register scratch1) {
131  DCHECK(name->IsUniqueName());
132  DCHECK(!receiver.is(scratch0));
133  Counters* counters = masm->isolate()->counters();
134  __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
135  __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
136
137  Label done;
138
139  const int kInterceptorOrAccessCheckNeededMask =
140      (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
141
142  // Bail out if the receiver has a named interceptor or requires access checks.
143  Register map = scratch1;
144  __ LoadP(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
145  __ lbz(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
146  __ andi(r0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
147  __ bne(miss_label, cr0);
148
149  // Check that receiver is a JSObject.
150  __ lbz(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
151  __ cmpi(scratch0, Operand(FIRST_JS_RECEIVER_TYPE));
152  __ blt(miss_label);
153
154  // Load properties array.
155  Register properties = scratch0;
156  __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
157  // Check that the properties array is a dictionary.
158  __ LoadP(map, FieldMemOperand(properties, HeapObject::kMapOffset));
159  Register tmp = properties;
160  __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
161  __ cmp(map, tmp);
162  __ bne(miss_label);
163
164  // Restore the temporarily used register.
165  __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
166
167
168  NameDictionaryLookupStub::GenerateNegativeLookup(
169      masm, miss_label, &done, receiver, properties, name, scratch1);
170  __ bind(&done);
171  __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
172}
173
174
175void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
176    MacroAssembler* masm, int index, Register result, Label* miss) {
177  __ LoadNativeContextSlot(index, result);
178  // Load its initial map. The global functions all have initial maps.
179  __ LoadP(result,
180           FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
181  // Load the prototype from the initial map.
182  __ LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
183}
184
185
186void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
187    MacroAssembler* masm, Register receiver, Register scratch1,
188    Register scratch2, Label* miss_label) {
189  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
190  __ mr(r3, scratch1);
191  __ Ret();
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.
198void 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  Isolate* isolate = masm->isolate();
203  DCHECK(cell->value()->IsTheHole(isolate));
204  Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
205  __ LoadWeakValue(scratch, weak_cell, miss);
206  __ LoadP(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
207  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
208  __ cmp(scratch, ip);
209  __ bne(miss);
210}
211
212
213static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
214                                     Register holder, Register name,
215                                     Handle<JSObject> holder_obj) {
216  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
217  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
218  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
219  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
220  __ push(name);
221  __ push(receiver);
222  __ push(holder);
223}
224
225
226static void CompileCallLoadPropertyWithInterceptor(
227    MacroAssembler* masm, Register receiver, Register holder, Register name,
228    Handle<JSObject> holder_obj, Runtime::FunctionId id) {
229  DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
230         Runtime::FunctionForId(id)->nargs);
231  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
232  __ CallRuntime(id);
233}
234
235
236// Generate call to api function.
237void PropertyHandlerCompiler::GenerateApiAccessorCall(
238    MacroAssembler* masm, const CallOptimization& optimization,
239    Handle<Map> receiver_map, Register receiver, Register scratch_in,
240    bool is_store, Register store_parameter, Register accessor_holder,
241    int accessor_index) {
242  DCHECK(!accessor_holder.is(scratch_in));
243  DCHECK(!receiver.is(scratch_in));
244  __ push(receiver);
245  // Write the arguments to stack frame.
246  if (is_store) {
247    DCHECK(!receiver.is(store_parameter));
248    DCHECK(!scratch_in.is(store_parameter));
249    __ push(store_parameter);
250  }
251  DCHECK(optimization.is_simple_api_call());
252
253  // Abi for CallApiCallbackStub.
254  Register callee = r3;
255  Register data = r7;
256  Register holder = r5;
257  Register api_function_address = r4;
258
259  // Put callee in place.
260  __ LoadAccessor(callee, accessor_holder, accessor_index,
261                  is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
262
263  // Put holder in place.
264  CallOptimization::HolderLookup holder_lookup;
265  int holder_depth = 0;
266  optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
267                                          &holder_depth);
268  switch (holder_lookup) {
269    case CallOptimization::kHolderIsReceiver:
270      __ Move(holder, receiver);
271      break;
272    case CallOptimization::kHolderFound:
273      __ LoadP(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
274      __ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
275      for (int i = 1; i < holder_depth; i++) {
276        __ LoadP(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
277        __ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
278      }
279      break;
280    case CallOptimization::kHolderNotFound:
281      UNREACHABLE();
282      break;
283  }
284
285  Isolate* isolate = masm->isolate();
286  Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
287  bool call_data_undefined = false;
288  // Put call data in place.
289  if (api_call_info->data()->IsUndefined(isolate)) {
290    call_data_undefined = true;
291    __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
292  } else {
293    if (optimization.is_constant_call()) {
294      __ LoadP(data,
295               FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
296      __ LoadP(data,
297               FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
298      __ LoadP(data,
299               FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
300    } else {
301      __ LoadP(data,
302               FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
303    }
304    __ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
305  }
306
307  if (api_call_info->fast_handler()->IsCode()) {
308    // Just tail call into the fast handler if present.
309    __ Jump(handle(Code::cast(api_call_info->fast_handler())),
310            RelocInfo::CODE_TARGET);
311    return;
312  }
313
314  // Put api_function_address in place.
315  Address function_address = v8::ToCData<Address>(api_call_info->callback());
316  ApiFunction fun(function_address);
317  ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
318  ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
319  __ mov(api_function_address, Operand(ref));
320
321  // Jump to stub.
322  CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
323                           !optimization.is_constant_call());
324  __ TailCallStub(&stub);
325}
326
327
328static void StoreIC_PushArgs(MacroAssembler* masm) {
329  __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
330          StoreDescriptor::ValueRegister(),
331          VectorStoreICDescriptor::SlotRegister(),
332          VectorStoreICDescriptor::VectorRegister());
333}
334
335
336void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
337  StoreIC_PushArgs(masm);
338
339  // The slow case calls into the runtime to complete the store without causing
340  // an IC miss that would otherwise cause a transition to the generic stub.
341  __ TailCallRuntime(Runtime::kStoreIC_Slow);
342}
343
344
345void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
346  StoreIC_PushArgs(masm);
347
348  // The slow case calls into the runtime to complete the store without causing
349  // an IC miss that would otherwise cause a transition to the generic stub.
350  __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
351}
352
353
354#undef __
355#define __ ACCESS_MASM(masm())
356
357
358void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
359                                                    Handle<Name> name) {
360  if (!label->is_unused()) {
361    __ bind(label);
362    __ mov(this->name(), Operand(name));
363  }
364}
365
366
367void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
368  __ mov(this->name(), Operand(name));
369}
370
371
372void NamedStoreHandlerCompiler::RearrangeVectorAndSlot(
373    Register current_map, Register destination_map) {
374  DCHECK(false);  // Not implemented.
375}
376
377
378void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
379                                                   Register map_reg,
380                                                   Register scratch,
381                                                   Label* miss) {
382  Handle<WeakCell> cell = Map::WeakCellForMap(transition);
383  DCHECK(!map_reg.is(scratch));
384  __ LoadWeakValue(map_reg, cell, miss);
385  if (transition->CanBeDeprecated()) {
386    __ lwz(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
387    __ DecodeField<Map::Deprecated>(r0, scratch, SetRC);
388    __ bne(miss, cr0);
389  }
390}
391
392
393void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
394                                                      int descriptor,
395                                                      Register value_reg,
396                                                      Register scratch,
397                                                      Label* miss_label) {
398  DCHECK(!map_reg.is(scratch));
399  DCHECK(!map_reg.is(value_reg));
400  DCHECK(!value_reg.is(scratch));
401  __ LoadInstanceDescriptors(map_reg, scratch);
402  __ LoadP(scratch, FieldMemOperand(
403                        scratch, DescriptorArray::GetValueOffset(descriptor)));
404  __ cmp(value_reg, scratch);
405  __ bne(miss_label);
406}
407
408void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
409                                                        Register value_reg,
410                                                        Label* miss_label) {
411  Register map_reg = scratch1();
412  Register scratch = scratch2();
413  DCHECK(!value_reg.is(map_reg));
414  DCHECK(!value_reg.is(scratch));
415  __ JumpIfSmi(value_reg, miss_label);
416  if (field_type->IsClass()) {
417    __ LoadP(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
418    __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
419                    scratch);
420    __ bne(miss_label);
421  }
422}
423
424
425Register PropertyHandlerCompiler::CheckPrototypes(
426    Register object_reg, Register holder_reg, Register scratch1,
427    Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check,
428    ReturnHolder return_what) {
429  Handle<Map> receiver_map = map();
430
431  // Make sure there's no overlap between holder and object registers.
432  DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
433  DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
434         !scratch2.is(scratch1));
435
436  Handle<Cell> validity_cell =
437      Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
438  if (!validity_cell.is_null()) {
439    DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
440    __ mov(scratch1, Operand(validity_cell));
441    __ LoadP(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
442    __ CmpSmiLiteral(scratch1, Smi::FromInt(Map::kPrototypeChainValid), r0);
443    __ bne(miss);
444  }
445
446  // The prototype chain of primitives (and their JSValue wrappers) depends
447  // on the native context, which can't be guarded by validity cells.
448  // |object_reg| holds the native context specific prototype in this case;
449  // we need to check its map.
450  if (check == CHECK_ALL_MAPS) {
451    __ LoadP(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset));
452    Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
453    __ CmpWeakValue(scratch1, cell, scratch2);
454    __ b(ne, miss);
455  }
456
457  // Keep track of the current object in register reg.
458  Register reg = object_reg;
459  int depth = 0;
460
461  Handle<JSObject> current = Handle<JSObject>::null();
462  if (receiver_map->IsJSGlobalObjectMap()) {
463    current = isolate()->global_object();
464  }
465  // Check access rights to the global object.  This has to happen after
466  // the map check so that we know that the object is actually a global
467  // object.
468  // This allows us to install generated handlers for accesses to the
469  // global proxy (as opposed to using slow ICs). See corresponding code
470  // in LookupForRead().
471  if (receiver_map->IsJSGlobalProxyMap()) {
472    __ CheckAccessGlobalProxy(reg, scratch2, miss);
473  }
474
475  Handle<JSObject> prototype = Handle<JSObject>::null();
476  Handle<Map> current_map = receiver_map;
477  Handle<Map> holder_map(holder()->map());
478  // Traverse the prototype chain and check the maps in the prototype chain for
479  // fast and global objects or do negative lookup for normal objects.
480  while (!current_map.is_identical_to(holder_map)) {
481    ++depth;
482
483    // Only global objects and objects that do not require access
484    // checks are allowed in stubs.
485    DCHECK(current_map->IsJSGlobalProxyMap() ||
486           !current_map->is_access_check_needed());
487
488    prototype = handle(JSObject::cast(current_map->prototype()));
489    if (current_map->IsJSGlobalObjectMap()) {
490      GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
491                                name, scratch2, miss);
492    } else if (current_map->is_dictionary_map()) {
493      DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
494      if (!name->IsUniqueName()) {
495        DCHECK(name->IsString());
496        name = factory()->InternalizeString(Handle<String>::cast(name));
497      }
498      DCHECK(current.is_null() ||
499             current->property_dictionary()->FindEntry(name) ==
500                 NameDictionary::kNotFound);
501
502      if (depth > 1) {
503        // TODO(jkummerow): Cache and re-use weak cell.
504        __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
505      }
506      GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
507                                       scratch2);
508    }
509
510    reg = holder_reg;  // From now on the object will be in holder_reg.
511    // Go to the next object in the prototype chain.
512    current = prototype;
513    current_map = handle(current->map());
514  }
515
516  DCHECK(!current_map->IsJSGlobalProxyMap());
517
518  // Log the check depth.
519  LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
520
521  bool return_holder = return_what == RETURN_HOLDER;
522  if (return_holder && depth != 0) {
523    __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
524  }
525
526  // Return the register containing the holder.
527  return return_holder ? reg : no_reg;
528}
529
530
531void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
532  if (!miss->is_unused()) {
533    Label success;
534    __ b(&success);
535    __ bind(miss);
536    if (IC::ICUseVector(kind())) {
537      DCHECK(kind() == Code::LOAD_IC);
538      PopVectorAndSlot();
539    }
540    TailCallBuiltin(masm(), MissBuiltin(kind()));
541    __ bind(&success);
542  }
543}
544
545
546void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
547  if (!miss->is_unused()) {
548    Label success;
549    __ b(&success);
550    GenerateRestoreName(miss, name);
551    if (IC::ICUseVector(kind())) PopVectorAndSlot();
552    TailCallBuiltin(masm(), MissBuiltin(kind()));
553    __ bind(&success);
554  }
555}
556
557
558void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
559  // Return the constant value.
560  __ Move(r3, value);
561  __ Ret();
562}
563
564
565void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
566    LookupIterator* it, Register holder_reg) {
567  DCHECK(holder()->HasNamedInterceptor());
568  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
569
570  // Compile the interceptor call, followed by inline code to load the
571  // property from further up the prototype chain if the call fails.
572  // Check that the maps haven't changed.
573  DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
574
575  // Preserve the receiver register explicitly whenever it is different from the
576  // holder and it is needed should the interceptor return without any result.
577  // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
578  // case might cause a miss during the prototype check.
579  bool must_perform_prototype_check =
580      !holder().is_identical_to(it->GetHolder<JSObject>());
581  bool must_preserve_receiver_reg =
582      !receiver().is(holder_reg) &&
583      (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
584
585  // Save necessary data before invoking an interceptor.
586  // Requires a frame to make GC aware of pushed pointers.
587  {
588    FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
589    if (must_preserve_receiver_reg) {
590      __ Push(receiver(), holder_reg, this->name());
591    } else {
592      __ Push(holder_reg, this->name());
593    }
594    InterceptorVectorSlotPush(holder_reg);
595    // Invoke an interceptor.  Note: map checks from receiver to
596    // interceptor's holder has been compiled before (see a caller
597    // of this method.)
598    CompileCallLoadPropertyWithInterceptor(
599        masm(), receiver(), holder_reg, this->name(), holder(),
600        Runtime::kLoadPropertyWithInterceptorOnly);
601
602    // Check if interceptor provided a value for property.  If it's
603    // the case, return immediately.
604    Label interceptor_failed;
605    __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
606    __ cmp(r3, scratch1());
607    __ beq(&interceptor_failed);
608    frame_scope.GenerateLeaveFrame();
609    __ Ret();
610
611    __ bind(&interceptor_failed);
612    InterceptorVectorSlotPop(holder_reg);
613    __ pop(this->name());
614    __ pop(holder_reg);
615    if (must_preserve_receiver_reg) {
616      __ pop(receiver());
617    }
618    // Leave the internal frame.
619  }
620
621  GenerateLoadPostInterceptor(it, holder_reg);
622}
623
624
625void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
626  // Call the runtime system to load the interceptor.
627  DCHECK(holder()->HasNamedInterceptor());
628  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
629  PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
630                           holder());
631
632  __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
633}
634
635
636Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
637    Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
638    LanguageMode language_mode) {
639  Register holder_reg = Frontend(name);
640
641  __ Push(receiver(), holder_reg);  // receiver
642
643  // If the callback cannot leak, then push the callback directly,
644  // otherwise wrap it in a weak cell.
645  if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
646    __ mov(ip, Operand(callback));
647  } else {
648    Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
649    __ mov(ip, Operand(cell));
650  }
651  __ push(ip);
652  __ mov(ip, Operand(name));
653  __ Push(ip, value());
654  __ Push(Smi::FromInt(language_mode));
655
656  // Do tail-call to the runtime system.
657  __ TailCallRuntime(Runtime::kStoreCallbackProperty);
658
659  // Return the generated code.
660  return GetCode(kind(), name);
661}
662
663
664Register NamedStoreHandlerCompiler::value() {
665  return StoreDescriptor::ValueRegister();
666}
667
668
669Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
670    Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
671  Label miss;
672  if (IC::ICUseVector(kind())) {
673    PushVectorAndSlot();
674  }
675  FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
676
677  // Get the value from the cell.
678  Register result = StoreDescriptor::ValueRegister();
679  Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
680  __ LoadWeakValue(result, weak_cell, &miss);
681  __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset));
682
683  // Check for deleted property if property can actually be deleted.
684  if (is_configurable) {
685    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
686    __ cmp(result, ip);
687    __ beq(&miss);
688  }
689
690  Counters* counters = isolate()->counters();
691  __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r4, r6);
692  if (IC::ICUseVector(kind())) {
693    DiscardVectorAndSlot();
694  }
695  __ Ret();
696
697  FrontendFooter(name, &miss);
698
699  // Return the generated code.
700  return GetCode(kind(), name);
701}
702
703
704#undef __
705}  // namespace internal
706}  // namespace v8
707
708#endif  // V8_TARGET_ARCH_ARM
709