| 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_MIPS | 7 #if V8_TARGET_ARCH_MIPS |
| 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 __ sll(offset_scratch, offset, 1); | 51 __ sll(offset_scratch, offset, 1); |
| 52 __ Addu(offset_scratch, offset_scratch, offset); | 52 __ Addu(offset_scratch, offset_scratch, offset); |
| 53 | 53 |
| 54 // Calculate the base address of the entry. | 54 // Calculate the base address of the entry. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 __ Jump(at); | 90 __ Jump(at); |
| 91 | 91 |
| 92 // Miss: fall through. | 92 // Miss: fall through. |
| 93 __ bind(&miss); | 93 __ bind(&miss); |
| 94 } | 94 } |
| 95 | 95 |
| 96 | 96 |
| 97 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( | 97 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( |
| 98 MacroAssembler* masm, Label* miss_label, Register receiver, | 98 MacroAssembler* masm, Label* miss_label, Register receiver, |
| 99 Handle<Name> name, Register scratch0, Register scratch1) { | 99 Handle<Name> name, Register scratch0, Register scratch1) { |
| 100 ASSERT(name->IsUniqueName()); | 100 DCHECK(name->IsUniqueName()); |
| 101 ASSERT(!receiver.is(scratch0)); | 101 DCHECK(!receiver.is(scratch0)); |
| 102 Counters* counters = masm->isolate()->counters(); | 102 Counters* counters = masm->isolate()->counters(); |
| 103 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); | 103 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); |
| 104 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); | 104 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); |
| 105 | 105 |
| 106 Label done; | 106 Label done; |
| 107 | 107 |
| 108 const int kInterceptorOrAccessCheckNeededMask = | 108 const int kInterceptorOrAccessCheckNeededMask = |
| 109 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); | 109 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
| 110 | 110 |
| 111 // Bail out if the receiver has a named interceptor or requires access checks. | 111 // Bail out if the receiver has a named interceptor or requires access checks. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 Register name, | 150 Register name, |
| 151 Register scratch, | 151 Register scratch, |
| 152 Register extra, | 152 Register extra, |
| 153 Register extra2, | 153 Register extra2, |
| 154 Register extra3) { | 154 Register extra3) { |
| 155 Isolate* isolate = masm->isolate(); | 155 Isolate* isolate = masm->isolate(); |
| 156 Label miss; | 156 Label miss; |
| 157 | 157 |
| 158 // Make sure that code is valid. The multiplying code relies on the | 158 // Make sure that code is valid. The multiplying code relies on the |
| 159 // entry size being 12. | 159 // entry size being 12. |
| 160 ASSERT(sizeof(Entry) == 12); | 160 DCHECK(sizeof(Entry) == 12); |
| 161 | 161 |
| 162 // Make sure the flags does not name a specific type. | 162 // Make sure the flags does not name a specific type. |
| 163 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); | 163 DCHECK(Code::ExtractTypeFromFlags(flags) == 0); |
| 164 | 164 |
| 165 // Make sure that there are no register conflicts. | 165 // Make sure that there are no register conflicts. |
| 166 ASSERT(!scratch.is(receiver)); | 166 DCHECK(!scratch.is(receiver)); |
| 167 ASSERT(!scratch.is(name)); | 167 DCHECK(!scratch.is(name)); |
| 168 ASSERT(!extra.is(receiver)); | 168 DCHECK(!extra.is(receiver)); |
| 169 ASSERT(!extra.is(name)); | 169 DCHECK(!extra.is(name)); |
| 170 ASSERT(!extra.is(scratch)); | 170 DCHECK(!extra.is(scratch)); |
| 171 ASSERT(!extra2.is(receiver)); | 171 DCHECK(!extra2.is(receiver)); |
| 172 ASSERT(!extra2.is(name)); | 172 DCHECK(!extra2.is(name)); |
| 173 ASSERT(!extra2.is(scratch)); | 173 DCHECK(!extra2.is(scratch)); |
| 174 ASSERT(!extra2.is(extra)); | 174 DCHECK(!extra2.is(extra)); |
| 175 | 175 |
| 176 // Check register validity. | 176 // Check register validity. |
| 177 ASSERT(!scratch.is(no_reg)); | 177 DCHECK(!scratch.is(no_reg)); |
| 178 ASSERT(!extra.is(no_reg)); | 178 DCHECK(!extra.is(no_reg)); |
| 179 ASSERT(!extra2.is(no_reg)); | 179 DCHECK(!extra2.is(no_reg)); |
| 180 ASSERT(!extra3.is(no_reg)); | 180 DCHECK(!extra3.is(no_reg)); |
| 181 | 181 |
| 182 Counters* counters = masm->isolate()->counters(); | 182 Counters* counters = masm->isolate()->counters(); |
| 183 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, | 183 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, |
| 184 extra2, extra3); | 184 extra2, extra3); |
| 185 | 185 |
| 186 // Check that the receiver isn't a smi. | 186 // Check that the receiver isn't a smi. |
| 187 __ JumpIfSmi(receiver, &miss); | 187 __ JumpIfSmi(receiver, &miss); |
| 188 | 188 |
| 189 // Get the map of the receiver and compute the hash. | 189 // Get the map of the receiver and compute the hash. |
| 190 __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); | 190 __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); | 265 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); |
| 266 __ Ret(USE_DELAY_SLOT); | 266 __ Ret(USE_DELAY_SLOT); |
| 267 __ mov(v0, scratch1); | 267 __ mov(v0, scratch1); |
| 268 } | 268 } |
| 269 | 269 |
| 270 | 270 |
| 271 void PropertyHandlerCompiler::GenerateCheckPropertyCell( | 271 void PropertyHandlerCompiler::GenerateCheckPropertyCell( |
| 272 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, | 272 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, |
| 273 Register scratch, Label* miss) { | 273 Register scratch, Label* miss) { |
| 274 Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name); | 274 Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name); |
| 275 ASSERT(cell->value()->IsTheHole()); | 275 DCHECK(cell->value()->IsTheHole()); |
| 276 __ li(scratch, Operand(cell)); | 276 __ li(scratch, Operand(cell)); |
| 277 __ lw(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); | 277 __ lw(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); |
| 278 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 278 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 279 __ Branch(miss, ne, scratch, Operand(at)); | 279 __ Branch(miss, ne, scratch, Operand(at)); |
| 280 } | 280 } |
| 281 | 281 |
| 282 | 282 |
| 283 // Generate StoreTransition code, value is passed in a0 register. | 283 // Generate StoreTransition code, value is passed in a0 register. |
| 284 // After executing generated code, the receiver_reg and name_reg | 284 // After executing generated code, the receiver_reg and name_reg |
| 285 // may be clobbered. | 285 // may be clobbered. |
| 286 void NamedStoreHandlerCompiler::GenerateStoreTransition( | 286 void NamedStoreHandlerCompiler::GenerateStoreTransition( |
| 287 MacroAssembler* masm, LookupResult* lookup, Handle<Map> transition, | 287 MacroAssembler* masm, LookupResult* lookup, Handle<Map> transition, |
| 288 Handle<Name> name, Register receiver_reg, Register storage_reg, | 288 Handle<Name> name, Register receiver_reg, Register storage_reg, |
| 289 Register value_reg, Register scratch1, Register scratch2, Register scratch3, | 289 Register value_reg, Register scratch1, Register scratch2, Register scratch3, |
| 290 Label* miss_label, Label* slow) { | 290 Label* miss_label, Label* slow) { |
| 291 // a0 : value. | 291 // a0 : value. |
| 292 Label exit; | 292 Label exit; |
| 293 | 293 |
| 294 int descriptor = transition->LastAdded(); | 294 int descriptor = transition->LastAdded(); |
| 295 DescriptorArray* descriptors = transition->instance_descriptors(); | 295 DescriptorArray* descriptors = transition->instance_descriptors(); |
| 296 PropertyDetails details = descriptors->GetDetails(descriptor); | 296 PropertyDetails details = descriptors->GetDetails(descriptor); |
| 297 Representation representation = details.representation(); | 297 Representation representation = details.representation(); |
| 298 ASSERT(!representation.IsNone()); | 298 DCHECK(!representation.IsNone()); |
| 299 | 299 |
| 300 if (details.type() == CONSTANT) { | 300 if (details.type() == CONSTANT) { |
| 301 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate()); | 301 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate()); |
| 302 __ li(scratch1, constant); | 302 __ li(scratch1, constant); |
| 303 __ Branch(miss_label, ne, value_reg, Operand(scratch1)); | 303 __ Branch(miss_label, ne, value_reg, Operand(scratch1)); |
| 304 } else if (representation.IsSmi()) { | 304 } else if (representation.IsSmi()) { |
| 305 __ JumpIfNotSmi(value_reg, miss_label); | 305 __ JumpIfNotSmi(value_reg, miss_label); |
| 306 } else if (representation.IsHeapObject()) { | 306 } else if (representation.IsHeapObject()) { |
| 307 __ JumpIfSmi(value_reg, miss_label); | 307 __ JumpIfSmi(value_reg, miss_label); |
| 308 HeapType* field_type = descriptors->GetFieldType(descriptor); | 308 HeapType* field_type = descriptors->GetFieldType(descriptor); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 338 __ bind(&heap_number); | 338 __ bind(&heap_number); |
| 339 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, | 339 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, |
| 340 miss_label, DONT_DO_SMI_CHECK); | 340 miss_label, DONT_DO_SMI_CHECK); |
| 341 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | 341 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |
| 342 | 342 |
| 343 __ bind(&do_store); | 343 __ bind(&do_store); |
| 344 __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); | 344 __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); |
| 345 } | 345 } |
| 346 | 346 |
| 347 // Stub never generated for objects that require access checks. | 347 // Stub never generated for objects that require access checks. |
| 348 ASSERT(!transition->is_access_check_needed()); | 348 DCHECK(!transition->is_access_check_needed()); |
| 349 | 349 |
| 350 // Perform map transition for the receiver if necessary. | 350 // Perform map transition for the receiver if necessary. |
| 351 if (details.type() == FIELD && | 351 if (details.type() == FIELD && |
| 352 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { | 352 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { |
| 353 // The properties must be extended before we can store the value. | 353 // The properties must be extended before we can store the value. |
| 354 // We jump to a runtime call that extends the properties array. | 354 // We jump to a runtime call that extends the properties array. |
| 355 __ push(receiver_reg); | 355 __ push(receiver_reg); |
| 356 __ li(a2, Operand(transition)); | 356 __ li(a2, Operand(transition)); |
| 357 __ Push(a2, a0); | 357 __ Push(a2, a0); |
| 358 __ TailCallExternalReference( | 358 __ TailCallExternalReference( |
| (...skipping 11 matching lines...) Expand all Loading... |
| 370 __ RecordWriteField(receiver_reg, | 370 __ RecordWriteField(receiver_reg, |
| 371 HeapObject::kMapOffset, | 371 HeapObject::kMapOffset, |
| 372 scratch1, | 372 scratch1, |
| 373 scratch2, | 373 scratch2, |
| 374 kRAHasNotBeenSaved, | 374 kRAHasNotBeenSaved, |
| 375 kDontSaveFPRegs, | 375 kDontSaveFPRegs, |
| 376 OMIT_REMEMBERED_SET, | 376 OMIT_REMEMBERED_SET, |
| 377 OMIT_SMI_CHECK); | 377 OMIT_SMI_CHECK); |
| 378 | 378 |
| 379 if (details.type() == CONSTANT) { | 379 if (details.type() == CONSTANT) { |
| 380 ASSERT(value_reg.is(a0)); | 380 DCHECK(value_reg.is(a0)); |
| 381 __ Ret(USE_DELAY_SLOT); | 381 __ Ret(USE_DELAY_SLOT); |
| 382 __ mov(v0, a0); | 382 __ mov(v0, a0); |
| 383 return; | 383 return; |
| 384 } | 384 } |
| 385 | 385 |
| 386 int index = transition->instance_descriptors()->GetFieldIndex( | 386 int index = transition->instance_descriptors()->GetFieldIndex( |
| 387 transition->LastAdded()); | 387 transition->LastAdded()); |
| 388 | 388 |
| 389 // Adjust for the number of properties stored in the object. Even in the | 389 // Adjust for the number of properties stored in the object. Even in the |
| 390 // face of a transition we can use the old map here because the size of the | 390 // face of a transition we can use the old map here because the size of the |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 storage_reg, | 439 storage_reg, |
| 440 receiver_reg, | 440 receiver_reg, |
| 441 kRAHasNotBeenSaved, | 441 kRAHasNotBeenSaved, |
| 442 kDontSaveFPRegs, | 442 kDontSaveFPRegs, |
| 443 EMIT_REMEMBERED_SET, | 443 EMIT_REMEMBERED_SET, |
| 444 smi_check); | 444 smi_check); |
| 445 } | 445 } |
| 446 } | 446 } |
| 447 | 447 |
| 448 // Return the value (register v0). | 448 // Return the value (register v0). |
| 449 ASSERT(value_reg.is(a0)); | 449 DCHECK(value_reg.is(a0)); |
| 450 __ bind(&exit); | 450 __ bind(&exit); |
| 451 __ Ret(USE_DELAY_SLOT); | 451 __ Ret(USE_DELAY_SLOT); |
| 452 __ mov(v0, a0); | 452 __ mov(v0, a0); |
| 453 } | 453 } |
| 454 | 454 |
| 455 | 455 |
| 456 // Generate StoreField code, value is passed in a0 register. | 456 // Generate StoreField code, value is passed in a0 register. |
| 457 // When leaving generated code after success, the receiver_reg and name_reg | 457 // When leaving generated code after success, the receiver_reg and name_reg |
| 458 // may be clobbered. Upon branch to miss_label, the receiver and name | 458 // may be clobbered. Upon branch to miss_label, the receiver and name |
| 459 // registers have their original values. | 459 // registers have their original values. |
| 460 void NamedStoreHandlerCompiler::GenerateStoreField( | 460 void NamedStoreHandlerCompiler::GenerateStoreField( |
| 461 MacroAssembler* masm, Handle<JSObject> object, LookupResult* lookup, | 461 MacroAssembler* masm, Handle<JSObject> object, LookupResult* lookup, |
| 462 Register receiver_reg, Register name_reg, Register value_reg, | 462 Register receiver_reg, Register name_reg, Register value_reg, |
| 463 Register scratch1, Register scratch2, Label* miss_label) { | 463 Register scratch1, Register scratch2, Label* miss_label) { |
| 464 // a0 : value | 464 // a0 : value |
| 465 Label exit; | 465 Label exit; |
| 466 | 466 |
| 467 // Stub never generated for non-global objects that require access | 467 // Stub never generated for non-global objects that require access |
| 468 // checks. | 468 // checks. |
| 469 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 469 DCHECK(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 470 | 470 |
| 471 FieldIndex index = lookup->GetFieldIndex(); | 471 FieldIndex index = lookup->GetFieldIndex(); |
| 472 | 472 |
| 473 Representation representation = lookup->representation(); | 473 Representation representation = lookup->representation(); |
| 474 ASSERT(!representation.IsNone()); | 474 DCHECK(!representation.IsNone()); |
| 475 if (representation.IsSmi()) { | 475 if (representation.IsSmi()) { |
| 476 __ JumpIfNotSmi(value_reg, miss_label); | 476 __ JumpIfNotSmi(value_reg, miss_label); |
| 477 } else if (representation.IsHeapObject()) { | 477 } else if (representation.IsHeapObject()) { |
| 478 __ JumpIfSmi(value_reg, miss_label); | 478 __ JumpIfSmi(value_reg, miss_label); |
| 479 HeapType* field_type = lookup->GetFieldType(); | 479 HeapType* field_type = lookup->GetFieldType(); |
| 480 HeapType::Iterator<Map> it = field_type->Classes(); | 480 HeapType::Iterator<Map> it = field_type->Classes(); |
| 481 if (!it.Done()) { | 481 if (!it.Done()) { |
| 482 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); | 482 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); |
| 483 Label do_store; | 483 Label do_store; |
| 484 Handle<Map> current; | 484 Handle<Map> current; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 513 __ jmp(&do_store); | 513 __ jmp(&do_store); |
| 514 | 514 |
| 515 __ bind(&heap_number); | 515 __ bind(&heap_number); |
| 516 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex, | 516 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex, |
| 517 miss_label, DONT_DO_SMI_CHECK); | 517 miss_label, DONT_DO_SMI_CHECK); |
| 518 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | 518 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |
| 519 | 519 |
| 520 __ bind(&do_store); | 520 __ bind(&do_store); |
| 521 __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset)); | 521 __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset)); |
| 522 // Return the value (register v0). | 522 // Return the value (register v0). |
| 523 ASSERT(value_reg.is(a0)); | 523 DCHECK(value_reg.is(a0)); |
| 524 __ Ret(USE_DELAY_SLOT); | 524 __ Ret(USE_DELAY_SLOT); |
| 525 __ mov(v0, a0); | 525 __ mov(v0, a0); |
| 526 return; | 526 return; |
| 527 } | 527 } |
| 528 | 528 |
| 529 // TODO(verwaest): Share this code as a code stub. | 529 // TODO(verwaest): Share this code as a code stub. |
| 530 SmiCheck smi_check = representation.IsTagged() | 530 SmiCheck smi_check = representation.IsTagged() |
| 531 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; | 531 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; |
| 532 if (index.is_inobject()) { | 532 if (index.is_inobject()) { |
| 533 // Set the property straight into the object. | 533 // Set the property straight into the object. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 name_reg, | 568 name_reg, |
| 569 receiver_reg, | 569 receiver_reg, |
| 570 kRAHasNotBeenSaved, | 570 kRAHasNotBeenSaved, |
| 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 v0). | 577 // Return the value (register v0). |
| 578 ASSERT(value_reg.is(a0)); | 578 DCHECK(value_reg.is(a0)); |
| 579 __ bind(&exit); | 579 __ bind(&exit); |
| 580 __ Ret(USE_DELAY_SLOT); | 580 __ Ret(USE_DELAY_SLOT); |
| 581 __ mov(v0, a0); | 581 __ mov(v0, a0); |
| 582 } | 582 } |
| 583 | 583 |
| 584 | 584 |
| 585 void NamedStoreHandlerCompiler::GenerateRestoreName(MacroAssembler* masm, | 585 void NamedStoreHandlerCompiler::GenerateRestoreName(MacroAssembler* masm, |
| 586 Label* label, | 586 Label* label, |
| 587 Handle<Name> name) { | 587 Handle<Name> name) { |
| 588 if (!label->is_unused()) { | 588 if (!label->is_unused()) { |
| 589 __ bind(label); | 589 __ bind(label); |
| 590 __ li(this->name(), Operand(name)); | 590 __ li(this->name(), Operand(name)); |
| 591 } | 591 } |
| 592 } | 592 } |
| 593 | 593 |
| 594 | 594 |
| 595 static void PushInterceptorArguments(MacroAssembler* masm, | 595 static void PushInterceptorArguments(MacroAssembler* masm, |
| 596 Register receiver, | 596 Register receiver, |
| 597 Register holder, | 597 Register holder, |
| 598 Register name, | 598 Register name, |
| 599 Handle<JSObject> holder_obj) { | 599 Handle<JSObject> holder_obj) { |
| 600 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); | 600 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); |
| 601 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); | 601 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); |
| 602 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); | 602 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); |
| 603 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); | 603 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); |
| 604 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); | 604 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); |
| 605 __ push(name); | 605 __ push(name); |
| 606 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); | 606 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); |
| 607 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor)); | 607 DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); |
| 608 Register scratch = name; | 608 Register scratch = name; |
| 609 __ li(scratch, Operand(interceptor)); | 609 __ li(scratch, Operand(interceptor)); |
| 610 __ Push(scratch, receiver, holder); | 610 __ Push(scratch, receiver, holder); |
| 611 } | 611 } |
| 612 | 612 |
| 613 | 613 |
| 614 static void CompileCallLoadPropertyWithInterceptor( | 614 static void CompileCallLoadPropertyWithInterceptor( |
| 615 MacroAssembler* masm, | 615 MacroAssembler* masm, |
| 616 Register receiver, | 616 Register receiver, |
| 617 Register holder, | 617 Register holder, |
| 618 Register name, | 618 Register name, |
| 619 Handle<JSObject> holder_obj, | 619 Handle<JSObject> holder_obj, |
| 620 IC::UtilityId id) { | 620 IC::UtilityId id) { |
| 621 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); | 621 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |
| 622 __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), | 622 __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), |
| 623 NamedLoadHandlerCompiler::kInterceptorArgsLength); | 623 NamedLoadHandlerCompiler::kInterceptorArgsLength); |
| 624 } | 624 } |
| 625 | 625 |
| 626 | 626 |
| 627 // Generate call to api function. | 627 // Generate call to api function. |
| 628 void PropertyHandlerCompiler::GenerateFastApiCall( | 628 void PropertyHandlerCompiler::GenerateFastApiCall( |
| 629 MacroAssembler* masm, const CallOptimization& optimization, | 629 MacroAssembler* masm, const CallOptimization& optimization, |
| 630 Handle<Map> receiver_map, Register receiver, Register scratch_in, | 630 Handle<Map> receiver_map, Register receiver, Register scratch_in, |
| 631 bool is_store, int argc, Register* values) { | 631 bool is_store, int argc, Register* values) { |
| 632 ASSERT(!receiver.is(scratch_in)); | 632 DCHECK(!receiver.is(scratch_in)); |
| 633 // Preparing to push, adjust sp. | 633 // Preparing to push, adjust sp. |
| 634 __ Subu(sp, sp, Operand((argc + 1) * kPointerSize)); | 634 __ Subu(sp, sp, Operand((argc + 1) * kPointerSize)); |
| 635 __ sw(receiver, MemOperand(sp, argc * kPointerSize)); // Push receiver. | 635 __ sw(receiver, MemOperand(sp, argc * kPointerSize)); // Push receiver. |
| 636 // Write the arguments to stack frame. | 636 // Write the arguments to stack frame. |
| 637 for (int i = 0; i < argc; i++) { | 637 for (int i = 0; i < argc; i++) { |
| 638 Register arg = values[argc-1-i]; | 638 Register arg = values[argc-1-i]; |
| 639 ASSERT(!receiver.is(arg)); | 639 DCHECK(!receiver.is(arg)); |
| 640 ASSERT(!scratch_in.is(arg)); | 640 DCHECK(!scratch_in.is(arg)); |
| 641 __ sw(arg, MemOperand(sp, (argc-1-i) * kPointerSize)); // Push arg. | 641 __ sw(arg, MemOperand(sp, (argc-1-i) * kPointerSize)); // Push arg. |
| 642 } | 642 } |
| 643 ASSERT(optimization.is_simple_api_call()); | 643 DCHECK(optimization.is_simple_api_call()); |
| 644 | 644 |
| 645 // Abi for CallApiFunctionStub. | 645 // Abi for CallApiFunctionStub. |
| 646 Register callee = a0; | 646 Register callee = a0; |
| 647 Register call_data = t0; | 647 Register call_data = t0; |
| 648 Register holder = a2; | 648 Register holder = a2; |
| 649 Register api_function_address = a1; | 649 Register api_function_address = a1; |
| 650 | 650 |
| 651 // Put holder in place. | 651 // Put holder in place. |
| 652 CallOptimization::HolderLookup holder_lookup; | 652 CallOptimization::HolderLookup holder_lookup; |
| 653 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( | 653 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 #define __ ACCESS_MASM(masm()) | 710 #define __ ACCESS_MASM(masm()) |
| 711 | 711 |
| 712 | 712 |
| 713 Register PropertyHandlerCompiler::CheckPrototypes( | 713 Register PropertyHandlerCompiler::CheckPrototypes( |
| 714 Register object_reg, Register holder_reg, Register scratch1, | 714 Register object_reg, Register holder_reg, Register scratch1, |
| 715 Register scratch2, Handle<Name> name, Label* miss, | 715 Register scratch2, Handle<Name> name, Label* miss, |
| 716 PrototypeCheckType check) { | 716 PrototypeCheckType check) { |
| 717 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); | 717 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); |
| 718 | 718 |
| 719 // Make sure there's no overlap between holder and object registers. | 719 // Make sure there's no overlap between holder and object registers. |
| 720 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 720 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 721 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 721 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
| 722 && !scratch2.is(scratch1)); | 722 && !scratch2.is(scratch1)); |
| 723 | 723 |
| 724 // Keep track of the current object in register reg. | 724 // Keep track of the current object in register reg. |
| 725 Register reg = object_reg; | 725 Register reg = object_reg; |
| 726 int depth = 0; | 726 int depth = 0; |
| 727 | 727 |
| 728 Handle<JSObject> current = Handle<JSObject>::null(); | 728 Handle<JSObject> current = Handle<JSObject>::null(); |
| 729 if (type()->IsConstant()) { | 729 if (type()->IsConstant()) { |
| 730 current = Handle<JSObject>::cast(type()->AsConstant()->Value()); | 730 current = Handle<JSObject>::cast(type()->AsConstant()->Value()); |
| 731 } | 731 } |
| 732 Handle<JSObject> prototype = Handle<JSObject>::null(); | 732 Handle<JSObject> prototype = Handle<JSObject>::null(); |
| 733 Handle<Map> current_map = receiver_map; | 733 Handle<Map> current_map = receiver_map; |
| 734 Handle<Map> holder_map(holder()->map()); | 734 Handle<Map> holder_map(holder()->map()); |
| 735 // Traverse the prototype chain and check the maps in the prototype chain for | 735 // Traverse the prototype chain and check the maps in the prototype chain for |
| 736 // fast and global objects or do negative lookup for normal objects. | 736 // fast and global objects or do negative lookup for normal objects. |
| 737 while (!current_map.is_identical_to(holder_map)) { | 737 while (!current_map.is_identical_to(holder_map)) { |
| 738 ++depth; | 738 ++depth; |
| 739 | 739 |
| 740 // Only global objects and objects that do not require access | 740 // Only global objects and objects that do not require access |
| 741 // checks are allowed in stubs. | 741 // checks are allowed in stubs. |
| 742 ASSERT(current_map->IsJSGlobalProxyMap() || | 742 DCHECK(current_map->IsJSGlobalProxyMap() || |
| 743 !current_map->is_access_check_needed()); | 743 !current_map->is_access_check_needed()); |
| 744 | 744 |
| 745 prototype = handle(JSObject::cast(current_map->prototype())); | 745 prototype = handle(JSObject::cast(current_map->prototype())); |
| 746 if (current_map->is_dictionary_map() && | 746 if (current_map->is_dictionary_map() && |
| 747 !current_map->IsJSGlobalObjectMap() && | 747 !current_map->IsJSGlobalObjectMap() && |
| 748 !current_map->IsJSGlobalProxyMap()) { | 748 !current_map->IsJSGlobalProxyMap()) { |
| 749 if (!name->IsUniqueName()) { | 749 if (!name->IsUniqueName()) { |
| 750 ASSERT(name->IsString()); | 750 DCHECK(name->IsString()); |
| 751 name = factory()->InternalizeString(Handle<String>::cast(name)); | 751 name = factory()->InternalizeString(Handle<String>::cast(name)); |
| 752 } | 752 } |
| 753 ASSERT(current.is_null() || | 753 DCHECK(current.is_null() || |
| 754 current->property_dictionary()->FindEntry(name) == | 754 current->property_dictionary()->FindEntry(name) == |
| 755 NameDictionary::kNotFound); | 755 NameDictionary::kNotFound); |
| 756 | 756 |
| 757 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, | 757 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, |
| 758 scratch1, scratch2); | 758 scratch1, scratch2); |
| 759 | 759 |
| 760 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | 760 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 761 reg = holder_reg; // From now on the object will be in holder_reg. | 761 reg = holder_reg; // From now on the object will be in holder_reg. |
| 762 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); | 762 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); |
| 763 } else { | 763 } else { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 802 | 802 |
| 803 // Log the check depth. | 803 // Log the check depth. |
| 804 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 804 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 805 | 805 |
| 806 if (depth != 0 || check == CHECK_ALL_MAPS) { | 806 if (depth != 0 || check == CHECK_ALL_MAPS) { |
| 807 // Check the holder map. | 807 // Check the holder map. |
| 808 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK); | 808 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK); |
| 809 } | 809 } |
| 810 | 810 |
| 811 // Perform security check for access to the global object. | 811 // Perform security check for access to the global object. |
| 812 ASSERT(current_map->IsJSGlobalProxyMap() || | 812 DCHECK(current_map->IsJSGlobalProxyMap() || |
| 813 !current_map->is_access_check_needed()); | 813 !current_map->is_access_check_needed()); |
| 814 if (current_map->IsJSGlobalProxyMap()) { | 814 if (current_map->IsJSGlobalProxyMap()) { |
| 815 __ CheckAccessGlobalProxy(reg, scratch1, miss); | 815 __ CheckAccessGlobalProxy(reg, scratch1, miss); |
| 816 } | 816 } |
| 817 | 817 |
| 818 // Return the register containing the holder. | 818 // Return the register containing the holder. |
| 819 return reg; | 819 return reg; |
| 820 } | 820 } |
| 821 | 821 |
| 822 | 822 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 843 | 843 |
| 844 | 844 |
| 845 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, | 845 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, |
| 846 Handle<Name> name, | 846 Handle<Name> name, |
| 847 Handle<Object> callback) { | 847 Handle<Object> callback) { |
| 848 Label miss; | 848 Label miss; |
| 849 | 849 |
| 850 Register reg = FrontendHeader(object_reg, name, &miss); | 850 Register reg = FrontendHeader(object_reg, name, &miss); |
| 851 | 851 |
| 852 if (!holder()->HasFastProperties()) { | 852 if (!holder()->HasFastProperties()) { |
| 853 ASSERT(!holder()->IsGlobalObject()); | 853 DCHECK(!holder()->IsGlobalObject()); |
| 854 ASSERT(!reg.is(scratch2())); | 854 DCHECK(!reg.is(scratch2())); |
| 855 ASSERT(!reg.is(scratch3())); | 855 DCHECK(!reg.is(scratch3())); |
| 856 ASSERT(!reg.is(scratch4())); | 856 DCHECK(!reg.is(scratch4())); |
| 857 | 857 |
| 858 // Load the properties dictionary. | 858 // Load the properties dictionary. |
| 859 Register dictionary = scratch4(); | 859 Register dictionary = scratch4(); |
| 860 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset)); | 860 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset)); |
| 861 | 861 |
| 862 // Probe the dictionary. | 862 // Probe the dictionary. |
| 863 Label probe_done; | 863 Label probe_done; |
| 864 NameDictionaryLookupStub::GeneratePositiveLookup(masm(), | 864 NameDictionaryLookupStub::GeneratePositiveLookup(masm(), |
| 865 &miss, | 865 &miss, |
| 866 &probe_done, | 866 &probe_done, |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 904 Register reg, Handle<ExecutableAccessorInfo> callback) { | 904 Register reg, Handle<ExecutableAccessorInfo> callback) { |
| 905 // Build AccessorInfo::args_ list on the stack and push property name below | 905 // Build AccessorInfo::args_ list on the stack and push property name below |
| 906 // the exit frame to make GC aware of them and store pointers to them. | 906 // the exit frame to make GC aware of them and store pointers to them. |
| 907 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); | 907 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); |
| 908 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); | 908 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); |
| 909 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); | 909 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); |
| 910 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); | 910 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); |
| 911 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); | 911 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); |
| 912 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); | 912 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); |
| 913 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); | 913 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); |
| 914 ASSERT(!scratch2().is(reg)); | 914 DCHECK(!scratch2().is(reg)); |
| 915 ASSERT(!scratch3().is(reg)); | 915 DCHECK(!scratch3().is(reg)); |
| 916 ASSERT(!scratch4().is(reg)); | 916 DCHECK(!scratch4().is(reg)); |
| 917 __ push(receiver()); | 917 __ push(receiver()); |
| 918 if (heap()->InNewSpace(callback->data())) { | 918 if (heap()->InNewSpace(callback->data())) { |
| 919 __ li(scratch3(), callback); | 919 __ li(scratch3(), callback); |
| 920 __ lw(scratch3(), FieldMemOperand(scratch3(), | 920 __ lw(scratch3(), FieldMemOperand(scratch3(), |
| 921 ExecutableAccessorInfo::kDataOffset)); | 921 ExecutableAccessorInfo::kDataOffset)); |
| 922 } else { | 922 } else { |
| 923 __ li(scratch3(), Handle<Object>(callback->data(), isolate())); | 923 __ li(scratch3(), Handle<Object>(callback->data(), isolate())); |
| 924 } | 924 } |
| 925 __ Subu(sp, sp, 6 * kPointerSize); | 925 __ Subu(sp, sp, 6 * kPointerSize); |
| 926 __ sw(scratch3(), MemOperand(sp, 5 * kPointerSize)); | 926 __ sw(scratch3(), MemOperand(sp, 5 * kPointerSize)); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 945 __ li(getter_address_reg, Operand(ref)); | 945 __ li(getter_address_reg, Operand(ref)); |
| 946 | 946 |
| 947 CallApiGetterStub stub(isolate()); | 947 CallApiGetterStub stub(isolate()); |
| 948 __ TailCallStub(&stub); | 948 __ TailCallStub(&stub); |
| 949 } | 949 } |
| 950 | 950 |
| 951 | 951 |
| 952 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg, | 952 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg, |
| 953 LookupResult* lookup, | 953 LookupResult* lookup, |
| 954 Handle<Name> name) { | 954 Handle<Name> name) { |
| 955 ASSERT(holder()->HasNamedInterceptor()); | 955 DCHECK(holder()->HasNamedInterceptor()); |
| 956 ASSERT(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); | 956 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); |
| 957 | 957 |
| 958 // So far the most popular follow ups for interceptor loads are FIELD | 958 // So far the most popular follow ups for interceptor loads are FIELD |
| 959 // and CALLBACKS, so inline only them, other cases may be added | 959 // and CALLBACKS, so inline only them, other cases may be added |
| 960 // later. | 960 // later. |
| 961 bool compile_followup_inline = false; | 961 bool compile_followup_inline = false; |
| 962 if (lookup->IsFound() && lookup->IsCacheable()) { | 962 if (lookup->IsFound() && lookup->IsCacheable()) { |
| 963 if (lookup->IsField()) { | 963 if (lookup->IsField()) { |
| 964 compile_followup_inline = true; | 964 compile_followup_inline = true; |
| 965 } else if (lookup->type() == CALLBACKS && | 965 } else if (lookup->type() == CALLBACKS && |
| 966 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { | 966 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { |
| 967 Handle<ExecutableAccessorInfo> callback( | 967 Handle<ExecutableAccessorInfo> callback( |
| 968 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); | 968 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); |
| 969 compile_followup_inline = | 969 compile_followup_inline = |
| 970 callback->getter() != NULL && | 970 callback->getter() != NULL && |
| 971 ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback, | 971 ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback, |
| 972 type()); | 972 type()); |
| 973 } | 973 } |
| 974 } | 974 } |
| 975 | 975 |
| 976 if (compile_followup_inline) { | 976 if (compile_followup_inline) { |
| 977 // Compile the interceptor call, followed by inline code to load the | 977 // Compile the interceptor call, followed by inline code to load the |
| 978 // property from further up the prototype chain if the call fails. | 978 // property from further up the prototype chain if the call fails. |
| 979 // Check that the maps haven't changed. | 979 // Check that the maps haven't changed. |
| 980 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); | 980 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
| 981 | 981 |
| 982 // Preserve the receiver register explicitly whenever it is different from | 982 // Preserve the receiver register explicitly whenever it is different from |
| 983 // the holder and it is needed should the interceptor return without any | 983 // the holder and it is needed should the interceptor return without any |
| 984 // result. The CALLBACKS case needs the receiver to be passed into C++ code, | 984 // result. The CALLBACKS case needs the receiver to be passed into C++ code, |
| 985 // the FIELD case might cause a miss during the prototype check. | 985 // the FIELD case might cause a miss during the prototype check. |
| 986 bool must_perfrom_prototype_check = *holder() != lookup->holder(); | 986 bool must_perfrom_prototype_check = *holder() != lookup->holder(); |
| 987 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && | 987 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && |
| 988 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); | 988 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); |
| 989 | 989 |
| 990 // Save necessary data before invoking an interceptor. | 990 // Save necessary data before invoking an interceptor. |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1123 Register name = LoadIC::NameRegister(); | 1123 Register name = LoadIC::NameRegister(); |
| 1124 static Register registers[] = { receiver, name, a3, a0, t0, t1 }; | 1124 static Register registers[] = { receiver, name, a3, a0, t0, t1 }; |
| 1125 return registers; | 1125 return registers; |
| 1126 } | 1126 } |
| 1127 | 1127 |
| 1128 | 1128 |
| 1129 Register* PropertyAccessCompiler::store_calling_convention() { | 1129 Register* PropertyAccessCompiler::store_calling_convention() { |
| 1130 // receiver, name, scratch1, scratch2, scratch3. | 1130 // receiver, name, scratch1, scratch2, scratch3. |
| 1131 Register receiver = StoreIC::ReceiverRegister(); | 1131 Register receiver = StoreIC::ReceiverRegister(); |
| 1132 Register name = StoreIC::NameRegister(); | 1132 Register name = StoreIC::NameRegister(); |
| 1133 ASSERT(a3.is(KeyedStoreIC::MapRegister())); | 1133 DCHECK(a3.is(KeyedStoreIC::MapRegister())); |
| 1134 static Register registers[] = { receiver, name, a3, t0, t1 }; | 1134 static Register registers[] = { receiver, name, a3, t0, t1 }; |
| 1135 return registers; | 1135 return registers; |
| 1136 } | 1136 } |
| 1137 | 1137 |
| 1138 | 1138 |
| 1139 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } | 1139 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } |
| 1140 | 1140 |
| 1141 | 1141 |
| 1142 #undef __ | 1142 #undef __ |
| 1143 #define __ ACCESS_MASM(masm) | 1143 #define __ ACCESS_MASM(masm) |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1230 } | 1230 } |
| 1231 } | 1231 } |
| 1232 | 1232 |
| 1233 Label number_case; | 1233 Label number_case; |
| 1234 Register match = scratch2(); | 1234 Register match = scratch2(); |
| 1235 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; | 1235 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; |
| 1236 __ JumpIfSmi(receiver(), smi_target, match); // Reg match is 0 if Smi. | 1236 __ JumpIfSmi(receiver(), smi_target, match); // Reg match is 0 if Smi. |
| 1237 | 1237 |
| 1238 // Polymorphic keyed stores may use the map register | 1238 // Polymorphic keyed stores may use the map register |
| 1239 Register map_reg = scratch1(); | 1239 Register map_reg = scratch1(); |
| 1240 ASSERT(kind() != Code::KEYED_STORE_IC || | 1240 DCHECK(kind() != Code::KEYED_STORE_IC || |
| 1241 map_reg.is(KeyedStoreIC::MapRegister())); | 1241 map_reg.is(KeyedStoreIC::MapRegister())); |
| 1242 | 1242 |
| 1243 int receiver_count = types->length(); | 1243 int receiver_count = types->length(); |
| 1244 int number_of_handled_maps = 0; | 1244 int number_of_handled_maps = 0; |
| 1245 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); | 1245 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); |
| 1246 for (int current = 0; current < receiver_count; ++current) { | 1246 for (int current = 0; current < receiver_count; ++current) { |
| 1247 Handle<HeapType> type = types->at(current); | 1247 Handle<HeapType> type = types->at(current); |
| 1248 Handle<Map> map = IC::TypeToMap(*type, isolate()); | 1248 Handle<Map> map = IC::TypeToMap(*type, isolate()); |
| 1249 if (!map->is_deprecated()) { | 1249 if (!map->is_deprecated()) { |
| 1250 number_of_handled_maps++; | 1250 number_of_handled_maps++; |
| 1251 // Check map and tail call if there's a match. | 1251 // Check map and tail call if there's a match. |
| 1252 // Separate compare from branch, to provide path for above JumpIfSmi(). | 1252 // Separate compare from branch, to provide path for above JumpIfSmi(). |
| 1253 __ Subu(match, map_reg, Operand(map)); | 1253 __ Subu(match, map_reg, Operand(map)); |
| 1254 if (type->Is(HeapType::Number())) { | 1254 if (type->Is(HeapType::Number())) { |
| 1255 ASSERT(!number_case.is_unused()); | 1255 DCHECK(!number_case.is_unused()); |
| 1256 __ bind(&number_case); | 1256 __ bind(&number_case); |
| 1257 } | 1257 } |
| 1258 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, | 1258 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, |
| 1259 eq, match, Operand(zero_reg)); | 1259 eq, match, Operand(zero_reg)); |
| 1260 } | 1260 } |
| 1261 } | 1261 } |
| 1262 ASSERT(number_of_handled_maps != 0); | 1262 DCHECK(number_of_handled_maps != 0); |
| 1263 | 1263 |
| 1264 __ bind(&miss); | 1264 __ bind(&miss); |
| 1265 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1265 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1266 | 1266 |
| 1267 // Return the generated code. | 1267 // Return the generated code. |
| 1268 InlineCacheState state = | 1268 InlineCacheState state = |
| 1269 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; | 1269 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; |
| 1270 return GetCode(kind(), type, name, state); | 1270 return GetCode(kind(), type, name, state); |
| 1271 } | 1271 } |
| 1272 | 1272 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1315 #define __ ACCESS_MASM(masm) | 1315 #define __ ACCESS_MASM(masm) |
| 1316 | 1316 |
| 1317 | 1317 |
| 1318 void ElementHandlerCompiler::GenerateLoadDictionaryElement( | 1318 void ElementHandlerCompiler::GenerateLoadDictionaryElement( |
| 1319 MacroAssembler* masm) { | 1319 MacroAssembler* masm) { |
| 1320 // The return address is in ra. | 1320 // The return address is in ra. |
| 1321 Label slow, miss; | 1321 Label slow, miss; |
| 1322 | 1322 |
| 1323 Register key = LoadIC::NameRegister(); | 1323 Register key = LoadIC::NameRegister(); |
| 1324 Register receiver = LoadIC::ReceiverRegister(); | 1324 Register receiver = LoadIC::ReceiverRegister(); |
| 1325 ASSERT(receiver.is(a1)); | 1325 DCHECK(receiver.is(a1)); |
| 1326 ASSERT(key.is(a2)); | 1326 DCHECK(key.is(a2)); |
| 1327 | 1327 |
| 1328 __ UntagAndJumpIfNotSmi(t2, key, &miss); | 1328 __ UntagAndJumpIfNotSmi(t2, key, &miss); |
| 1329 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 1329 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 1330 __ LoadFromNumberDictionary(&slow, t0, key, v0, t2, a3, t1); | 1330 __ LoadFromNumberDictionary(&slow, t0, key, v0, t2, a3, t1); |
| 1331 __ Ret(); | 1331 __ Ret(); |
| 1332 | 1332 |
| 1333 // Slow case, key and receiver still unmodified. | 1333 // Slow case, key and receiver still unmodified. |
| 1334 __ bind(&slow); | 1334 __ bind(&slow); |
| 1335 __ IncrementCounter( | 1335 __ IncrementCounter( |
| 1336 masm->isolate()->counters()->keyed_load_external_array_slow(), | 1336 masm->isolate()->counters()->keyed_load_external_array_slow(), |
| 1337 1, a2, a3); | 1337 1, a2, a3); |
| 1338 | 1338 |
| 1339 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); | 1339 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); |
| 1340 | 1340 |
| 1341 // Miss case, call the runtime. | 1341 // Miss case, call the runtime. |
| 1342 __ bind(&miss); | 1342 __ bind(&miss); |
| 1343 | 1343 |
| 1344 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1344 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 1345 } | 1345 } |
| 1346 | 1346 |
| 1347 | 1347 |
| 1348 #undef __ | 1348 #undef __ |
| 1349 | 1349 |
| 1350 } } // namespace v8::internal | 1350 } } // namespace v8::internal |
| 1351 | 1351 |
| 1352 #endif // V8_TARGET_ARCH_MIPS | 1352 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |