| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
| 8 | 8 |
| 9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
| 10 #include "src/ic-inl.h" | 10 #include "src/ic-inl.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 Register offset_scratch) { | 29 Register offset_scratch) { |
| 30 ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); | 30 ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); |
| 31 ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); | 31 ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); |
| 32 ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); | 32 ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); |
| 33 | 33 |
| 34 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address()); | 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()); | 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()); | 36 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address()); |
| 37 | 37 |
| 38 // Check the relative positions of the address fields. | 38 // Check the relative positions of the address fields. |
| 39 ASSERT(value_off_addr > key_off_addr); | 39 DCHECK(value_off_addr > key_off_addr); |
| 40 ASSERT((value_off_addr - key_off_addr) % 4 == 0); | 40 DCHECK((value_off_addr - key_off_addr) % 4 == 0); |
| 41 ASSERT((value_off_addr - key_off_addr) < (256 * 4)); | 41 DCHECK((value_off_addr - key_off_addr) < (256 * 4)); |
| 42 ASSERT(map_off_addr > key_off_addr); | 42 DCHECK(map_off_addr > key_off_addr); |
| 43 ASSERT((map_off_addr - key_off_addr) % 4 == 0); | 43 DCHECK((map_off_addr - key_off_addr) % 4 == 0); |
| 44 ASSERT((map_off_addr - key_off_addr) < (256 * 4)); | 44 DCHECK((map_off_addr - key_off_addr) < (256 * 4)); |
| 45 | 45 |
| 46 Label miss; | 46 Label miss; |
| 47 Register base_addr = scratch; | 47 Register base_addr = scratch; |
| 48 scratch = no_reg; | 48 scratch = no_reg; |
| 49 | 49 |
| 50 // Multiply by 3 because there are 3 fields per entry (name, code, map). | 50 // Multiply by 3 because there are 3 fields per entry (name, code, map). |
| 51 __ add(offset_scratch, offset, Operand(offset, LSL, 1)); | 51 __ add(offset_scratch, offset, Operand(offset, LSL, 1)); |
| 52 | 52 |
| 53 // Calculate the base address of the entry. | 53 // Calculate the base address of the entry. |
| 54 __ mov(base_addr, Operand(key_offset)); | 54 __ mov(base_addr, Operand(key_offset)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 70 scratch2 = no_reg; | 70 scratch2 = no_reg; |
| 71 __ ldr(code, MemOperand(base_addr, value_off_addr - key_off_addr)); | 71 __ ldr(code, MemOperand(base_addr, value_off_addr - key_off_addr)); |
| 72 | 72 |
| 73 // Check that the flags match what we're looking for. | 73 // Check that the flags match what we're looking for. |
| 74 Register flags_reg = base_addr; | 74 Register flags_reg = base_addr; |
| 75 base_addr = no_reg; | 75 base_addr = no_reg; |
| 76 __ ldr(flags_reg, FieldMemOperand(code, Code::kFlagsOffset)); | 76 __ ldr(flags_reg, FieldMemOperand(code, Code::kFlagsOffset)); |
| 77 // It's a nice optimization if this constant is encodable in the bic insn. | 77 // It's a nice optimization if this constant is encodable in the bic insn. |
| 78 | 78 |
| 79 uint32_t mask = Code::kFlagsNotUsedInLookup; | 79 uint32_t mask = Code::kFlagsNotUsedInLookup; |
| 80 ASSERT(__ ImmediateFitsAddrMode1Instruction(mask)); | 80 DCHECK(__ ImmediateFitsAddrMode1Instruction(mask)); |
| 81 __ bic(flags_reg, flags_reg, Operand(mask)); | 81 __ bic(flags_reg, flags_reg, Operand(mask)); |
| 82 __ cmp(flags_reg, Operand(flags)); | 82 __ cmp(flags_reg, Operand(flags)); |
| 83 __ b(ne, &miss); | 83 __ b(ne, &miss); |
| 84 | 84 |
| 85 #ifdef DEBUG | 85 #ifdef DEBUG |
| 86 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { | 86 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { |
| 87 __ jmp(&miss); | 87 __ jmp(&miss); |
| 88 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { | 88 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { |
| 89 __ jmp(&miss); | 89 __ jmp(&miss); |
| 90 } | 90 } |
| 91 #endif | 91 #endif |
| 92 | 92 |
| 93 // Jump to the first instruction in the code stub. | 93 // Jump to the first instruction in the code stub. |
| 94 __ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag)); | 94 __ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 95 | 95 |
| 96 // Miss: fall through. | 96 // Miss: fall through. |
| 97 __ bind(&miss); | 97 __ bind(&miss); |
| 98 } | 98 } |
| 99 | 99 |
| 100 | 100 |
| 101 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( | 101 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( |
| 102 MacroAssembler* masm, Label* miss_label, Register receiver, | 102 MacroAssembler* masm, Label* miss_label, Register receiver, |
| 103 Handle<Name> name, Register scratch0, Register scratch1) { | 103 Handle<Name> name, Register scratch0, Register scratch1) { |
| 104 ASSERT(name->IsUniqueName()); | 104 DCHECK(name->IsUniqueName()); |
| 105 ASSERT(!receiver.is(scratch0)); | 105 DCHECK(!receiver.is(scratch0)); |
| 106 Counters* counters = masm->isolate()->counters(); | 106 Counters* counters = masm->isolate()->counters(); |
| 107 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); | 107 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); |
| 108 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); | 108 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); |
| 109 | 109 |
| 110 Label done; | 110 Label done; |
| 111 | 111 |
| 112 const int kInterceptorOrAccessCheckNeededMask = | 112 const int kInterceptorOrAccessCheckNeededMask = |
| 113 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); | 113 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
| 114 | 114 |
| 115 // Bail out if the receiver has a named interceptor or requires access checks. | 115 // Bail out if the receiver has a named interceptor or requires access checks. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 Register name, | 156 Register name, |
| 157 Register scratch, | 157 Register scratch, |
| 158 Register extra, | 158 Register extra, |
| 159 Register extra2, | 159 Register extra2, |
| 160 Register extra3) { | 160 Register extra3) { |
| 161 Isolate* isolate = masm->isolate(); | 161 Isolate* isolate = masm->isolate(); |
| 162 Label miss; | 162 Label miss; |
| 163 | 163 |
| 164 // Make sure that code is valid. The multiplying code relies on the | 164 // Make sure that code is valid. The multiplying code relies on the |
| 165 // entry size being 12. | 165 // entry size being 12. |
| 166 ASSERT(sizeof(Entry) == 12); | 166 DCHECK(sizeof(Entry) == 12); |
| 167 | 167 |
| 168 // Make sure the flags does not name a specific type. | 168 // Make sure the flags does not name a specific type. |
| 169 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); | 169 DCHECK(Code::ExtractTypeFromFlags(flags) == 0); |
| 170 | 170 |
| 171 // Make sure that there are no register conflicts. | 171 // Make sure that there are no register conflicts. |
| 172 ASSERT(!scratch.is(receiver)); | 172 DCHECK(!scratch.is(receiver)); |
| 173 ASSERT(!scratch.is(name)); | 173 DCHECK(!scratch.is(name)); |
| 174 ASSERT(!extra.is(receiver)); | 174 DCHECK(!extra.is(receiver)); |
| 175 ASSERT(!extra.is(name)); | 175 DCHECK(!extra.is(name)); |
| 176 ASSERT(!extra.is(scratch)); | 176 DCHECK(!extra.is(scratch)); |
| 177 ASSERT(!extra2.is(receiver)); | 177 DCHECK(!extra2.is(receiver)); |
| 178 ASSERT(!extra2.is(name)); | 178 DCHECK(!extra2.is(name)); |
| 179 ASSERT(!extra2.is(scratch)); | 179 DCHECK(!extra2.is(scratch)); |
| 180 ASSERT(!extra2.is(extra)); | 180 DCHECK(!extra2.is(extra)); |
| 181 | 181 |
| 182 // Check scratch, extra and extra2 registers are valid. | 182 // Check scratch, extra and extra2 registers are valid. |
| 183 ASSERT(!scratch.is(no_reg)); | 183 DCHECK(!scratch.is(no_reg)); |
| 184 ASSERT(!extra.is(no_reg)); | 184 DCHECK(!extra.is(no_reg)); |
| 185 ASSERT(!extra2.is(no_reg)); | 185 DCHECK(!extra2.is(no_reg)); |
| 186 ASSERT(!extra3.is(no_reg)); | 186 DCHECK(!extra3.is(no_reg)); |
| 187 | 187 |
| 188 Counters* counters = masm->isolate()->counters(); | 188 Counters* counters = masm->isolate()->counters(); |
| 189 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, | 189 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, |
| 190 extra2, extra3); | 190 extra2, extra3); |
| 191 | 191 |
| 192 // Check that the receiver isn't a smi. | 192 // Check that the receiver isn't a smi. |
| 193 __ JumpIfSmi(receiver, &miss); | 193 __ JumpIfSmi(receiver, &miss); |
| 194 | 194 |
| 195 // Get the map of the receiver and compute the hash. | 195 // Get the map of the receiver and compute the hash. |
| 196 __ ldr(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); | 196 __ ldr(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 } | 277 } |
| 278 | 278 |
| 279 | 279 |
| 280 // Generate code to check that a global property cell is empty. Create | 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 | 281 // the property cell at compilation time if no cell exists for the |
| 282 // property. | 282 // property. |
| 283 void PropertyHandlerCompiler::GenerateCheckPropertyCell( | 283 void PropertyHandlerCompiler::GenerateCheckPropertyCell( |
| 284 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, | 284 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, |
| 285 Register scratch, Label* miss) { | 285 Register scratch, Label* miss) { |
| 286 Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name); | 286 Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name); |
| 287 ASSERT(cell->value()->IsTheHole()); | 287 DCHECK(cell->value()->IsTheHole()); |
| 288 __ mov(scratch, Operand(cell)); | 288 __ mov(scratch, Operand(cell)); |
| 289 __ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); | 289 __ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); |
| 290 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 290 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 291 __ cmp(scratch, ip); | 291 __ cmp(scratch, ip); |
| 292 __ b(ne, miss); | 292 __ b(ne, miss); |
| 293 } | 293 } |
| 294 | 294 |
| 295 | 295 |
| 296 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, | 296 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, |
| 297 Register holder, Register name, | 297 Register holder, Register name, |
| 298 Handle<JSObject> holder_obj) { | 298 Handle<JSObject> holder_obj) { |
| 299 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); | 299 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); |
| 300 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); | 300 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); |
| 301 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); | 301 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); |
| 302 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); | 302 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); |
| 303 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); | 303 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); |
| 304 __ push(name); | 304 __ push(name); |
| 305 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); | 305 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); |
| 306 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor)); | 306 DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); |
| 307 Register scratch = name; | 307 Register scratch = name; |
| 308 __ mov(scratch, Operand(interceptor)); | 308 __ mov(scratch, Operand(interceptor)); |
| 309 __ push(scratch); | 309 __ push(scratch); |
| 310 __ push(receiver); | 310 __ push(receiver); |
| 311 __ push(holder); | 311 __ push(holder); |
| 312 } | 312 } |
| 313 | 313 |
| 314 | 314 |
| 315 static void CompileCallLoadPropertyWithInterceptor( | 315 static void CompileCallLoadPropertyWithInterceptor( |
| 316 MacroAssembler* masm, Register receiver, Register holder, Register name, | 316 MacroAssembler* masm, Register receiver, Register holder, Register name, |
| 317 Handle<JSObject> holder_obj, IC::UtilityId id) { | 317 Handle<JSObject> holder_obj, IC::UtilityId id) { |
| 318 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); | 318 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |
| 319 __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), | 319 __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), |
| 320 NamedLoadHandlerCompiler::kInterceptorArgsLength); | 320 NamedLoadHandlerCompiler::kInterceptorArgsLength); |
| 321 } | 321 } |
| 322 | 322 |
| 323 | 323 |
| 324 // Generate call to api function. | 324 // Generate call to api function. |
| 325 void PropertyHandlerCompiler::GenerateFastApiCall( | 325 void PropertyHandlerCompiler::GenerateFastApiCall( |
| 326 MacroAssembler* masm, const CallOptimization& optimization, | 326 MacroAssembler* masm, const CallOptimization& optimization, |
| 327 Handle<Map> receiver_map, Register receiver, Register scratch_in, | 327 Handle<Map> receiver_map, Register receiver, Register scratch_in, |
| 328 bool is_store, int argc, Register* values) { | 328 bool is_store, int argc, Register* values) { |
| 329 ASSERT(!receiver.is(scratch_in)); | 329 DCHECK(!receiver.is(scratch_in)); |
| 330 __ push(receiver); | 330 __ push(receiver); |
| 331 // Write the arguments to stack frame. | 331 // Write the arguments to stack frame. |
| 332 for (int i = 0; i < argc; i++) { | 332 for (int i = 0; i < argc; i++) { |
| 333 Register arg = values[argc - 1 - i]; | 333 Register arg = values[argc - 1 - i]; |
| 334 ASSERT(!receiver.is(arg)); | 334 DCHECK(!receiver.is(arg)); |
| 335 ASSERT(!scratch_in.is(arg)); | 335 DCHECK(!scratch_in.is(arg)); |
| 336 __ push(arg); | 336 __ push(arg); |
| 337 } | 337 } |
| 338 ASSERT(optimization.is_simple_api_call()); | 338 DCHECK(optimization.is_simple_api_call()); |
| 339 | 339 |
| 340 // Abi for CallApiFunctionStub. | 340 // Abi for CallApiFunctionStub. |
| 341 Register callee = r0; | 341 Register callee = r0; |
| 342 Register call_data = r4; | 342 Register call_data = r4; |
| 343 Register holder = r2; | 343 Register holder = r2; |
| 344 Register api_function_address = r1; | 344 Register api_function_address = r1; |
| 345 | 345 |
| 346 // Put holder in place. | 346 // Put holder in place. |
| 347 CallOptimization::HolderLookup holder_lookup; | 347 CallOptimization::HolderLookup holder_lookup; |
| 348 Handle<JSObject> api_holder = | 348 Handle<JSObject> api_holder = |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 Handle<Map> transition, Handle<Name> name, Register receiver_reg, | 419 Handle<Map> transition, Handle<Name> name, Register receiver_reg, |
| 420 Register storage_reg, Register value_reg, Register scratch1, | 420 Register storage_reg, Register value_reg, Register scratch1, |
| 421 Register scratch2, Register scratch3, Label* miss_label, Label* slow) { | 421 Register scratch2, Register scratch3, Label* miss_label, Label* slow) { |
| 422 // r0 : value | 422 // r0 : value |
| 423 Label exit; | 423 Label exit; |
| 424 | 424 |
| 425 int descriptor = transition->LastAdded(); | 425 int descriptor = transition->LastAdded(); |
| 426 DescriptorArray* descriptors = transition->instance_descriptors(); | 426 DescriptorArray* descriptors = transition->instance_descriptors(); |
| 427 PropertyDetails details = descriptors->GetDetails(descriptor); | 427 PropertyDetails details = descriptors->GetDetails(descriptor); |
| 428 Representation representation = details.representation(); | 428 Representation representation = details.representation(); |
| 429 ASSERT(!representation.IsNone()); | 429 DCHECK(!representation.IsNone()); |
| 430 | 430 |
| 431 if (details.type() == CONSTANT) { | 431 if (details.type() == CONSTANT) { |
| 432 Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); | 432 Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); |
| 433 __ Move(scratch1, constant); | 433 __ Move(scratch1, constant); |
| 434 __ cmp(value_reg, scratch1); | 434 __ cmp(value_reg, scratch1); |
| 435 __ b(ne, miss_label); | 435 __ b(ne, miss_label); |
| 436 } else if (representation.IsSmi()) { | 436 } else if (representation.IsSmi()) { |
| 437 __ JumpIfNotSmi(value_reg, miss_label); | 437 __ JumpIfNotSmi(value_reg, miss_label); |
| 438 } else if (representation.IsHeapObject()) { | 438 } else if (representation.IsHeapObject()) { |
| 439 __ JumpIfSmi(value_reg, miss_label); | 439 __ JumpIfSmi(value_reg, miss_label); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 468 __ bind(&heap_number); | 468 __ bind(&heap_number); |
| 469 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, | 469 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, |
| 470 miss_label, DONT_DO_SMI_CHECK); | 470 miss_label, DONT_DO_SMI_CHECK); |
| 471 __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | 471 __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |
| 472 | 472 |
| 473 __ bind(&do_store); | 473 __ bind(&do_store); |
| 474 __ vstr(d0, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); | 474 __ vstr(d0, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); |
| 475 } | 475 } |
| 476 | 476 |
| 477 // Stub never generated for objects that require access checks. | 477 // Stub never generated for objects that require access checks. |
| 478 ASSERT(!transition->is_access_check_needed()); | 478 DCHECK(!transition->is_access_check_needed()); |
| 479 | 479 |
| 480 // Perform map transition for the receiver if necessary. | 480 // Perform map transition for the receiver if necessary. |
| 481 if (details.type() == FIELD && | 481 if (details.type() == FIELD && |
| 482 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { | 482 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { |
| 483 // The properties must be extended before we can store the value. | 483 // The properties must be extended before we can store the value. |
| 484 // We jump to a runtime call that extends the properties array. | 484 // We jump to a runtime call that extends the properties array. |
| 485 __ push(receiver_reg); | 485 __ push(receiver_reg); |
| 486 __ mov(r2, Operand(transition)); | 486 __ mov(r2, Operand(transition)); |
| 487 __ Push(r2, r0); | 487 __ Push(r2, r0); |
| 488 __ TailCallExternalReference( | 488 __ TailCallExternalReference( |
| (...skipping 11 matching lines...) Expand all Loading... |
| 500 __ RecordWriteField(receiver_reg, | 500 __ RecordWriteField(receiver_reg, |
| 501 HeapObject::kMapOffset, | 501 HeapObject::kMapOffset, |
| 502 scratch1, | 502 scratch1, |
| 503 scratch2, | 503 scratch2, |
| 504 kLRHasNotBeenSaved, | 504 kLRHasNotBeenSaved, |
| 505 kDontSaveFPRegs, | 505 kDontSaveFPRegs, |
| 506 OMIT_REMEMBERED_SET, | 506 OMIT_REMEMBERED_SET, |
| 507 OMIT_SMI_CHECK); | 507 OMIT_SMI_CHECK); |
| 508 | 508 |
| 509 if (details.type() == CONSTANT) { | 509 if (details.type() == CONSTANT) { |
| 510 ASSERT(value_reg.is(r0)); | 510 DCHECK(value_reg.is(r0)); |
| 511 __ Ret(); | 511 __ Ret(); |
| 512 return; | 512 return; |
| 513 } | 513 } |
| 514 | 514 |
| 515 int index = transition->instance_descriptors()->GetFieldIndex( | 515 int index = transition->instance_descriptors()->GetFieldIndex( |
| 516 transition->LastAdded()); | 516 transition->LastAdded()); |
| 517 | 517 |
| 518 // Adjust for the number of properties stored in the object. Even in the | 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 | 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. | 520 // object and the number of in-object properties is not going to change. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 storage_reg, | 568 storage_reg, |
| 569 receiver_reg, | 569 receiver_reg, |
| 570 kLRHasNotBeenSaved, | 570 kLRHasNotBeenSaved, |
| 571 kDontSaveFPRegs, | 571 kDontSaveFPRegs, |
| 572 EMIT_REMEMBERED_SET, | 572 EMIT_REMEMBERED_SET, |
| 573 smi_check); | 573 smi_check); |
| 574 } | 574 } |
| 575 } | 575 } |
| 576 | 576 |
| 577 // Return the value (register r0). | 577 // Return the value (register r0). |
| 578 ASSERT(value_reg.is(r0)); | 578 DCHECK(value_reg.is(r0)); |
| 579 __ bind(&exit); | 579 __ bind(&exit); |
| 580 __ Ret(); | 580 __ Ret(); |
| 581 } | 581 } |
| 582 | 582 |
| 583 | 583 |
| 584 // Generate StoreField code, value is passed in r0 register. | 584 // Generate StoreField code, value is passed in r0 register. |
| 585 // When leaving generated code after success, the receiver_reg and name_reg | 585 // When leaving generated code after success, the receiver_reg and name_reg |
| 586 // may be clobbered. Upon branch to miss_label, the receiver and name | 586 // may be clobbered. Upon branch to miss_label, the receiver and name |
| 587 // registers have their original values. | 587 // registers have their original values. |
| 588 void NamedStoreHandlerCompiler::GenerateStoreField( | 588 void NamedStoreHandlerCompiler::GenerateStoreField( |
| 589 Handle<JSObject> object, LookupResult* lookup, Register receiver_reg, | 589 Handle<JSObject> object, LookupResult* lookup, Register receiver_reg, |
| 590 Register name_reg, Register value_reg, Register scratch1, Register scratch2, | 590 Register name_reg, Register value_reg, Register scratch1, Register scratch2, |
| 591 Label* miss_label) { | 591 Label* miss_label) { |
| 592 // r0 : value | 592 // r0 : value |
| 593 Label exit; | 593 Label exit; |
| 594 | 594 |
| 595 // Stub never generated for objects that require access checks. | 595 // Stub never generated for objects that require access checks. |
| 596 ASSERT(!object->IsAccessCheckNeeded()); | 596 DCHECK(!object->IsAccessCheckNeeded()); |
| 597 ASSERT(!object->IsJSGlobalProxy()); | 597 DCHECK(!object->IsJSGlobalProxy()); |
| 598 | 598 |
| 599 FieldIndex index = lookup->GetFieldIndex(); | 599 FieldIndex index = lookup->GetFieldIndex(); |
| 600 | 600 |
| 601 Representation representation = lookup->representation(); | 601 Representation representation = lookup->representation(); |
| 602 ASSERT(!representation.IsNone()); | 602 DCHECK(!representation.IsNone()); |
| 603 if (representation.IsSmi()) { | 603 if (representation.IsSmi()) { |
| 604 __ JumpIfNotSmi(value_reg, miss_label); | 604 __ JumpIfNotSmi(value_reg, miss_label); |
| 605 } else if (representation.IsHeapObject()) { | 605 } else if (representation.IsHeapObject()) { |
| 606 __ JumpIfSmi(value_reg, miss_label); | 606 __ JumpIfSmi(value_reg, miss_label); |
| 607 HeapType* field_type = lookup->GetFieldType(); | 607 HeapType* field_type = lookup->GetFieldType(); |
| 608 HeapType::Iterator<Map> it = field_type->Classes(); | 608 HeapType::Iterator<Map> it = field_type->Classes(); |
| 609 if (!it.Done()) { | 609 if (!it.Done()) { |
| 610 __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); | 610 __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); |
| 611 Label do_store; | 611 Label do_store; |
| 612 while (true) { | 612 while (true) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 639 __ jmp(&do_store); | 639 __ jmp(&do_store); |
| 640 | 640 |
| 641 __ bind(&heap_number); | 641 __ bind(&heap_number); |
| 642 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex, | 642 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex, |
| 643 miss_label, DONT_DO_SMI_CHECK); | 643 miss_label, DONT_DO_SMI_CHECK); |
| 644 __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | 644 __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |
| 645 | 645 |
| 646 __ bind(&do_store); | 646 __ bind(&do_store); |
| 647 __ vstr(d0, FieldMemOperand(scratch1, HeapNumber::kValueOffset)); | 647 __ vstr(d0, FieldMemOperand(scratch1, HeapNumber::kValueOffset)); |
| 648 // Return the value (register r0). | 648 // Return the value (register r0). |
| 649 ASSERT(value_reg.is(r0)); | 649 DCHECK(value_reg.is(r0)); |
| 650 __ Ret(); | 650 __ Ret(); |
| 651 return; | 651 return; |
| 652 } | 652 } |
| 653 | 653 |
| 654 // TODO(verwaest): Share this code as a code stub. | 654 // TODO(verwaest): Share this code as a code stub. |
| 655 SmiCheck smi_check = representation.IsTagged() | 655 SmiCheck smi_check = representation.IsTagged() |
| 656 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; | 656 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; |
| 657 if (index.is_inobject()) { | 657 if (index.is_inobject()) { |
| 658 // Set the property straight into the object. | 658 // Set the property straight into the object. |
| 659 __ str(value_reg, FieldMemOperand(receiver_reg, index.offset())); | 659 __ str(value_reg, FieldMemOperand(receiver_reg, index.offset())); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 name_reg, | 693 name_reg, |
| 694 receiver_reg, | 694 receiver_reg, |
| 695 kLRHasNotBeenSaved, | 695 kLRHasNotBeenSaved, |
| 696 kDontSaveFPRegs, | 696 kDontSaveFPRegs, |
| 697 EMIT_REMEMBERED_SET, | 697 EMIT_REMEMBERED_SET, |
| 698 smi_check); | 698 smi_check); |
| 699 } | 699 } |
| 700 } | 700 } |
| 701 | 701 |
| 702 // Return the value (register r0). | 702 // Return the value (register r0). |
| 703 ASSERT(value_reg.is(r0)); | 703 DCHECK(value_reg.is(r0)); |
| 704 __ bind(&exit); | 704 __ bind(&exit); |
| 705 __ Ret(); | 705 __ Ret(); |
| 706 } | 706 } |
| 707 | 707 |
| 708 | 708 |
| 709 Register PropertyHandlerCompiler::CheckPrototypes( | 709 Register PropertyHandlerCompiler::CheckPrototypes( |
| 710 Register object_reg, Register holder_reg, Register scratch1, | 710 Register object_reg, Register holder_reg, Register scratch1, |
| 711 Register scratch2, Handle<Name> name, Label* miss, | 711 Register scratch2, Handle<Name> name, Label* miss, |
| 712 PrototypeCheckType check) { | 712 PrototypeCheckType check) { |
| 713 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); | 713 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); |
| 714 | 714 |
| 715 // Make sure there's no overlap between holder and object registers. | 715 // Make sure there's no overlap between holder and object registers. |
| 716 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 716 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 717 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 717 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
| 718 && !scratch2.is(scratch1)); | 718 && !scratch2.is(scratch1)); |
| 719 | 719 |
| 720 // Keep track of the current object in register reg. | 720 // Keep track of the current object in register reg. |
| 721 Register reg = object_reg; | 721 Register reg = object_reg; |
| 722 int depth = 0; | 722 int depth = 0; |
| 723 | 723 |
| 724 Handle<JSObject> current = Handle<JSObject>::null(); | 724 Handle<JSObject> current = Handle<JSObject>::null(); |
| 725 if (type()->IsConstant()) { | 725 if (type()->IsConstant()) { |
| 726 current = Handle<JSObject>::cast(type()->AsConstant()->Value()); | 726 current = Handle<JSObject>::cast(type()->AsConstant()->Value()); |
| 727 } | 727 } |
| 728 Handle<JSObject> prototype = Handle<JSObject>::null(); | 728 Handle<JSObject> prototype = Handle<JSObject>::null(); |
| 729 Handle<Map> current_map = receiver_map; | 729 Handle<Map> current_map = receiver_map; |
| 730 Handle<Map> holder_map(holder()->map()); | 730 Handle<Map> holder_map(holder()->map()); |
| 731 // Traverse the prototype chain and check the maps in the prototype chain for | 731 // Traverse the prototype chain and check the maps in the prototype chain for |
| 732 // fast and global objects or do negative lookup for normal objects. | 732 // fast and global objects or do negative lookup for normal objects. |
| 733 while (!current_map.is_identical_to(holder_map)) { | 733 while (!current_map.is_identical_to(holder_map)) { |
| 734 ++depth; | 734 ++depth; |
| 735 | 735 |
| 736 // Only global objects and objects that do not require access | 736 // Only global objects and objects that do not require access |
| 737 // checks are allowed in stubs. | 737 // checks are allowed in stubs. |
| 738 ASSERT(current_map->IsJSGlobalProxyMap() || | 738 DCHECK(current_map->IsJSGlobalProxyMap() || |
| 739 !current_map->is_access_check_needed()); | 739 !current_map->is_access_check_needed()); |
| 740 | 740 |
| 741 prototype = handle(JSObject::cast(current_map->prototype())); | 741 prototype = handle(JSObject::cast(current_map->prototype())); |
| 742 if (current_map->is_dictionary_map() && | 742 if (current_map->is_dictionary_map() && |
| 743 !current_map->IsJSGlobalObjectMap() && | 743 !current_map->IsJSGlobalObjectMap() && |
| 744 !current_map->IsJSGlobalProxyMap()) { | 744 !current_map->IsJSGlobalProxyMap()) { |
| 745 if (!name->IsUniqueName()) { | 745 if (!name->IsUniqueName()) { |
| 746 ASSERT(name->IsString()); | 746 DCHECK(name->IsString()); |
| 747 name = factory()->InternalizeString(Handle<String>::cast(name)); | 747 name = factory()->InternalizeString(Handle<String>::cast(name)); |
| 748 } | 748 } |
| 749 ASSERT(current.is_null() || | 749 DCHECK(current.is_null() || |
| 750 current->property_dictionary()->FindEntry(name) == | 750 current->property_dictionary()->FindEntry(name) == |
| 751 NameDictionary::kNotFound); | 751 NameDictionary::kNotFound); |
| 752 | 752 |
| 753 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, | 753 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, |
| 754 scratch1, scratch2); | 754 scratch1, scratch2); |
| 755 | 755 |
| 756 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | 756 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 757 reg = holder_reg; // From now on the object will be in holder_reg. | 757 reg = holder_reg; // From now on the object will be in holder_reg. |
| 758 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); | 758 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); |
| 759 } else { | 759 } else { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 | 798 |
| 799 // Log the check depth. | 799 // Log the check depth. |
| 800 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 800 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 801 | 801 |
| 802 if (depth != 0 || check == CHECK_ALL_MAPS) { | 802 if (depth != 0 || check == CHECK_ALL_MAPS) { |
| 803 // Check the holder map. | 803 // Check the holder map. |
| 804 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK); | 804 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK); |
| 805 } | 805 } |
| 806 | 806 |
| 807 // Perform security check for access to the global object. | 807 // Perform security check for access to the global object. |
| 808 ASSERT(current_map->IsJSGlobalProxyMap() || | 808 DCHECK(current_map->IsJSGlobalProxyMap() || |
| 809 !current_map->is_access_check_needed()); | 809 !current_map->is_access_check_needed()); |
| 810 if (current_map->IsJSGlobalProxyMap()) { | 810 if (current_map->IsJSGlobalProxyMap()) { |
| 811 __ CheckAccessGlobalProxy(reg, scratch1, miss); | 811 __ CheckAccessGlobalProxy(reg, scratch1, miss); |
| 812 } | 812 } |
| 813 | 813 |
| 814 // Return the register containing the holder. | 814 // Return the register containing the holder. |
| 815 return reg; | 815 return reg; |
| 816 } | 816 } |
| 817 | 817 |
| 818 | 818 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 839 | 839 |
| 840 | 840 |
| 841 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, | 841 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, |
| 842 Handle<Name> name, | 842 Handle<Name> name, |
| 843 Handle<Object> callback) { | 843 Handle<Object> callback) { |
| 844 Label miss; | 844 Label miss; |
| 845 | 845 |
| 846 Register reg = FrontendHeader(object_reg, name, &miss); | 846 Register reg = FrontendHeader(object_reg, name, &miss); |
| 847 | 847 |
| 848 if (!holder()->HasFastProperties()) { | 848 if (!holder()->HasFastProperties()) { |
| 849 ASSERT(!holder()->IsGlobalObject()); | 849 DCHECK(!holder()->IsGlobalObject()); |
| 850 ASSERT(!reg.is(scratch2())); | 850 DCHECK(!reg.is(scratch2())); |
| 851 ASSERT(!reg.is(scratch3())); | 851 DCHECK(!reg.is(scratch3())); |
| 852 ASSERT(!reg.is(scratch4())); | 852 DCHECK(!reg.is(scratch4())); |
| 853 | 853 |
| 854 // Load the properties dictionary. | 854 // Load the properties dictionary. |
| 855 Register dictionary = scratch4(); | 855 Register dictionary = scratch4(); |
| 856 __ ldr(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset)); | 856 __ ldr(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset)); |
| 857 | 857 |
| 858 // Probe the dictionary. | 858 // Probe the dictionary. |
| 859 Label probe_done; | 859 Label probe_done; |
| 860 NameDictionaryLookupStub::GeneratePositiveLookup(masm(), | 860 NameDictionaryLookupStub::GeneratePositiveLookup(masm(), |
| 861 &miss, | 861 &miss, |
| 862 &probe_done, | 862 &probe_done, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 901 Register reg, Handle<ExecutableAccessorInfo> callback) { | 901 Register reg, Handle<ExecutableAccessorInfo> callback) { |
| 902 // Build AccessorInfo::args_ list on the stack and push property name below | 902 // Build AccessorInfo::args_ list on the stack and push property name below |
| 903 // the exit frame to make GC aware of them and store pointers to them. | 903 // the exit frame to make GC aware of them and store pointers to them. |
| 904 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); | 904 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); |
| 905 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); | 905 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); |
| 906 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); | 906 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); |
| 907 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); | 907 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); |
| 908 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); | 908 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); |
| 909 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); | 909 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); |
| 910 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); | 910 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); |
| 911 ASSERT(!scratch2().is(reg)); | 911 DCHECK(!scratch2().is(reg)); |
| 912 ASSERT(!scratch3().is(reg)); | 912 DCHECK(!scratch3().is(reg)); |
| 913 ASSERT(!scratch4().is(reg)); | 913 DCHECK(!scratch4().is(reg)); |
| 914 __ push(receiver()); | 914 __ push(receiver()); |
| 915 if (heap()->InNewSpace(callback->data())) { | 915 if (heap()->InNewSpace(callback->data())) { |
| 916 __ Move(scratch3(), callback); | 916 __ Move(scratch3(), callback); |
| 917 __ ldr(scratch3(), FieldMemOperand(scratch3(), | 917 __ ldr(scratch3(), FieldMemOperand(scratch3(), |
| 918 ExecutableAccessorInfo::kDataOffset)); | 918 ExecutableAccessorInfo::kDataOffset)); |
| 919 } else { | 919 } else { |
| 920 __ Move(scratch3(), Handle<Object>(callback->data(), isolate())); | 920 __ Move(scratch3(), Handle<Object>(callback->data(), isolate())); |
| 921 } | 921 } |
| 922 __ push(scratch3()); | 922 __ push(scratch3()); |
| 923 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); | 923 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 939 __ mov(getter_address_reg, Operand(ref)); | 939 __ mov(getter_address_reg, Operand(ref)); |
| 940 | 940 |
| 941 CallApiGetterStub stub(isolate()); | 941 CallApiGetterStub stub(isolate()); |
| 942 __ TailCallStub(&stub); | 942 __ TailCallStub(&stub); |
| 943 } | 943 } |
| 944 | 944 |
| 945 | 945 |
| 946 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg, | 946 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg, |
| 947 LookupResult* lookup, | 947 LookupResult* lookup, |
| 948 Handle<Name> name) { | 948 Handle<Name> name) { |
| 949 ASSERT(holder()->HasNamedInterceptor()); | 949 DCHECK(holder()->HasNamedInterceptor()); |
| 950 ASSERT(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); | 950 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); |
| 951 | 951 |
| 952 // So far the most popular follow ups for interceptor loads are FIELD | 952 // So far the most popular follow ups for interceptor loads are FIELD |
| 953 // and CALLBACKS, so inline only them, other cases may be added | 953 // and CALLBACKS, so inline only them, other cases may be added |
| 954 // later. | 954 // later. |
| 955 bool compile_followup_inline = false; | 955 bool compile_followup_inline = false; |
| 956 if (lookup->IsFound() && lookup->IsCacheable()) { | 956 if (lookup->IsFound() && lookup->IsCacheable()) { |
| 957 if (lookup->IsField()) { | 957 if (lookup->IsField()) { |
| 958 compile_followup_inline = true; | 958 compile_followup_inline = true; |
| 959 } else if (lookup->type() == CALLBACKS && | 959 } else if (lookup->type() == CALLBACKS && |
| 960 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { | 960 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { |
| 961 Handle<ExecutableAccessorInfo> callback( | 961 Handle<ExecutableAccessorInfo> callback( |
| 962 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); | 962 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); |
| 963 compile_followup_inline = | 963 compile_followup_inline = |
| 964 callback->getter() != NULL && | 964 callback->getter() != NULL && |
| 965 ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback, | 965 ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback, |
| 966 type()); | 966 type()); |
| 967 } | 967 } |
| 968 } | 968 } |
| 969 | 969 |
| 970 if (compile_followup_inline) { | 970 if (compile_followup_inline) { |
| 971 // Compile the interceptor call, followed by inline code to load the | 971 // Compile the interceptor call, followed by inline code to load the |
| 972 // property from further up the prototype chain if the call fails. | 972 // property from further up the prototype chain if the call fails. |
| 973 // Check that the maps haven't changed. | 973 // Check that the maps haven't changed. |
| 974 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); | 974 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
| 975 | 975 |
| 976 // Preserve the receiver register explicitly whenever it is different from | 976 // Preserve the receiver register explicitly whenever it is different from |
| 977 // the holder and it is needed should the interceptor return without any | 977 // the holder and it is needed should the interceptor return without any |
| 978 // result. The CALLBACKS case needs the receiver to be passed into C++ code, | 978 // result. The CALLBACKS case needs the receiver to be passed into C++ code, |
| 979 // the FIELD case might cause a miss during the prototype check. | 979 // the FIELD case might cause a miss during the prototype check. |
| 980 bool must_perfrom_prototype_check = *holder() != lookup->holder(); | 980 bool must_perfrom_prototype_check = *holder() != lookup->holder(); |
| 981 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && | 981 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && |
| 982 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); | 982 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); |
| 983 | 983 |
| 984 // Save necessary data before invoking an interceptor. | 984 // Save necessary data before invoking an interceptor. |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1121 Register name = LoadIC::NameRegister(); | 1121 Register name = LoadIC::NameRegister(); |
| 1122 static Register registers[] = { receiver, name, r3, r0, r4, r5 }; | 1122 static Register registers[] = { receiver, name, r3, r0, r4, r5 }; |
| 1123 return registers; | 1123 return registers; |
| 1124 } | 1124 } |
| 1125 | 1125 |
| 1126 | 1126 |
| 1127 Register* PropertyAccessCompiler::store_calling_convention() { | 1127 Register* PropertyAccessCompiler::store_calling_convention() { |
| 1128 // receiver, name, scratch1, scratch2, scratch3. | 1128 // receiver, name, scratch1, scratch2, scratch3. |
| 1129 Register receiver = StoreIC::ReceiverRegister(); | 1129 Register receiver = StoreIC::ReceiverRegister(); |
| 1130 Register name = StoreIC::NameRegister(); | 1130 Register name = StoreIC::NameRegister(); |
| 1131 ASSERT(r3.is(KeyedStoreIC::MapRegister())); | 1131 DCHECK(r3.is(KeyedStoreIC::MapRegister())); |
| 1132 static Register registers[] = { receiver, name, r3, r4, r5 }; | 1132 static Register registers[] = { receiver, name, r3, r4, r5 }; |
| 1133 return registers; | 1133 return registers; |
| 1134 } | 1134 } |
| 1135 | 1135 |
| 1136 | 1136 |
| 1137 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } | 1137 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } |
| 1138 | 1138 |
| 1139 | 1139 |
| 1140 #undef __ | 1140 #undef __ |
| 1141 #define __ ACCESS_MASM(masm) | 1141 #define __ ACCESS_MASM(masm) |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1227 __ b(ne, &miss); | 1227 __ b(ne, &miss); |
| 1228 } | 1228 } |
| 1229 } | 1229 } |
| 1230 | 1230 |
| 1231 Label number_case; | 1231 Label number_case; |
| 1232 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; | 1232 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; |
| 1233 __ JumpIfSmi(receiver(), smi_target); | 1233 __ JumpIfSmi(receiver(), smi_target); |
| 1234 | 1234 |
| 1235 // Polymorphic keyed stores may use the map register | 1235 // Polymorphic keyed stores may use the map register |
| 1236 Register map_reg = scratch1(); | 1236 Register map_reg = scratch1(); |
| 1237 ASSERT(kind() != Code::KEYED_STORE_IC || | 1237 DCHECK(kind() != Code::KEYED_STORE_IC || |
| 1238 map_reg.is(KeyedStoreIC::MapRegister())); | 1238 map_reg.is(KeyedStoreIC::MapRegister())); |
| 1239 | 1239 |
| 1240 int receiver_count = types->length(); | 1240 int receiver_count = types->length(); |
| 1241 int number_of_handled_maps = 0; | 1241 int number_of_handled_maps = 0; |
| 1242 __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); | 1242 __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); |
| 1243 for (int current = 0; current < receiver_count; ++current) { | 1243 for (int current = 0; current < receiver_count; ++current) { |
| 1244 Handle<HeapType> type = types->at(current); | 1244 Handle<HeapType> type = types->at(current); |
| 1245 Handle<Map> map = IC::TypeToMap(*type, isolate()); | 1245 Handle<Map> map = IC::TypeToMap(*type, isolate()); |
| 1246 if (!map->is_deprecated()) { | 1246 if (!map->is_deprecated()) { |
| 1247 number_of_handled_maps++; | 1247 number_of_handled_maps++; |
| 1248 __ mov(ip, Operand(map)); | 1248 __ mov(ip, Operand(map)); |
| 1249 __ cmp(map_reg, ip); | 1249 __ cmp(map_reg, ip); |
| 1250 if (type->Is(HeapType::Number())) { | 1250 if (type->Is(HeapType::Number())) { |
| 1251 ASSERT(!number_case.is_unused()); | 1251 DCHECK(!number_case.is_unused()); |
| 1252 __ bind(&number_case); | 1252 __ bind(&number_case); |
| 1253 } | 1253 } |
| 1254 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq); | 1254 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq); |
| 1255 } | 1255 } |
| 1256 } | 1256 } |
| 1257 ASSERT(number_of_handled_maps != 0); | 1257 DCHECK(number_of_handled_maps != 0); |
| 1258 | 1258 |
| 1259 __ bind(&miss); | 1259 __ bind(&miss); |
| 1260 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1260 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1261 | 1261 |
| 1262 // Return the generated code. | 1262 // Return the generated code. |
| 1263 InlineCacheState state = | 1263 InlineCacheState state = |
| 1264 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; | 1264 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; |
| 1265 return GetCode(kind(), type, name, state); | 1265 return GetCode(kind(), type, name, state); |
| 1266 } | 1266 } |
| 1267 | 1267 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1300 #define __ ACCESS_MASM(masm) | 1300 #define __ ACCESS_MASM(masm) |
| 1301 | 1301 |
| 1302 | 1302 |
| 1303 void ElementHandlerCompiler::GenerateLoadDictionaryElement( | 1303 void ElementHandlerCompiler::GenerateLoadDictionaryElement( |
| 1304 MacroAssembler* masm) { | 1304 MacroAssembler* masm) { |
| 1305 // The return address is in lr. | 1305 // The return address is in lr. |
| 1306 Label slow, miss; | 1306 Label slow, miss; |
| 1307 | 1307 |
| 1308 Register key = LoadIC::NameRegister(); | 1308 Register key = LoadIC::NameRegister(); |
| 1309 Register receiver = LoadIC::ReceiverRegister(); | 1309 Register receiver = LoadIC::ReceiverRegister(); |
| 1310 ASSERT(receiver.is(r1)); | 1310 DCHECK(receiver.is(r1)); |
| 1311 ASSERT(key.is(r2)); | 1311 DCHECK(key.is(r2)); |
| 1312 | 1312 |
| 1313 __ UntagAndJumpIfNotSmi(r6, key, &miss); | 1313 __ UntagAndJumpIfNotSmi(r6, key, &miss); |
| 1314 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 1314 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 1315 __ LoadFromNumberDictionary(&slow, r4, key, r0, r6, r3, r5); | 1315 __ LoadFromNumberDictionary(&slow, r4, key, r0, r6, r3, r5); |
| 1316 __ Ret(); | 1316 __ Ret(); |
| 1317 | 1317 |
| 1318 __ bind(&slow); | 1318 __ bind(&slow); |
| 1319 __ IncrementCounter( | 1319 __ IncrementCounter( |
| 1320 masm->isolate()->counters()->keyed_load_external_array_slow(), | 1320 masm->isolate()->counters()->keyed_load_external_array_slow(), |
| 1321 1, r2, r3); | 1321 1, r2, r3); |
| 1322 | 1322 |
| 1323 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); | 1323 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); |
| 1324 | 1324 |
| 1325 // Miss case, call the runtime. | 1325 // Miss case, call the runtime. |
| 1326 __ bind(&miss); | 1326 __ bind(&miss); |
| 1327 | 1327 |
| 1328 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1328 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 1329 } | 1329 } |
| 1330 | 1330 |
| 1331 | 1331 |
| 1332 #undef __ | 1332 #undef __ |
| 1333 | 1333 |
| 1334 } } // namespace v8::internal | 1334 } } // namespace v8::internal |
| 1335 | 1335 |
| 1336 #endif // V8_TARGET_ARCH_ARM | 1336 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |