| OLD | NEW | 
 | (Empty) | 
|     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_ARM |  | 
|     8  |  | 
|     9 #include "src/codegen.h" |  | 
|    10 #include "src/ic-inl.h" |  | 
|    11 #include "src/stub-cache.h" |  | 
|    12  |  | 
|    13 namespace v8 { |  | 
|    14 namespace internal { |  | 
|    15  |  | 
|    16 #define __ ACCESS_MASM(masm) |  | 
|    17  |  | 
|    18  |  | 
|    19 static void ProbeTable(Isolate* isolate, |  | 
|    20                        MacroAssembler* masm, |  | 
|    21                        Code::Flags flags, |  | 
|    22                        StubCache::Table table, |  | 
|    23                        Register receiver, |  | 
|    24                        Register name, |  | 
|    25                        // Number of the cache entry, not scaled. |  | 
|    26                        Register offset, |  | 
|    27                        Register scratch, |  | 
|    28                        Register scratch2, |  | 
|    29                        Register offset_scratch) { |  | 
|    30   ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); |  | 
|    31   ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); |  | 
|    32   ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); |  | 
|    33  |  | 
|    34   uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address()); |  | 
|    35   uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address()); |  | 
|    36   uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address()); |  | 
|    37  |  | 
|    38   // Check the relative positions of the address fields. |  | 
|    39   DCHECK(value_off_addr > key_off_addr); |  | 
|    40   DCHECK((value_off_addr - key_off_addr) % 4 == 0); |  | 
|    41   DCHECK((value_off_addr - key_off_addr) < (256 * 4)); |  | 
|    42   DCHECK(map_off_addr > key_off_addr); |  | 
|    43   DCHECK((map_off_addr - key_off_addr) % 4 == 0); |  | 
|    44   DCHECK((map_off_addr - key_off_addr) < (256 * 4)); |  | 
|    45  |  | 
|    46   Label miss; |  | 
|    47   Register base_addr = scratch; |  | 
|    48   scratch = no_reg; |  | 
|    49  |  | 
|    50   // Multiply by 3 because there are 3 fields per entry (name, code, map). |  | 
|    51   __ add(offset_scratch, offset, Operand(offset, LSL, 1)); |  | 
|    52  |  | 
|    53   // Calculate the base address of the entry. |  | 
|    54   __ mov(base_addr, Operand(key_offset)); |  | 
|    55   __ add(base_addr, base_addr, Operand(offset_scratch, LSL, kPointerSizeLog2)); |  | 
|    56  |  | 
|    57   // Check that the key in the entry matches the name. |  | 
|    58   __ ldr(ip, MemOperand(base_addr, 0)); |  | 
|    59   __ cmp(name, ip); |  | 
|    60   __ b(ne, &miss); |  | 
|    61  |  | 
|    62   // Check the map matches. |  | 
|    63   __ ldr(ip, MemOperand(base_addr, map_off_addr - key_off_addr)); |  | 
|    64   __ ldr(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset)); |  | 
|    65   __ cmp(ip, scratch2); |  | 
|    66   __ b(ne, &miss); |  | 
|    67  |  | 
|    68   // Get the code entry from the cache. |  | 
|    69   Register code = scratch2; |  | 
|    70   scratch2 = no_reg; |  | 
|    71   __ ldr(code, MemOperand(base_addr, value_off_addr - key_off_addr)); |  | 
|    72  |  | 
|    73   // Check that the flags match what we're looking for. |  | 
|    74   Register flags_reg = base_addr; |  | 
|    75   base_addr = no_reg; |  | 
|    76   __ ldr(flags_reg, FieldMemOperand(code, Code::kFlagsOffset)); |  | 
|    77   // It's a nice optimization if this constant is encodable in the bic insn. |  | 
|    78  |  | 
|    79   uint32_t mask = Code::kFlagsNotUsedInLookup; |  | 
|    80   DCHECK(__ ImmediateFitsAddrMode1Instruction(mask)); |  | 
|    81   __ bic(flags_reg, flags_reg, Operand(mask)); |  | 
|    82   __ cmp(flags_reg, Operand(flags)); |  | 
|    83   __ b(ne, &miss); |  | 
|    84  |  | 
|    85 #ifdef DEBUG |  | 
|    86     if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { |  | 
|    87       __ jmp(&miss); |  | 
|    88     } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { |  | 
|    89       __ jmp(&miss); |  | 
|    90     } |  | 
|    91 #endif |  | 
|    92  |  | 
|    93   // Jump to the first instruction in the code stub. |  | 
|    94   __ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag)); |  | 
|    95  |  | 
|    96   // Miss: fall through. |  | 
|    97   __ bind(&miss); |  | 
|    98 } |  | 
|    99  |  | 
|   100  |  | 
|   101 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( |  | 
|   102     MacroAssembler* masm, Label* miss_label, Register receiver, |  | 
|   103     Handle<Name> name, Register scratch0, Register scratch1) { |  | 
|   104   DCHECK(name->IsUniqueName()); |  | 
|   105   DCHECK(!receiver.is(scratch0)); |  | 
|   106   Counters* counters = masm->isolate()->counters(); |  | 
|   107   __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); |  | 
|   108   __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); |  | 
|   109  |  | 
|   110   Label done; |  | 
|   111  |  | 
|   112   const int kInterceptorOrAccessCheckNeededMask = |  | 
|   113       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |  | 
|   114  |  | 
|   115   // Bail out if the receiver has a named interceptor or requires access checks. |  | 
|   116   Register map = scratch1; |  | 
|   117   __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); |  | 
|   118   __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); |  | 
|   119   __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask)); |  | 
|   120   __ b(ne, miss_label); |  | 
|   121  |  | 
|   122   // Check that receiver is a JSObject. |  | 
|   123   __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); |  | 
|   124   __ cmp(scratch0, Operand(FIRST_SPEC_OBJECT_TYPE)); |  | 
|   125   __ b(lt, miss_label); |  | 
|   126  |  | 
|   127   // Load properties array. |  | 
|   128   Register properties = scratch0; |  | 
|   129   __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |  | 
|   130   // Check that the properties array is a dictionary. |  | 
|   131   __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); |  | 
|   132   Register tmp = properties; |  | 
|   133   __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); |  | 
|   134   __ cmp(map, tmp); |  | 
|   135   __ b(ne, miss_label); |  | 
|   136  |  | 
|   137   // Restore the temporarily used register. |  | 
|   138   __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |  | 
|   139  |  | 
|   140  |  | 
|   141   NameDictionaryLookupStub::GenerateNegativeLookup(masm, |  | 
|   142                                                    miss_label, |  | 
|   143                                                    &done, |  | 
|   144                                                    receiver, |  | 
|   145                                                    properties, |  | 
|   146                                                    name, |  | 
|   147                                                    scratch1); |  | 
|   148   __ bind(&done); |  | 
|   149   __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); |  | 
|   150 } |  | 
|   151  |  | 
|   152  |  | 
|   153 void StubCache::GenerateProbe(MacroAssembler* masm, |  | 
|   154                               Code::Flags flags, |  | 
|   155                               Register receiver, |  | 
|   156                               Register name, |  | 
|   157                               Register scratch, |  | 
|   158                               Register extra, |  | 
|   159                               Register extra2, |  | 
|   160                               Register extra3) { |  | 
|   161   Isolate* isolate = masm->isolate(); |  | 
|   162   Label miss; |  | 
|   163  |  | 
|   164   // Make sure that code is valid. The multiplying code relies on the |  | 
|   165   // entry size being 12. |  | 
|   166   DCHECK(sizeof(Entry) == 12); |  | 
|   167  |  | 
|   168   // Make sure the flags does not name a specific type. |  | 
|   169   DCHECK(Code::ExtractTypeFromFlags(flags) == 0); |  | 
|   170  |  | 
|   171   // Make sure that there are no register conflicts. |  | 
|   172   DCHECK(!scratch.is(receiver)); |  | 
|   173   DCHECK(!scratch.is(name)); |  | 
|   174   DCHECK(!extra.is(receiver)); |  | 
|   175   DCHECK(!extra.is(name)); |  | 
|   176   DCHECK(!extra.is(scratch)); |  | 
|   177   DCHECK(!extra2.is(receiver)); |  | 
|   178   DCHECK(!extra2.is(name)); |  | 
|   179   DCHECK(!extra2.is(scratch)); |  | 
|   180   DCHECK(!extra2.is(extra)); |  | 
|   181  |  | 
|   182   // Check scratch, extra and extra2 registers are valid. |  | 
|   183   DCHECK(!scratch.is(no_reg)); |  | 
|   184   DCHECK(!extra.is(no_reg)); |  | 
|   185   DCHECK(!extra2.is(no_reg)); |  | 
|   186   DCHECK(!extra3.is(no_reg)); |  | 
|   187  |  | 
|   188   Counters* counters = masm->isolate()->counters(); |  | 
|   189   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, |  | 
|   190                       extra2, extra3); |  | 
|   191  |  | 
|   192   // Check that the receiver isn't a smi. |  | 
|   193   __ JumpIfSmi(receiver, &miss); |  | 
|   194  |  | 
|   195   // Get the map of the receiver and compute the hash. |  | 
|   196   __ ldr(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); |  | 
|   197   __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset)); |  | 
|   198   __ add(scratch, scratch, Operand(ip)); |  | 
|   199   uint32_t mask = kPrimaryTableSize - 1; |  | 
|   200   // We shift out the last two bits because they are not part of the hash and |  | 
|   201   // they are always 01 for maps. |  | 
|   202   __ mov(scratch, Operand(scratch, LSR, kCacheIndexShift)); |  | 
|   203   // Mask down the eor argument to the minimum to keep the immediate |  | 
|   204   // ARM-encodable. |  | 
|   205   __ eor(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask)); |  | 
|   206   // Prefer and_ to ubfx here because ubfx takes 2 cycles. |  | 
|   207   __ and_(scratch, scratch, Operand(mask)); |  | 
|   208  |  | 
|   209   // Probe the primary table. |  | 
|   210   ProbeTable(isolate, |  | 
|   211              masm, |  | 
|   212              flags, |  | 
|   213              kPrimary, |  | 
|   214              receiver, |  | 
|   215              name, |  | 
|   216              scratch, |  | 
|   217              extra, |  | 
|   218              extra2, |  | 
|   219              extra3); |  | 
|   220  |  | 
|   221   // Primary miss: Compute hash for secondary probe. |  | 
|   222   __ sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift)); |  | 
|   223   uint32_t mask2 = kSecondaryTableSize - 1; |  | 
|   224   __ add(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2)); |  | 
|   225   __ and_(scratch, scratch, Operand(mask2)); |  | 
|   226  |  | 
|   227   // Probe the secondary table. |  | 
|   228   ProbeTable(isolate, |  | 
|   229              masm, |  | 
|   230              flags, |  | 
|   231              kSecondary, |  | 
|   232              receiver, |  | 
|   233              name, |  | 
|   234              scratch, |  | 
|   235              extra, |  | 
|   236              extra2, |  | 
|   237              extra3); |  | 
|   238  |  | 
|   239   // Cache miss: Fall-through and let caller handle the miss by |  | 
|   240   // entering the runtime system. |  | 
|   241   __ bind(&miss); |  | 
|   242   __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, |  | 
|   243                       extra2, extra3); |  | 
|   244 } |  | 
|   245  |  | 
|   246  |  | 
|   247 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( |  | 
|   248     MacroAssembler* masm, int index, Register prototype, Label* miss) { |  | 
|   249   Isolate* isolate = masm->isolate(); |  | 
|   250   // Get the global function with the given index. |  | 
|   251   Handle<JSFunction> function( |  | 
|   252       JSFunction::cast(isolate->native_context()->get(index))); |  | 
|   253  |  | 
|   254   // Check we're still in the same context. |  | 
|   255   Register scratch = prototype; |  | 
|   256   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); |  | 
|   257   __ ldr(scratch, MemOperand(cp, offset)); |  | 
|   258   __ ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); |  | 
|   259   __ ldr(scratch, MemOperand(scratch, Context::SlotOffset(index))); |  | 
|   260   __ Move(ip, function); |  | 
|   261   __ cmp(ip, scratch); |  | 
|   262   __ b(ne, miss); |  | 
|   263  |  | 
|   264   // Load its initial map. The global functions all have initial maps. |  | 
|   265   __ Move(prototype, Handle<Map>(function->initial_map())); |  | 
|   266   // Load the prototype from the initial map. |  | 
|   267   __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); |  | 
|   268 } |  | 
|   269  |  | 
|   270  |  | 
|   271 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( |  | 
|   272     MacroAssembler* masm, Register receiver, Register scratch1, |  | 
|   273     Register scratch2, Label* miss_label) { |  | 
|   274   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); |  | 
|   275   __ mov(r0, scratch1); |  | 
|   276   __ Ret(); |  | 
|   277 } |  | 
|   278  |  | 
|   279  |  | 
|   280 // Generate code to check that a global property cell is empty. Create |  | 
|   281 // the property cell at compilation time if no cell exists for the |  | 
|   282 // property. |  | 
|   283 void PropertyHandlerCompiler::GenerateCheckPropertyCell( |  | 
|   284     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, |  | 
|   285     Register scratch, Label* miss) { |  | 
|   286   Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name); |  | 
|   287   DCHECK(cell->value()->IsTheHole()); |  | 
|   288   __ mov(scratch, Operand(cell)); |  | 
|   289   __ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); |  | 
|   290   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |  | 
|   291   __ cmp(scratch, ip); |  | 
|   292   __ b(ne, miss); |  | 
|   293 } |  | 
|   294  |  | 
|   295  |  | 
|   296 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, |  | 
|   297                                      Register holder, Register name, |  | 
|   298                                      Handle<JSObject> holder_obj) { |  | 
|   299   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); |  | 
|   300   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); |  | 
|   301   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); |  | 
|   302   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); |  | 
|   303   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); |  | 
|   304   __ push(name); |  | 
|   305   Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); |  | 
|   306   DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); |  | 
|   307   Register scratch = name; |  | 
|   308   __ mov(scratch, Operand(interceptor)); |  | 
|   309   __ push(scratch); |  | 
|   310   __ push(receiver); |  | 
|   311   __ push(holder); |  | 
|   312 } |  | 
|   313  |  | 
|   314  |  | 
|   315 static void CompileCallLoadPropertyWithInterceptor( |  | 
|   316     MacroAssembler* masm, Register receiver, Register holder, Register name, |  | 
|   317     Handle<JSObject> holder_obj, IC::UtilityId id) { |  | 
|   318   PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |  | 
|   319   __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), |  | 
|   320                            NamedLoadHandlerCompiler::kInterceptorArgsLength); |  | 
|   321 } |  | 
|   322  |  | 
|   323  |  | 
|   324 // Generate call to api function. |  | 
|   325 void PropertyHandlerCompiler::GenerateFastApiCall( |  | 
|   326     MacroAssembler* masm, const CallOptimization& optimization, |  | 
|   327     Handle<Map> receiver_map, Register receiver, Register scratch_in, |  | 
|   328     bool is_store, int argc, Register* values) { |  | 
|   329   DCHECK(!receiver.is(scratch_in)); |  | 
|   330   __ push(receiver); |  | 
|   331   // Write the arguments to stack frame. |  | 
|   332   for (int i = 0; i < argc; i++) { |  | 
|   333     Register arg = values[argc - 1 - i]; |  | 
|   334     DCHECK(!receiver.is(arg)); |  | 
|   335     DCHECK(!scratch_in.is(arg)); |  | 
|   336     __ push(arg); |  | 
|   337   } |  | 
|   338   DCHECK(optimization.is_simple_api_call()); |  | 
|   339  |  | 
|   340   // Abi for CallApiFunctionStub. |  | 
|   341   Register callee = r0; |  | 
|   342   Register call_data = r4; |  | 
|   343   Register holder = r2; |  | 
|   344   Register api_function_address = r1; |  | 
|   345  |  | 
|   346   // Put holder in place. |  | 
|   347   CallOptimization::HolderLookup holder_lookup; |  | 
|   348   Handle<JSObject> api_holder = |  | 
|   349       optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); |  | 
|   350   switch (holder_lookup) { |  | 
|   351     case CallOptimization::kHolderIsReceiver: |  | 
|   352       __ Move(holder, receiver); |  | 
|   353       break; |  | 
|   354     case CallOptimization::kHolderFound: |  | 
|   355       __ Move(holder, api_holder); |  | 
|   356       break; |  | 
|   357     case CallOptimization::kHolderNotFound: |  | 
|   358       UNREACHABLE(); |  | 
|   359       break; |  | 
|   360   } |  | 
|   361  |  | 
|   362   Isolate* isolate = masm->isolate(); |  | 
|   363   Handle<JSFunction> function = optimization.constant_function(); |  | 
|   364   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |  | 
|   365   Handle<Object> call_data_obj(api_call_info->data(), isolate); |  | 
|   366  |  | 
|   367   // Put callee in place. |  | 
|   368   __ Move(callee, function); |  | 
|   369  |  | 
|   370   bool call_data_undefined = false; |  | 
|   371   // Put call_data in place. |  | 
|   372   if (isolate->heap()->InNewSpace(*call_data_obj)) { |  | 
|   373     __ Move(call_data, api_call_info); |  | 
|   374     __ ldr(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset)); |  | 
|   375   } else if (call_data_obj->IsUndefined()) { |  | 
|   376     call_data_undefined = true; |  | 
|   377     __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex); |  | 
|   378   } else { |  | 
|   379     __ Move(call_data, call_data_obj); |  | 
|   380   } |  | 
|   381  |  | 
|   382   // Put api_function_address in place. |  | 
|   383   Address function_address = v8::ToCData<Address>(api_call_info->callback()); |  | 
|   384   ApiFunction fun(function_address); |  | 
|   385   ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; |  | 
|   386   ExternalReference ref = ExternalReference(&fun, type, masm->isolate()); |  | 
|   387   __ mov(api_function_address, Operand(ref)); |  | 
|   388  |  | 
|   389   // Jump to stub. |  | 
|   390   CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); |  | 
|   391   __ TailCallStub(&stub); |  | 
|   392 } |  | 
|   393  |  | 
|   394  |  | 
|   395 void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, |  | 
|   396                                               Handle<Code> code) { |  | 
|   397   __ Jump(code, RelocInfo::CODE_TARGET); |  | 
|   398 } |  | 
|   399  |  | 
|   400  |  | 
|   401 #undef __ |  | 
|   402 #define __ ACCESS_MASM(masm()) |  | 
|   403  |  | 
|   404  |  | 
|   405 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, |  | 
|   406                                                     Handle<Name> name) { |  | 
|   407   if (!label->is_unused()) { |  | 
|   408     __ bind(label); |  | 
|   409     __ mov(this->name(), Operand(name)); |  | 
|   410   } |  | 
|   411 } |  | 
|   412  |  | 
|   413  |  | 
|   414 // Generate StoreTransition code, value is passed in r0 register. |  | 
|   415 // When leaving generated code after success, the receiver_reg and name_reg |  | 
|   416 // may be clobbered.  Upon branch to miss_label, the receiver and name |  | 
|   417 // registers have their original values. |  | 
|   418 void NamedStoreHandlerCompiler::GenerateStoreTransition( |  | 
|   419     Handle<Map> transition, Handle<Name> name, Register receiver_reg, |  | 
|   420     Register storage_reg, Register value_reg, Register scratch1, |  | 
|   421     Register scratch2, Register scratch3, Label* miss_label, Label* slow) { |  | 
|   422   // r0 : value |  | 
|   423   Label exit; |  | 
|   424  |  | 
|   425   int descriptor = transition->LastAdded(); |  | 
|   426   DescriptorArray* descriptors = transition->instance_descriptors(); |  | 
|   427   PropertyDetails details = descriptors->GetDetails(descriptor); |  | 
|   428   Representation representation = details.representation(); |  | 
|   429   DCHECK(!representation.IsNone()); |  | 
|   430  |  | 
|   431   if (details.type() == CONSTANT) { |  | 
|   432     Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); |  | 
|   433     __ Move(scratch1, constant); |  | 
|   434     __ cmp(value_reg, scratch1); |  | 
|   435     __ b(ne, miss_label); |  | 
|   436   } else if (representation.IsSmi()) { |  | 
|   437     __ JumpIfNotSmi(value_reg, miss_label); |  | 
|   438   } else if (representation.IsHeapObject()) { |  | 
|   439     __ JumpIfSmi(value_reg, miss_label); |  | 
|   440     HeapType* field_type = descriptors->GetFieldType(descriptor); |  | 
|   441     HeapType::Iterator<Map> it = field_type->Classes(); |  | 
|   442     if (!it.Done()) { |  | 
|   443       __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); |  | 
|   444       Label do_store; |  | 
|   445       while (true) { |  | 
|   446         __ CompareMap(scratch1, it.Current(), &do_store); |  | 
|   447         it.Advance(); |  | 
|   448         if (it.Done()) { |  | 
|   449           __ b(ne, miss_label); |  | 
|   450           break; |  | 
|   451         } |  | 
|   452         __ b(eq, &do_store); |  | 
|   453       } |  | 
|   454       __ bind(&do_store); |  | 
|   455     } |  | 
|   456   } else if (representation.IsDouble()) { |  | 
|   457     Label do_store, heap_number; |  | 
|   458     __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex); |  | 
|   459     __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow, |  | 
|   460                           TAG_RESULT, MUTABLE); |  | 
|   461  |  | 
|   462     __ JumpIfNotSmi(value_reg, &heap_number); |  | 
|   463     __ SmiUntag(scratch1, value_reg); |  | 
|   464     __ vmov(s0, scratch1); |  | 
|   465     __ vcvt_f64_s32(d0, s0); |  | 
|   466     __ jmp(&do_store); |  | 
|   467  |  | 
|   468     __ bind(&heap_number); |  | 
|   469     __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, |  | 
|   470                 miss_label, DONT_DO_SMI_CHECK); |  | 
|   471     __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |  | 
|   472  |  | 
|   473     __ bind(&do_store); |  | 
|   474     __ vstr(d0, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); |  | 
|   475   } |  | 
|   476  |  | 
|   477   // Stub never generated for objects that require access checks. |  | 
|   478   DCHECK(!transition->is_access_check_needed()); |  | 
|   479  |  | 
|   480   // Perform map transition for the receiver if necessary. |  | 
|   481   if (details.type() == FIELD && |  | 
|   482       Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { |  | 
|   483     // The properties must be extended before we can store the value. |  | 
|   484     // We jump to a runtime call that extends the properties array. |  | 
|   485     __ push(receiver_reg); |  | 
|   486     __ mov(r2, Operand(transition)); |  | 
|   487     __ Push(r2, r0); |  | 
|   488     __ TailCallExternalReference( |  | 
|   489         ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |  | 
|   490                           isolate()), |  | 
|   491         3, 1); |  | 
|   492     return; |  | 
|   493   } |  | 
|   494  |  | 
|   495   // Update the map of the object. |  | 
|   496   __ mov(scratch1, Operand(transition)); |  | 
|   497   __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |  | 
|   498  |  | 
|   499   // Update the write barrier for the map field. |  | 
|   500   __ RecordWriteField(receiver_reg, |  | 
|   501                       HeapObject::kMapOffset, |  | 
|   502                       scratch1, |  | 
|   503                       scratch2, |  | 
|   504                       kLRHasNotBeenSaved, |  | 
|   505                       kDontSaveFPRegs, |  | 
|   506                       OMIT_REMEMBERED_SET, |  | 
|   507                       OMIT_SMI_CHECK); |  | 
|   508  |  | 
|   509   if (details.type() == CONSTANT) { |  | 
|   510     DCHECK(value_reg.is(r0)); |  | 
|   511     __ Ret(); |  | 
|   512     return; |  | 
|   513   } |  | 
|   514  |  | 
|   515   int index = transition->instance_descriptors()->GetFieldIndex( |  | 
|   516       transition->LastAdded()); |  | 
|   517  |  | 
|   518   // Adjust for the number of properties stored in the object. Even in the |  | 
|   519   // face of a transition we can use the old map here because the size of the |  | 
|   520   // object and the number of in-object properties is not going to change. |  | 
|   521   index -= transition->inobject_properties(); |  | 
|   522  |  | 
|   523   // TODO(verwaest): Share this code as a code stub. |  | 
|   524   SmiCheck smi_check = representation.IsTagged() |  | 
|   525       ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; |  | 
|   526   if (index < 0) { |  | 
|   527     // Set the property straight into the object. |  | 
|   528     int offset = transition->instance_size() + (index * kPointerSize); |  | 
|   529     if (representation.IsDouble()) { |  | 
|   530       __ str(storage_reg, FieldMemOperand(receiver_reg, offset)); |  | 
|   531     } else { |  | 
|   532       __ str(value_reg, FieldMemOperand(receiver_reg, offset)); |  | 
|   533     } |  | 
|   534  |  | 
|   535     if (!representation.IsSmi()) { |  | 
|   536       // Update the write barrier for the array address. |  | 
|   537       if (!representation.IsDouble()) { |  | 
|   538         __ mov(storage_reg, value_reg); |  | 
|   539       } |  | 
|   540       __ RecordWriteField(receiver_reg, |  | 
|   541                           offset, |  | 
|   542                           storage_reg, |  | 
|   543                           scratch1, |  | 
|   544                           kLRHasNotBeenSaved, |  | 
|   545                           kDontSaveFPRegs, |  | 
|   546                           EMIT_REMEMBERED_SET, |  | 
|   547                           smi_check); |  | 
|   548     } |  | 
|   549   } else { |  | 
|   550     // Write to the properties array. |  | 
|   551     int offset = index * kPointerSize + FixedArray::kHeaderSize; |  | 
|   552     // Get the properties array |  | 
|   553     __ ldr(scratch1, |  | 
|   554            FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); |  | 
|   555     if (representation.IsDouble()) { |  | 
|   556       __ str(storage_reg, FieldMemOperand(scratch1, offset)); |  | 
|   557     } else { |  | 
|   558       __ str(value_reg, FieldMemOperand(scratch1, offset)); |  | 
|   559     } |  | 
|   560  |  | 
|   561     if (!representation.IsSmi()) { |  | 
|   562       // Update the write barrier for the array address. |  | 
|   563       if (!representation.IsDouble()) { |  | 
|   564         __ mov(storage_reg, value_reg); |  | 
|   565       } |  | 
|   566       __ RecordWriteField(scratch1, |  | 
|   567                           offset, |  | 
|   568                           storage_reg, |  | 
|   569                           receiver_reg, |  | 
|   570                           kLRHasNotBeenSaved, |  | 
|   571                           kDontSaveFPRegs, |  | 
|   572                           EMIT_REMEMBERED_SET, |  | 
|   573                           smi_check); |  | 
|   574     } |  | 
|   575   } |  | 
|   576  |  | 
|   577   // Return the value (register r0). |  | 
|   578   DCHECK(value_reg.is(r0)); |  | 
|   579   __ bind(&exit); |  | 
|   580   __ Ret(); |  | 
|   581 } |  | 
|   582  |  | 
|   583  |  | 
|   584 void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, |  | 
|   585                                                    Register value_reg, |  | 
|   586                                                    Label* miss_label) { |  | 
|   587   DCHECK(lookup->representation().IsHeapObject()); |  | 
|   588   __ JumpIfSmi(value_reg, miss_label); |  | 
|   589   HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); |  | 
|   590   __ ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset)); |  | 
|   591   Label do_store; |  | 
|   592   while (true) { |  | 
|   593     __ CompareMap(scratch1(), it.Current(), &do_store); |  | 
|   594     it.Advance(); |  | 
|   595     if (it.Done()) { |  | 
|   596       __ b(ne, miss_label); |  | 
|   597       break; |  | 
|   598     } |  | 
|   599     __ b(eq, &do_store); |  | 
|   600   } |  | 
|   601   __ bind(&do_store); |  | 
|   602  |  | 
|   603   StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), |  | 
|   604                       lookup->representation()); |  | 
|   605   GenerateTailCall(masm(), stub.GetCode()); |  | 
|   606 } |  | 
|   607  |  | 
|   608  |  | 
|   609 Register PropertyHandlerCompiler::CheckPrototypes( |  | 
|   610     Register object_reg, Register holder_reg, Register scratch1, |  | 
|   611     Register scratch2, Handle<Name> name, Label* miss, |  | 
|   612     PrototypeCheckType check) { |  | 
|   613   Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); |  | 
|   614  |  | 
|   615   // Make sure there's no overlap between holder and object registers. |  | 
|   616   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |  | 
|   617   DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |  | 
|   618          && !scratch2.is(scratch1)); |  | 
|   619  |  | 
|   620   // Keep track of the current object in register reg. |  | 
|   621   Register reg = object_reg; |  | 
|   622   int depth = 0; |  | 
|   623  |  | 
|   624   Handle<JSObject> current = Handle<JSObject>::null(); |  | 
|   625   if (type()->IsConstant()) { |  | 
|   626     current = Handle<JSObject>::cast(type()->AsConstant()->Value()); |  | 
|   627   } |  | 
|   628   Handle<JSObject> prototype = Handle<JSObject>::null(); |  | 
|   629   Handle<Map> current_map = receiver_map; |  | 
|   630   Handle<Map> holder_map(holder()->map()); |  | 
|   631   // Traverse the prototype chain and check the maps in the prototype chain for |  | 
|   632   // fast and global objects or do negative lookup for normal objects. |  | 
|   633   while (!current_map.is_identical_to(holder_map)) { |  | 
|   634     ++depth; |  | 
|   635  |  | 
|   636     // Only global objects and objects that do not require access |  | 
|   637     // checks are allowed in stubs. |  | 
|   638     DCHECK(current_map->IsJSGlobalProxyMap() || |  | 
|   639            !current_map->is_access_check_needed()); |  | 
|   640  |  | 
|   641     prototype = handle(JSObject::cast(current_map->prototype())); |  | 
|   642     if (current_map->is_dictionary_map() && |  | 
|   643         !current_map->IsJSGlobalObjectMap()) { |  | 
|   644       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast. |  | 
|   645       if (!name->IsUniqueName()) { |  | 
|   646         DCHECK(name->IsString()); |  | 
|   647         name = factory()->InternalizeString(Handle<String>::cast(name)); |  | 
|   648       } |  | 
|   649       DCHECK(current.is_null() || |  | 
|   650              current->property_dictionary()->FindEntry(name) == |  | 
|   651              NameDictionary::kNotFound); |  | 
|   652  |  | 
|   653       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, |  | 
|   654                                        scratch1, scratch2); |  | 
|   655  |  | 
|   656       __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |  | 
|   657       reg = holder_reg;  // From now on the object will be in holder_reg. |  | 
|   658       __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); |  | 
|   659     } else { |  | 
|   660       Register map_reg = scratch1; |  | 
|   661       if (depth != 1 || check == CHECK_ALL_MAPS) { |  | 
|   662         // CheckMap implicitly loads the map of |reg| into |map_reg|. |  | 
|   663         __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK); |  | 
|   664       } else { |  | 
|   665         __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); |  | 
|   666       } |  | 
|   667  |  | 
|   668       // Check access rights to the global object.  This has to happen after |  | 
|   669       // the map check so that we know that the object is actually a global |  | 
|   670       // object. |  | 
|   671       // This allows us to install generated handlers for accesses to the |  | 
|   672       // global proxy (as opposed to using slow ICs). See corresponding code |  | 
|   673       // in LookupForRead(). |  | 
|   674       if (current_map->IsJSGlobalProxyMap()) { |  | 
|   675         __ CheckAccessGlobalProxy(reg, scratch2, miss); |  | 
|   676       } else if (current_map->IsJSGlobalObjectMap()) { |  | 
|   677         GenerateCheckPropertyCell( |  | 
|   678             masm(), Handle<JSGlobalObject>::cast(current), name, |  | 
|   679             scratch2, miss); |  | 
|   680       } |  | 
|   681  |  | 
|   682       reg = holder_reg;  // From now on the object will be in holder_reg. |  | 
|   683  |  | 
|   684       // Two possible reasons for loading the prototype from the map: |  | 
|   685       // (1) Can't store references to new space in code. |  | 
|   686       // (2) Handler is shared for all receivers with the same prototype |  | 
|   687       //     map (but not necessarily the same prototype instance). |  | 
|   688       bool load_prototype_from_map = |  | 
|   689           heap()->InNewSpace(*prototype) || depth == 1; |  | 
|   690       if (load_prototype_from_map) { |  | 
|   691         __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); |  | 
|   692       } else { |  | 
|   693         __ mov(reg, Operand(prototype)); |  | 
|   694       } |  | 
|   695     } |  | 
|   696  |  | 
|   697     // Go to the next object in the prototype chain. |  | 
|   698     current = prototype; |  | 
|   699     current_map = handle(current->map()); |  | 
|   700   } |  | 
|   701  |  | 
|   702   // Log the check depth. |  | 
|   703   LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |  | 
|   704  |  | 
|   705   if (depth != 0 || check == CHECK_ALL_MAPS) { |  | 
|   706     // Check the holder map. |  | 
|   707     __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK); |  | 
|   708   } |  | 
|   709  |  | 
|   710   // Perform security check for access to the global object. |  | 
|   711   DCHECK(current_map->IsJSGlobalProxyMap() || |  | 
|   712          !current_map->is_access_check_needed()); |  | 
|   713   if (current_map->IsJSGlobalProxyMap()) { |  | 
|   714     __ CheckAccessGlobalProxy(reg, scratch1, miss); |  | 
|   715   } |  | 
|   716  |  | 
|   717   // Return the register containing the holder. |  | 
|   718   return reg; |  | 
|   719 } |  | 
|   720  |  | 
|   721  |  | 
|   722 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { |  | 
|   723   if (!miss->is_unused()) { |  | 
|   724     Label success; |  | 
|   725     __ b(&success); |  | 
|   726     __ bind(miss); |  | 
|   727     TailCallBuiltin(masm(), MissBuiltin(kind())); |  | 
|   728     __ bind(&success); |  | 
|   729   } |  | 
|   730 } |  | 
|   731  |  | 
|   732  |  | 
|   733 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { |  | 
|   734   if (!miss->is_unused()) { |  | 
|   735     Label success; |  | 
|   736     __ b(&success); |  | 
|   737     GenerateRestoreName(miss, name); |  | 
|   738     TailCallBuiltin(masm(), MissBuiltin(kind())); |  | 
|   739     __ bind(&success); |  | 
|   740   } |  | 
|   741 } |  | 
|   742  |  | 
|   743  |  | 
|   744 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { |  | 
|   745   // Return the constant value. |  | 
|   746   __ Move(r0, value); |  | 
|   747   __ Ret(); |  | 
|   748 } |  | 
|   749  |  | 
|   750  |  | 
|   751 void NamedLoadHandlerCompiler::GenerateLoadCallback( |  | 
|   752     Register reg, Handle<ExecutableAccessorInfo> callback) { |  | 
|   753   // Build AccessorInfo::args_ list on the stack and push property name below |  | 
|   754   // the exit frame to make GC aware of them and store pointers to them. |  | 
|   755   STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); |  | 
|   756   STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); |  | 
|   757   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); |  | 
|   758   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); |  | 
|   759   STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); |  | 
|   760   STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); |  | 
|   761   STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); |  | 
|   762   DCHECK(!scratch2().is(reg)); |  | 
|   763   DCHECK(!scratch3().is(reg)); |  | 
|   764   DCHECK(!scratch4().is(reg)); |  | 
|   765   __ push(receiver()); |  | 
|   766   if (heap()->InNewSpace(callback->data())) { |  | 
|   767     __ Move(scratch3(), callback); |  | 
|   768     __ ldr(scratch3(), FieldMemOperand(scratch3(), |  | 
|   769                                        ExecutableAccessorInfo::kDataOffset)); |  | 
|   770   } else { |  | 
|   771     __ Move(scratch3(), Handle<Object>(callback->data(), isolate())); |  | 
|   772   } |  | 
|   773   __ push(scratch3()); |  | 
|   774   __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); |  | 
|   775   __ mov(scratch4(), scratch3()); |  | 
|   776   __ Push(scratch3(), scratch4()); |  | 
|   777   __ mov(scratch4(), |  | 
|   778          Operand(ExternalReference::isolate_address(isolate()))); |  | 
|   779   __ Push(scratch4(), reg); |  | 
|   780   __ mov(scratch2(), sp);  // scratch2 = PropertyAccessorInfo::args_ |  | 
|   781   __ push(name()); |  | 
|   782  |  | 
|   783   // Abi for CallApiGetter |  | 
|   784   Register getter_address_reg = r2; |  | 
|   785  |  | 
|   786   Address getter_address = v8::ToCData<Address>(callback->getter()); |  | 
|   787   ApiFunction fun(getter_address); |  | 
|   788   ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; |  | 
|   789   ExternalReference ref = ExternalReference(&fun, type, isolate()); |  | 
|   790   __ mov(getter_address_reg, Operand(ref)); |  | 
|   791  |  | 
|   792   CallApiGetterStub stub(isolate()); |  | 
|   793   __ TailCallStub(&stub); |  | 
|   794 } |  | 
|   795  |  | 
|   796  |  | 
|   797 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( |  | 
|   798     LookupIterator* it, Register holder_reg) { |  | 
|   799   DCHECK(holder()->HasNamedInterceptor()); |  | 
|   800   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); |  | 
|   801  |  | 
|   802   // Compile the interceptor call, followed by inline code to load the |  | 
|   803   // property from further up the prototype chain if the call fails. |  | 
|   804   // Check that the maps haven't changed. |  | 
|   805   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |  | 
|   806  |  | 
|   807   // Preserve the receiver register explicitly whenever it is different from the |  | 
|   808   // holder and it is needed should the interceptor return without any result. |  | 
|   809   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD |  | 
|   810   // case might cause a miss during the prototype check. |  | 
|   811   bool must_perform_prototype_check = |  | 
|   812       !holder().is_identical_to(it->GetHolder<JSObject>()); |  | 
|   813   bool must_preserve_receiver_reg = |  | 
|   814       !receiver().is(holder_reg) && |  | 
|   815       (it->property_kind() == LookupIterator::ACCESSOR || |  | 
|   816        must_perform_prototype_check); |  | 
|   817  |  | 
|   818   // Save necessary data before invoking an interceptor. |  | 
|   819   // Requires a frame to make GC aware of pushed pointers. |  | 
|   820   { |  | 
|   821     FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL); |  | 
|   822     if (must_preserve_receiver_reg) { |  | 
|   823       __ Push(receiver(), holder_reg, this->name()); |  | 
|   824     } else { |  | 
|   825       __ Push(holder_reg, this->name()); |  | 
|   826     } |  | 
|   827     // Invoke an interceptor.  Note: map checks from receiver to |  | 
|   828     // interceptor's holder has been compiled before (see a caller |  | 
|   829     // of this method.) |  | 
|   830     CompileCallLoadPropertyWithInterceptor( |  | 
|   831         masm(), receiver(), holder_reg, this->name(), holder(), |  | 
|   832         IC::kLoadPropertyWithInterceptorOnly); |  | 
|   833  |  | 
|   834     // Check if interceptor provided a value for property.  If it's |  | 
|   835     // the case, return immediately. |  | 
|   836     Label interceptor_failed; |  | 
|   837     __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); |  | 
|   838     __ cmp(r0, scratch1()); |  | 
|   839     __ b(eq, &interceptor_failed); |  | 
|   840     frame_scope.GenerateLeaveFrame(); |  | 
|   841     __ Ret(); |  | 
|   842  |  | 
|   843     __ bind(&interceptor_failed); |  | 
|   844     __ pop(this->name()); |  | 
|   845     __ pop(holder_reg); |  | 
|   846     if (must_preserve_receiver_reg) { |  | 
|   847       __ pop(receiver()); |  | 
|   848     } |  | 
|   849     // Leave the internal frame. |  | 
|   850   } |  | 
|   851  |  | 
|   852   GenerateLoadPostInterceptor(it, holder_reg); |  | 
|   853 } |  | 
|   854  |  | 
|   855  |  | 
|   856 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { |  | 
|   857   // Call the runtime system to load the interceptor. |  | 
|   858   DCHECK(holder()->HasNamedInterceptor()); |  | 
|   859   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); |  | 
|   860   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), |  | 
|   861                            holder()); |  | 
|   862  |  | 
|   863   ExternalReference ref = ExternalReference( |  | 
|   864       IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); |  | 
|   865   __ TailCallExternalReference( |  | 
|   866       ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); |  | 
|   867 } |  | 
|   868  |  | 
|   869  |  | 
|   870 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( |  | 
|   871     Handle<JSObject> object, Handle<Name> name, |  | 
|   872     Handle<ExecutableAccessorInfo> callback) { |  | 
|   873   Register holder_reg = Frontend(receiver(), name); |  | 
|   874  |  | 
|   875   __ push(receiver());  // receiver |  | 
|   876   __ push(holder_reg); |  | 
|   877   __ mov(ip, Operand(callback));  // callback info |  | 
|   878   __ push(ip); |  | 
|   879   __ mov(ip, Operand(name)); |  | 
|   880   __ Push(ip, value()); |  | 
|   881  |  | 
|   882   // Do tail-call to the runtime system. |  | 
|   883   ExternalReference store_callback_property = |  | 
|   884       ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); |  | 
|   885   __ TailCallExternalReference(store_callback_property, 5, 1); |  | 
|   886  |  | 
|   887   // Return the generated code. |  | 
|   888   return GetCode(kind(), Code::FAST, name); |  | 
|   889 } |  | 
|   890  |  | 
|   891  |  | 
|   892 #undef __ |  | 
|   893 #define __ ACCESS_MASM(masm) |  | 
|   894  |  | 
|   895  |  | 
|   896 void NamedStoreHandlerCompiler::GenerateStoreViaSetter( |  | 
|   897     MacroAssembler* masm, Handle<HeapType> type, Register receiver, |  | 
|   898     Handle<JSFunction> setter) { |  | 
|   899   // ----------- S t a t e ------------- |  | 
|   900   //  -- lr    : return address |  | 
|   901   // ----------------------------------- |  | 
|   902   { |  | 
|   903     FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |  | 
|   904  |  | 
|   905     // Save value register, so we can restore it later. |  | 
|   906     __ push(value()); |  | 
|   907  |  | 
|   908     if (!setter.is_null()) { |  | 
|   909       // Call the JavaScript setter with receiver and value on the stack. |  | 
|   910       if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { |  | 
|   911         // Swap in the global receiver. |  | 
|   912         __ ldr(receiver, |  | 
|   913                FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); |  | 
|   914       } |  | 
|   915       __ Push(receiver, value()); |  | 
|   916       ParameterCount actual(1); |  | 
|   917       ParameterCount expected(setter); |  | 
|   918       __ InvokeFunction(setter, expected, actual, |  | 
|   919                         CALL_FUNCTION, NullCallWrapper()); |  | 
|   920     } else { |  | 
|   921       // If we generate a global code snippet for deoptimization only, remember |  | 
|   922       // the place to continue after deoptimization. |  | 
|   923       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); |  | 
|   924     } |  | 
|   925  |  | 
|   926     // We have to return the passed value, not the return value of the setter. |  | 
|   927     __ pop(r0); |  | 
|   928  |  | 
|   929     // Restore context register. |  | 
|   930     __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |  | 
|   931   } |  | 
|   932   __ Ret(); |  | 
|   933 } |  | 
|   934  |  | 
|   935  |  | 
|   936 #undef __ |  | 
|   937 #define __ ACCESS_MASM(masm()) |  | 
|   938  |  | 
|   939  |  | 
|   940 Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( |  | 
|   941     Handle<Name> name) { |  | 
|   942   __ Push(receiver(), this->name(), value()); |  | 
|   943  |  | 
|   944   // Do tail-call to the runtime system. |  | 
|   945   ExternalReference store_ic_property = ExternalReference( |  | 
|   946       IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); |  | 
|   947   __ TailCallExternalReference(store_ic_property, 3, 1); |  | 
|   948  |  | 
|   949   // Return the generated code. |  | 
|   950   return GetCode(kind(), Code::FAST, name); |  | 
|   951 } |  | 
|   952  |  | 
|   953  |  | 
|   954 Register* PropertyAccessCompiler::load_calling_convention() { |  | 
|   955   // receiver, name, scratch1, scratch2, scratch3, scratch4. |  | 
|   956   Register receiver = LoadIC::ReceiverRegister(); |  | 
|   957   Register name = LoadIC::NameRegister(); |  | 
|   958   static Register registers[] = { receiver, name, r3, r0, r4, r5 }; |  | 
|   959   return registers; |  | 
|   960 } |  | 
|   961  |  | 
|   962  |  | 
|   963 Register* PropertyAccessCompiler::store_calling_convention() { |  | 
|   964   // receiver, name, scratch1, scratch2, scratch3. |  | 
|   965   Register receiver = StoreIC::ReceiverRegister(); |  | 
|   966   Register name = StoreIC::NameRegister(); |  | 
|   967   DCHECK(r3.is(KeyedStoreIC::MapRegister())); |  | 
|   968   static Register registers[] = { receiver, name, r3, r4, r5 }; |  | 
|   969   return registers; |  | 
|   970 } |  | 
|   971  |  | 
|   972  |  | 
|   973 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } |  | 
|   974  |  | 
|   975  |  | 
|   976 #undef __ |  | 
|   977 #define __ ACCESS_MASM(masm) |  | 
|   978  |  | 
|   979  |  | 
|   980 void NamedLoadHandlerCompiler::GenerateLoadViaGetter( |  | 
|   981     MacroAssembler* masm, Handle<HeapType> type, Register receiver, |  | 
|   982     Handle<JSFunction> getter) { |  | 
|   983   // ----------- S t a t e ------------- |  | 
|   984   //  -- r0    : receiver |  | 
|   985   //  -- r2    : name |  | 
|   986   //  -- lr    : return address |  | 
|   987   // ----------------------------------- |  | 
|   988   { |  | 
|   989     FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |  | 
|   990  |  | 
|   991     if (!getter.is_null()) { |  | 
|   992       // Call the JavaScript getter with the receiver on the stack. |  | 
|   993       if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { |  | 
|   994         // Swap in the global receiver. |  | 
|   995         __ ldr(receiver, |  | 
|   996                FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); |  | 
|   997       } |  | 
|   998       __ push(receiver); |  | 
|   999       ParameterCount actual(0); |  | 
|  1000       ParameterCount expected(getter); |  | 
|  1001       __ InvokeFunction(getter, expected, actual, |  | 
|  1002                         CALL_FUNCTION, NullCallWrapper()); |  | 
|  1003     } else { |  | 
|  1004       // If we generate a global code snippet for deoptimization only, remember |  | 
|  1005       // the place to continue after deoptimization. |  | 
|  1006       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); |  | 
|  1007     } |  | 
|  1008  |  | 
|  1009     // Restore context register. |  | 
|  1010     __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |  | 
|  1011   } |  | 
|  1012   __ Ret(); |  | 
|  1013 } |  | 
|  1014  |  | 
|  1015  |  | 
|  1016 #undef __ |  | 
|  1017 #define __ ACCESS_MASM(masm()) |  | 
|  1018  |  | 
|  1019  |  | 
|  1020 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( |  | 
|  1021     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { |  | 
|  1022   Label miss; |  | 
|  1023   FrontendHeader(receiver(), name, &miss); |  | 
|  1024  |  | 
|  1025   // Get the value from the cell. |  | 
|  1026   Register result = StoreIC::ValueRegister(); |  | 
|  1027   __ mov(result, Operand(cell)); |  | 
|  1028   __ ldr(result, FieldMemOperand(result, Cell::kValueOffset)); |  | 
|  1029  |  | 
|  1030   // Check for deleted property if property can actually be deleted. |  | 
|  1031   if (is_configurable) { |  | 
|  1032     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |  | 
|  1033     __ cmp(result, ip); |  | 
|  1034     __ b(eq, &miss); |  | 
|  1035   } |  | 
|  1036  |  | 
|  1037   Counters* counters = isolate()->counters(); |  | 
|  1038   __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3); |  | 
|  1039   __ Ret(); |  | 
|  1040  |  | 
|  1041   FrontendFooter(name, &miss); |  | 
|  1042  |  | 
|  1043   // Return the generated code. |  | 
|  1044   return GetCode(kind(), Code::NORMAL, name); |  | 
|  1045 } |  | 
|  1046  |  | 
|  1047  |  | 
|  1048 Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, |  | 
|  1049                                                     CodeHandleList* handlers, |  | 
|  1050                                                     Handle<Name> name, |  | 
|  1051                                                     Code::StubType type, |  | 
|  1052                                                     IcCheckType check) { |  | 
|  1053   Label miss; |  | 
|  1054  |  | 
|  1055   if (check == PROPERTY && |  | 
|  1056       (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { |  | 
|  1057     // In case we are compiling an IC for dictionary loads and stores, just |  | 
|  1058     // check whether the name is unique. |  | 
|  1059     if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) { |  | 
|  1060       __ JumpIfNotUniqueName(this->name(), &miss); |  | 
|  1061     } else { |  | 
|  1062       __ cmp(this->name(), Operand(name)); |  | 
|  1063       __ b(ne, &miss); |  | 
|  1064     } |  | 
|  1065   } |  | 
|  1066  |  | 
|  1067   Label number_case; |  | 
|  1068   Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; |  | 
|  1069   __ JumpIfSmi(receiver(), smi_target); |  | 
|  1070  |  | 
|  1071   // Polymorphic keyed stores may use the map register |  | 
|  1072   Register map_reg = scratch1(); |  | 
|  1073   DCHECK(kind() != Code::KEYED_STORE_IC || |  | 
|  1074          map_reg.is(KeyedStoreIC::MapRegister())); |  | 
|  1075  |  | 
|  1076   int receiver_count = types->length(); |  | 
|  1077   int number_of_handled_maps = 0; |  | 
|  1078   __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); |  | 
|  1079   for (int current = 0; current < receiver_count; ++current) { |  | 
|  1080     Handle<HeapType> type = types->at(current); |  | 
|  1081     Handle<Map> map = IC::TypeToMap(*type, isolate()); |  | 
|  1082     if (!map->is_deprecated()) { |  | 
|  1083       number_of_handled_maps++; |  | 
|  1084       __ mov(ip, Operand(map)); |  | 
|  1085       __ cmp(map_reg, ip); |  | 
|  1086       if (type->Is(HeapType::Number())) { |  | 
|  1087         DCHECK(!number_case.is_unused()); |  | 
|  1088         __ bind(&number_case); |  | 
|  1089       } |  | 
|  1090       __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq); |  | 
|  1091     } |  | 
|  1092   } |  | 
|  1093   DCHECK(number_of_handled_maps != 0); |  | 
|  1094  |  | 
|  1095   __ bind(&miss); |  | 
|  1096   TailCallBuiltin(masm(), MissBuiltin(kind())); |  | 
|  1097  |  | 
|  1098   // Return the generated code. |  | 
|  1099   InlineCacheState state = |  | 
|  1100       number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; |  | 
|  1101   return GetCode(kind(), type, name, state); |  | 
|  1102 } |  | 
|  1103  |  | 
|  1104  |  | 
|  1105 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( |  | 
|  1106     MapHandleList* receiver_maps, CodeHandleList* handler_stubs, |  | 
|  1107     MapHandleList* transitioned_maps) { |  | 
|  1108   Label miss; |  | 
|  1109   __ JumpIfSmi(receiver(), &miss); |  | 
|  1110  |  | 
|  1111   int receiver_count = receiver_maps->length(); |  | 
|  1112   __ ldr(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset)); |  | 
|  1113   for (int i = 0; i < receiver_count; ++i) { |  | 
|  1114     __ mov(ip, Operand(receiver_maps->at(i))); |  | 
|  1115     __ cmp(scratch1(), ip); |  | 
|  1116     if (transitioned_maps->at(i).is_null()) { |  | 
|  1117       __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq); |  | 
|  1118     } else { |  | 
|  1119       Label next_map; |  | 
|  1120       __ b(ne, &next_map); |  | 
|  1121       __ mov(transition_map(), Operand(transitioned_maps->at(i))); |  | 
|  1122       __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, al); |  | 
|  1123       __ bind(&next_map); |  | 
|  1124     } |  | 
|  1125   } |  | 
|  1126  |  | 
|  1127   __ bind(&miss); |  | 
|  1128   TailCallBuiltin(masm(), MissBuiltin(kind())); |  | 
|  1129  |  | 
|  1130   // Return the generated code. |  | 
|  1131   return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); |  | 
|  1132 } |  | 
|  1133  |  | 
|  1134  |  | 
|  1135 #undef __ |  | 
|  1136 #define __ ACCESS_MASM(masm) |  | 
|  1137  |  | 
|  1138  |  | 
|  1139 void ElementHandlerCompiler::GenerateLoadDictionaryElement( |  | 
|  1140     MacroAssembler* masm) { |  | 
|  1141   // The return address is in lr. |  | 
|  1142   Label slow, miss; |  | 
|  1143  |  | 
|  1144   Register key = LoadIC::NameRegister(); |  | 
|  1145   Register receiver = LoadIC::ReceiverRegister(); |  | 
|  1146   DCHECK(receiver.is(r1)); |  | 
|  1147   DCHECK(key.is(r2)); |  | 
|  1148  |  | 
|  1149   __ UntagAndJumpIfNotSmi(r6, key, &miss); |  | 
|  1150   __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); |  | 
|  1151   __ LoadFromNumberDictionary(&slow, r4, key, r0, r6, r3, r5); |  | 
|  1152   __ Ret(); |  | 
|  1153  |  | 
|  1154   __ bind(&slow); |  | 
|  1155   __ IncrementCounter( |  | 
|  1156       masm->isolate()->counters()->keyed_load_external_array_slow(), |  | 
|  1157       1, r2, r3); |  | 
|  1158  |  | 
|  1159   TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); |  | 
|  1160  |  | 
|  1161   // Miss case, call the runtime. |  | 
|  1162   __ bind(&miss); |  | 
|  1163  |  | 
|  1164   TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |  | 
|  1165 } |  | 
|  1166  |  | 
|  1167  |  | 
|  1168 #undef __ |  | 
|  1169  |  | 
|  1170 } }  // namespace v8::internal |  | 
|  1171  |  | 
|  1172 #endif  // V8_TARGET_ARCH_ARM |  | 
| OLD | NEW |