1// Copyright 2015 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_S390
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
20void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
21    MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
22    int accessor_index, int expected_arguments, Register scratch) {
23  // ----------- S t a t e -------------
24  //  -- r2    : receiver
25  //  -- r4    : name
26  //  -- lr    : return address
27  // -----------------------------------
28  {
29    FrameScope scope(masm, StackFrame::INTERNAL);
30
31    // Save context register
32    __ push(cp);
33
34    if (accessor_index >= 0) {
35      DCHECK(!holder.is(scratch));
36      DCHECK(!receiver.is(scratch));
37      // Call the JavaScript getter with the receiver on the stack.
38      if (map->IsJSGlobalObjectMap()) {
39        // Swap in the global receiver.
40        __ LoadP(scratch,
41                 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
42        receiver = scratch;
43      }
44      __ Push(receiver);
45      __ LoadAccessor(r3, holder, accessor_index, ACCESSOR_GETTER);
46      __ LoadImmP(r2, Operand::Zero());
47      __ Call(masm->isolate()->builtins()->CallFunction(
48                  ConvertReceiverMode::kNotNullOrUndefined),
49              RelocInfo::CODE_TARGET);
50    } else {
51      // If we generate a global code snippet for deoptimization only, remember
52      // the place to continue after deoptimization.
53      masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
54    }
55
56    // Restore context register.
57    __ pop(cp);
58  }
59  __ Ret();
60}
61
62void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
63    MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
64    int accessor_index, int expected_arguments, Register scratch) {
65  // ----------- S t a t e -------------
66  //  -- lr    : return address
67  // -----------------------------------
68  {
69    FrameScope scope(masm, StackFrame::INTERNAL);
70
71    // Save context register
72    // Save value register, so we can restore it later.
73    __ Push(cp, value());
74
75    if (accessor_index >= 0) {
76      DCHECK(!holder.is(scratch));
77      DCHECK(!receiver.is(scratch));
78      DCHECK(!value().is(scratch));
79      // Call the JavaScript setter with receiver and value on the stack.
80      if (map->IsJSGlobalObjectMap()) {
81        // Swap in the global receiver.
82        __ LoadP(scratch,
83                 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
84        receiver = scratch;
85      }
86      __ Push(receiver, value());
87      __ LoadAccessor(r3, holder, accessor_index, ACCESSOR_SETTER);
88      __ LoadImmP(r2, Operand(1));
89      __ Call(masm->isolate()->builtins()->CallFunction(
90                  ConvertReceiverMode::kNotNullOrUndefined),
91              RelocInfo::CODE_TARGET);
92    } else {
93      // If we generate a global code snippet for deoptimization only, remember
94      // the place to continue after deoptimization.
95      masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
96    }
97
98    // We have to return the passed value, not the return value of the setter.
99    // Restore context register.
100    __ Pop(cp, r2);
101  }
102  __ Ret();
103}
104
105void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
106                                                Register slot) {
107  MacroAssembler* masm = this->masm();
108  STATIC_ASSERT(LoadWithVectorDescriptor::kSlot <
109                LoadWithVectorDescriptor::kVector);
110  STATIC_ASSERT(StoreWithVectorDescriptor::kSlot <
111                StoreWithVectorDescriptor::kVector);
112  STATIC_ASSERT(StoreTransitionDescriptor::kSlot <
113                StoreTransitionDescriptor::kVector);
114  __ Push(slot, vector);
115}
116
117void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
118  MacroAssembler* masm = this->masm();
119  __ Pop(slot, vector);
120}
121
122void PropertyHandlerCompiler::DiscardVectorAndSlot() {
123  MacroAssembler* masm = this->masm();
124  // Remove vector and slot.
125  __ la(sp, MemOperand(sp, 2 * kPointerSize));
126}
127
128void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
129  // No-op. Return address is in lr register.
130}
131
132void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
133  // No-op. Return address is in lr register.
134}
135
136void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
137    MacroAssembler* masm, Label* miss_label, Register receiver,
138    Handle<Name> name, Register scratch0, Register scratch1) {
139  DCHECK(name->IsUniqueName());
140  DCHECK(!receiver.is(scratch0));
141  Counters* counters = masm->isolate()->counters();
142  __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
143  __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
144
145  Label done;
146
147  const int kInterceptorOrAccessCheckNeededMask =
148      (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
149
150  // Bail out if the receiver has a named interceptor or requires access checks.
151  Register map = scratch1;
152  __ LoadP(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
153  __ LoadlB(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
154  __ AndP(r0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
155  __ bne(miss_label);
156
157  // Check that receiver is a JSObject.
158  // TODO(joransiu): Merge into SI compare
159  __ LoadlB(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
160  __ CmpP(scratch0, Operand(FIRST_JS_RECEIVER_TYPE));
161  __ blt(miss_label);
162
163  // Load properties array.
164  Register properties = scratch0;
165  __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
166  // Check that the properties array is a dictionary.
167  __ LoadP(map, FieldMemOperand(properties, HeapObject::kMapOffset));
168  __ CompareRoot(map, Heap::kHashTableMapRootIndex);
169  __ bne(miss_label);
170
171  // Restore the temporarily used register.
172  __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
173
174  NameDictionaryLookupStub::GenerateNegativeLookup(
175      masm, miss_label, &done, receiver, properties, name, scratch1);
176  __ bind(&done);
177  __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
178}
179
180void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
181    MacroAssembler* masm, int index, Register result, Label* miss) {
182  __ LoadNativeContextSlot(index, result);
183  // Load its initial map. The global functions all have initial maps.
184  __ LoadP(result,
185           FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
186  // Load the prototype from the initial map.
187  __ LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
188}
189
190void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
191    MacroAssembler* masm, Register receiver, Register scratch1,
192    Register scratch2, Label* miss_label) {
193  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
194  __ LoadRR(r2, scratch1);
195  __ Ret();
196}
197
198// Generate code to check that a global property cell is empty. Create
199// the property cell at compilation time if no cell exists for the
200// property.
201void PropertyHandlerCompiler::GenerateCheckPropertyCell(
202    MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
203    Register scratch, Label* miss) {
204  Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
205      global, name, PropertyCellType::kInvalidated);
206  Isolate* isolate = masm->isolate();
207  DCHECK(cell->value()->IsTheHole(isolate));
208  Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
209  __ LoadWeakValue(scratch, weak_cell, miss);
210  __ LoadP(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
211  __ CompareRoot(scratch, Heap::kTheHoleValueRootIndex);
212  __ bne(miss);
213}
214
215static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
216                                     Register holder, Register name,
217                                     Handle<JSObject> holder_obj) {
218  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
219  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
220  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
221  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
222  __ Push(name);
223  __ Push(receiver);
224  __ Push(holder);
225}
226
227static void CompileCallLoadPropertyWithInterceptor(
228    MacroAssembler* masm, Register receiver, Register holder, Register name,
229    Handle<JSObject> holder_obj, Runtime::FunctionId id) {
230  DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
231         Runtime::FunctionForId(id)->nargs);
232  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
233  __ CallRuntime(id);
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 = r2;
255  Register data = r6;
256  Register holder = r4;
257  Register api_function_address = r3;
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#undef __
328#define __ ACCESS_MASM(masm())
329
330void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
331                                                    Handle<Name> name) {
332  if (!label->is_unused()) {
333    __ bind(label);
334    __ mov(this->name(), Operand(name));
335  }
336}
337
338void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
339  __ mov(this->name(), Operand(name));
340}
341
342void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
343                                                   Register map_reg,
344                                                   Register scratch,
345                                                   Label* miss) {
346  Handle<WeakCell> cell = Map::WeakCellForMap(transition);
347  DCHECK(!map_reg.is(scratch));
348  __ LoadWeakValue(map_reg, cell, miss);
349  if (transition->CanBeDeprecated()) {
350    __ LoadlW(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
351    __ DecodeField<Map::Deprecated>(r0, scratch);
352    __ bne(miss);
353  }
354}
355
356void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
357                                                      int descriptor,
358                                                      Register value_reg,
359                                                      Register scratch,
360                                                      Label* miss_label) {
361  DCHECK(!map_reg.is(scratch));
362  DCHECK(!map_reg.is(value_reg));
363  DCHECK(!value_reg.is(scratch));
364  __ LoadInstanceDescriptors(map_reg, scratch);
365  __ CmpP(value_reg, FieldMemOperand(
366                         scratch, DescriptorArray::GetValueOffset(descriptor)));
367  __ bne(miss_label);
368}
369
370void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
371                                                        Register value_reg,
372                                                        Label* miss_label) {
373  Register map_reg = scratch1();
374  Register scratch = scratch2();
375  DCHECK(!value_reg.is(map_reg));
376  DCHECK(!value_reg.is(scratch));
377  __ JumpIfSmi(value_reg, miss_label);
378  if (field_type->IsClass()) {
379    __ LoadP(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
380    __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
381                    scratch);
382    __ bne(miss_label);
383  }
384}
385
386void PropertyHandlerCompiler::GenerateAccessCheck(
387    Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
388    Label* miss, bool compare_native_contexts_only) {
389  Label done;
390  // Load current native context.
391  __ LoadP(scratch1, NativeContextMemOperand());
392  // Load expected native context.
393  __ LoadWeakValue(scratch2, native_context_cell, miss);
394  __ CmpP(scratch1, scratch2);
395
396  if (!compare_native_contexts_only) {
397    __ beq(&done);
398
399    // Compare security tokens of current and expected native contexts.
400    __ LoadP(scratch1,
401             ContextMemOperand(scratch1, Context::SECURITY_TOKEN_INDEX));
402    __ LoadP(scratch2,
403             ContextMemOperand(scratch2, Context::SECURITY_TOKEN_INDEX));
404    __ CmpP(scratch1, scratch2);
405  }
406  __ bne(miss);
407
408  __ bind(&done);
409}
410
411Register PropertyHandlerCompiler::CheckPrototypes(
412    Register object_reg, Register holder_reg, Register scratch1,
413    Register scratch2, Handle<Name> name, Label* miss,
414    ReturnHolder return_what) {
415  Handle<Map> receiver_map = map();
416
417  // Make sure there's no overlap between holder and object registers.
418  DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
419  DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
420         !scratch2.is(scratch1));
421
422  Handle<Cell> validity_cell =
423      Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
424  if (!validity_cell.is_null()) {
425    DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
426    __ mov(scratch1, Operand(validity_cell));
427    __ LoadP(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
428    __ CmpSmiLiteral(scratch1, Smi::FromInt(Map::kPrototypeChainValid), r0);
429    __ bne(miss);
430  }
431
432  // Keep track of the current object in register reg.
433  Register reg = object_reg;
434  int depth = 0;
435
436  Handle<JSObject> current = Handle<JSObject>::null();
437  if (receiver_map->IsJSGlobalObjectMap()) {
438    current = isolate()->global_object();
439  }
440
441  Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
442                          isolate());
443  Handle<Map> holder_map(holder()->map());
444  // Traverse the prototype chain and check the maps in the prototype chain for
445  // fast and global objects or do negative lookup for normal objects.
446  while (!current_map.is_identical_to(holder_map)) {
447    ++depth;
448
449    if (current_map->IsJSGlobalObjectMap()) {
450      GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
451                                name, scratch2, miss);
452    } else if (current_map->is_dictionary_map()) {
453      DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
454      DCHECK(name->IsUniqueName());
455      DCHECK(current.is_null() ||
456             current->property_dictionary()->FindEntry(name) ==
457                 NameDictionary::kNotFound);
458
459      if (depth > 1) {
460        Handle<WeakCell> weak_cell =
461            Map::GetOrCreatePrototypeWeakCell(current, isolate());
462        __ LoadWeakValue(reg, weak_cell, miss);
463      }
464      GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
465                                       scratch2);
466    }
467
468    reg = holder_reg;  // From now on the object will be in holder_reg.
469    // Go to the next object in the prototype chain.
470    current = handle(JSObject::cast(current_map->prototype()));
471    current_map = handle(current->map());
472  }
473
474  DCHECK(!current_map->IsJSGlobalProxyMap());
475
476  // Log the check depth.
477  LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
478
479  bool return_holder = return_what == RETURN_HOLDER;
480  if (return_holder && depth != 0) {
481    Handle<WeakCell> weak_cell =
482        Map::GetOrCreatePrototypeWeakCell(current, isolate());
483    __ LoadWeakValue(reg, weak_cell, miss);
484  }
485
486  // Return the register containing the holder.
487  return return_holder ? reg : no_reg;
488}
489
490void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
491  if (!miss->is_unused()) {
492    Label success;
493    __ b(&success);
494    __ bind(miss);
495    if (IC::ICUseVector(kind())) {
496      DCHECK(kind() == Code::LOAD_IC);
497      PopVectorAndSlot();
498    }
499    TailCallBuiltin(masm(), MissBuiltin(kind()));
500    __ bind(&success);
501  }
502}
503
504void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
505  if (!miss->is_unused()) {
506    Label success;
507    __ b(&success);
508    GenerateRestoreName(miss, name);
509    if (IC::ICUseVector(kind())) PopVectorAndSlot();
510    TailCallBuiltin(masm(), MissBuiltin(kind()));
511    __ bind(&success);
512  }
513}
514
515void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
516  // Return the constant value.
517  __ Move(r2, value);
518  __ Ret();
519}
520
521void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
522    LookupIterator* it, Register holder_reg) {
523  DCHECK(holder()->HasNamedInterceptor());
524  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
525
526  // Compile the interceptor call, followed by inline code to load the
527  // property from further up the prototype chain if the call fails.
528  // Check that the maps haven't changed.
529  DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
530
531  // Preserve the receiver register explicitly whenever it is different from the
532  // holder and it is needed should the interceptor return without any result.
533  // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
534  // case might cause a miss during the prototype check.
535  bool must_perform_prototype_check =
536      !holder().is_identical_to(it->GetHolder<JSObject>());
537  bool must_preserve_receiver_reg =
538      !receiver().is(holder_reg) &&
539      (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
540
541  // Save necessary data before invoking an interceptor.
542  // Requires a frame to make GC aware of pushed pointers.
543  {
544    FrameScope frame_scope(masm(), StackFrame::INTERNAL);
545    if (must_preserve_receiver_reg) {
546      __ Push(receiver(), holder_reg, this->name());
547    } else {
548      __ Push(holder_reg, this->name());
549    }
550    InterceptorVectorSlotPush(holder_reg);
551    // Invoke an interceptor.  Note: map checks from receiver to
552    // interceptor's holder has been compiled before (see a caller
553    // of this method.)
554    CompileCallLoadPropertyWithInterceptor(
555        masm(), receiver(), holder_reg, this->name(), holder(),
556        Runtime::kLoadPropertyWithInterceptorOnly);
557
558    // Check if interceptor provided a value for property.  If it's
559    // the case, return immediately.
560    Label interceptor_failed;
561    __ CompareRoot(r2, Heap::kNoInterceptorResultSentinelRootIndex);
562    __ beq(&interceptor_failed, Label::kNear);
563    frame_scope.GenerateLeaveFrame();
564    __ Ret();
565
566    __ bind(&interceptor_failed);
567    InterceptorVectorSlotPop(holder_reg);
568    __ Pop(this->name());
569    __ Pop(holder_reg);
570    if (must_preserve_receiver_reg) {
571      __ Pop(receiver());
572    }
573    // Leave the internal frame.
574  }
575
576  GenerateLoadPostInterceptor(it, holder_reg);
577}
578
579void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
580  // Call the runtime system to load the interceptor.
581  DCHECK(holder()->HasNamedInterceptor());
582  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
583  PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
584                           holder());
585
586  __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
587}
588
589void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
590  STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
591}
592
593Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
594    Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
595    LanguageMode language_mode) {
596  Register holder_reg = Frontend(name);
597
598  __ Push(receiver(), holder_reg);  // receiver
599
600  // If the callback cannot leak, then push the callback directly,
601  // otherwise wrap it in a weak cell.
602  if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
603    __ mov(ip, Operand(callback));
604  } else {
605    Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
606    __ mov(ip, Operand(cell));
607  }
608  __ Push(ip);
609  __ mov(ip, Operand(name));
610  __ Push(ip, value());
611  __ Push(Smi::FromInt(language_mode));
612
613  // Do tail-call to the runtime system.
614  __ TailCallRuntime(Runtime::kStoreCallbackProperty);
615
616  // Return the generated code.
617  return GetCode(kind(), name);
618}
619
620Register NamedStoreHandlerCompiler::value() {
621  return StoreDescriptor::ValueRegister();
622}
623
624Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
625    Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
626  Label miss;
627  if (IC::ICUseVector(kind())) {
628    PushVectorAndSlot();
629  }
630  FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
631
632  // Get the value from the cell.
633  Register result = StoreDescriptor::ValueRegister();
634  Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
635  __ LoadWeakValue(result, weak_cell, &miss);
636  __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset));
637
638  // Check for deleted property if property can actually be deleted.
639  if (is_configurable) {
640    __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
641    __ beq(&miss);
642  }
643
644  Counters* counters = isolate()->counters();
645  __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r3, r5);
646  if (IC::ICUseVector(kind())) {
647    DiscardVectorAndSlot();
648  }
649  __ Ret();
650
651  FrontendFooter(name, &miss);
652
653  // Return the generated code.
654  return GetCode(kind(), name);
655}
656
657#undef __
658}  // namespace internal
659}  // namespace v8
660
661#endif  // V8_TARGET_ARCH_ARM
662