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