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_X87 | 7 #if V8_TARGET_ARCH_X87 |
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 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 // Pop at miss. | 110 // Pop at miss. |
111 __ bind(&miss); | 111 __ bind(&miss); |
112 __ pop(offset); | 112 __ pop(offset); |
113 } | 113 } |
114 } | 114 } |
115 | 115 |
116 | 116 |
117 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( | 117 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( |
118 MacroAssembler* masm, Label* miss_label, Register receiver, | 118 MacroAssembler* masm, Label* miss_label, Register receiver, |
119 Handle<Name> name, Register scratch0, Register scratch1) { | 119 Handle<Name> name, Register scratch0, Register scratch1) { |
120 ASSERT(name->IsUniqueName()); | 120 DCHECK(name->IsUniqueName()); |
121 ASSERT(!receiver.is(scratch0)); | 121 DCHECK(!receiver.is(scratch0)); |
122 Counters* counters = masm->isolate()->counters(); | 122 Counters* counters = masm->isolate()->counters(); |
123 __ IncrementCounter(counters->negative_lookups(), 1); | 123 __ IncrementCounter(counters->negative_lookups(), 1); |
124 __ IncrementCounter(counters->negative_lookups_miss(), 1); | 124 __ IncrementCounter(counters->negative_lookups_miss(), 1); |
125 | 125 |
126 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); | 126 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); |
127 | 127 |
128 const int kInterceptorOrAccessCheckNeededMask = | 128 const int kInterceptorOrAccessCheckNeededMask = |
129 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); | 129 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
130 | 130 |
131 // Bail out if the receiver has a named interceptor or requires access checks. | 131 // Bail out if the receiver has a named interceptor or requires access checks. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 Register receiver, | 163 Register receiver, |
164 Register name, | 164 Register name, |
165 Register scratch, | 165 Register scratch, |
166 Register extra, | 166 Register extra, |
167 Register extra2, | 167 Register extra2, |
168 Register extra3) { | 168 Register extra3) { |
169 Label miss; | 169 Label miss; |
170 | 170 |
171 // Assert that code is valid. The multiplying code relies on the entry size | 171 // Assert that code is valid. The multiplying code relies on the entry size |
172 // being 12. | 172 // being 12. |
173 ASSERT(sizeof(Entry) == 12); | 173 DCHECK(sizeof(Entry) == 12); |
174 | 174 |
175 // Assert the flags do not name a specific type. | 175 // Assert the flags do not name a specific type. |
176 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); | 176 DCHECK(Code::ExtractTypeFromFlags(flags) == 0); |
177 | 177 |
178 // Assert that there are no register conflicts. | 178 // Assert that there are no register conflicts. |
179 ASSERT(!scratch.is(receiver)); | 179 DCHECK(!scratch.is(receiver)); |
180 ASSERT(!scratch.is(name)); | 180 DCHECK(!scratch.is(name)); |
181 ASSERT(!extra.is(receiver)); | 181 DCHECK(!extra.is(receiver)); |
182 ASSERT(!extra.is(name)); | 182 DCHECK(!extra.is(name)); |
183 ASSERT(!extra.is(scratch)); | 183 DCHECK(!extra.is(scratch)); |
184 | 184 |
185 // Assert scratch and extra registers are valid, and extra2/3 are unused. | 185 // Assert scratch and extra registers are valid, and extra2/3 are unused. |
186 ASSERT(!scratch.is(no_reg)); | 186 DCHECK(!scratch.is(no_reg)); |
187 ASSERT(extra2.is(no_reg)); | 187 DCHECK(extra2.is(no_reg)); |
188 ASSERT(extra3.is(no_reg)); | 188 DCHECK(extra3.is(no_reg)); |
189 | 189 |
190 Register offset = scratch; | 190 Register offset = scratch; |
191 scratch = no_reg; | 191 scratch = no_reg; |
192 | 192 |
193 Counters* counters = masm->isolate()->counters(); | 193 Counters* counters = masm->isolate()->counters(); |
194 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); | 194 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); |
195 | 195 |
196 // Check that the receiver isn't a smi. | 196 // Check that the receiver isn't a smi. |
197 __ JumpIfSmi(receiver, &miss); | 197 __ JumpIfSmi(receiver, &miss); |
198 | 198 |
199 // Get the map of the receiver and compute the hash. | 199 // Get the map of the receiver and compute the hash. |
200 __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); | 200 __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); |
201 __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); | 201 __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); |
202 __ xor_(offset, flags); | 202 __ xor_(offset, flags); |
203 // We mask out the last two bits because they are not part of the hash and | 203 // We mask out the last two bits because they are not part of the hash and |
204 // they are always 01 for maps. Also in the two 'and' instructions below. | 204 // they are always 01 for maps. Also in the two 'and' instructions below. |
205 __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); | 205 __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); |
206 // ProbeTable expects the offset to be pointer scaled, which it is, because | 206 // ProbeTable expects the offset to be pointer scaled, which it is, because |
207 // the heap object tag size is 2 and the pointer size log 2 is also 2. | 207 // the heap object tag size is 2 and the pointer size log 2 is also 2. |
208 ASSERT(kCacheIndexShift == kPointerSizeLog2); | 208 DCHECK(kCacheIndexShift == kPointerSizeLog2); |
209 | 209 |
210 // Probe the primary table. | 210 // Probe the primary table. |
211 ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra); | 211 ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra); |
212 | 212 |
213 // Primary miss: Compute hash for secondary probe. | 213 // Primary miss: Compute hash for secondary probe. |
214 __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); | 214 __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); |
215 __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); | 215 __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); |
216 __ xor_(offset, flags); | 216 __ xor_(offset, flags); |
217 __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); | 217 __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); |
218 __ sub(offset, name); | 218 __ sub(offset, name); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 Register holder, | 264 Register holder, |
265 Register name, | 265 Register name, |
266 Handle<JSObject> holder_obj) { | 266 Handle<JSObject> holder_obj) { |
267 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); | 267 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); |
268 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); | 268 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); |
269 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); | 269 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); |
270 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); | 270 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); |
271 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); | 271 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); |
272 __ push(name); | 272 __ push(name); |
273 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); | 273 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); |
274 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor)); | 274 DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); |
275 Register scratch = name; | 275 Register scratch = name; |
276 __ mov(scratch, Immediate(interceptor)); | 276 __ mov(scratch, Immediate(interceptor)); |
277 __ push(scratch); | 277 __ push(scratch); |
278 __ push(receiver); | 278 __ push(receiver); |
279 __ push(holder); | 279 __ push(holder); |
280 } | 280 } |
281 | 281 |
282 | 282 |
283 static void CompileCallLoadPropertyWithInterceptor( | 283 static void CompileCallLoadPropertyWithInterceptor( |
284 MacroAssembler* masm, | 284 MacroAssembler* masm, |
(...skipping 16 matching lines...) Expand all Loading... |
301 MacroAssembler* masm, const CallOptimization& optimization, | 301 MacroAssembler* masm, const CallOptimization& optimization, |
302 Handle<Map> receiver_map, Register receiver, Register scratch_in, | 302 Handle<Map> receiver_map, Register receiver, Register scratch_in, |
303 bool is_store, int argc, Register* values) { | 303 bool is_store, int argc, Register* values) { |
304 // Copy return value. | 304 // Copy return value. |
305 __ pop(scratch_in); | 305 __ pop(scratch_in); |
306 // receiver | 306 // receiver |
307 __ push(receiver); | 307 __ push(receiver); |
308 // Write the arguments to stack frame. | 308 // Write the arguments to stack frame. |
309 for (int i = 0; i < argc; i++) { | 309 for (int i = 0; i < argc; i++) { |
310 Register arg = values[argc-1-i]; | 310 Register arg = values[argc-1-i]; |
311 ASSERT(!receiver.is(arg)); | 311 DCHECK(!receiver.is(arg)); |
312 ASSERT(!scratch_in.is(arg)); | 312 DCHECK(!scratch_in.is(arg)); |
313 __ push(arg); | 313 __ push(arg); |
314 } | 314 } |
315 __ push(scratch_in); | 315 __ push(scratch_in); |
316 // Stack now matches JSFunction abi. | 316 // Stack now matches JSFunction abi. |
317 ASSERT(optimization.is_simple_api_call()); | 317 DCHECK(optimization.is_simple_api_call()); |
318 | 318 |
319 // Abi for CallApiFunctionStub. | 319 // Abi for CallApiFunctionStub. |
320 Register callee = eax; | 320 Register callee = eax; |
321 Register call_data = ebx; | 321 Register call_data = ebx; |
322 Register holder = ecx; | 322 Register holder = ecx; |
323 Register api_function_address = edx; | 323 Register api_function_address = edx; |
324 Register scratch = edi; // scratch_in is no longer valid. | 324 Register scratch = edi; // scratch_in is no longer valid. |
325 | 325 |
326 // Put holder in place. | 326 // Put holder in place. |
327 CallOptimization::HolderLookup holder_lookup; | 327 CallOptimization::HolderLookup holder_lookup; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 | 381 |
382 | 382 |
383 // Generate code to check that a global property cell is empty. Create | 383 // Generate code to check that a global property cell is empty. Create |
384 // the property cell at compilation time if no cell exists for the | 384 // the property cell at compilation time if no cell exists for the |
385 // property. | 385 // property. |
386 void PropertyHandlerCompiler::GenerateCheckPropertyCell( | 386 void PropertyHandlerCompiler::GenerateCheckPropertyCell( |
387 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, | 387 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, |
388 Register scratch, Label* miss) { | 388 Register scratch, Label* miss) { |
389 Handle<PropertyCell> cell = | 389 Handle<PropertyCell> cell = |
390 JSGlobalObject::EnsurePropertyCell(global, name); | 390 JSGlobalObject::EnsurePropertyCell(global, name); |
391 ASSERT(cell->value()->IsTheHole()); | 391 DCHECK(cell->value()->IsTheHole()); |
392 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value(); | 392 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value(); |
393 if (masm->serializer_enabled()) { | 393 if (masm->serializer_enabled()) { |
394 __ mov(scratch, Immediate(cell)); | 394 __ mov(scratch, Immediate(cell)); |
395 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), | 395 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), |
396 Immediate(the_hole)); | 396 Immediate(the_hole)); |
397 } else { | 397 } else { |
398 __ cmp(Operand::ForCell(cell), Immediate(the_hole)); | 398 __ cmp(Operand::ForCell(cell), Immediate(the_hole)); |
399 } | 399 } |
400 __ j(not_equal, miss); | 400 __ j(not_equal, miss); |
401 } | 401 } |
402 | 402 |
403 | 403 |
404 // Receiver_reg is preserved on jumps to miss_label, but may be destroyed if | 404 // Receiver_reg is preserved on jumps to miss_label, but may be destroyed if |
405 // store is successful. | 405 // store is successful. |
406 void NamedStoreHandlerCompiler::GenerateStoreTransition( | 406 void NamedStoreHandlerCompiler::GenerateStoreTransition( |
407 MacroAssembler* masm, LookupResult* lookup, Handle<Map> transition, | 407 MacroAssembler* masm, LookupResult* lookup, Handle<Map> transition, |
408 Handle<Name> name, Register receiver_reg, Register storage_reg, | 408 Handle<Name> name, Register receiver_reg, Register storage_reg, |
409 Register value_reg, Register scratch1, Register scratch2, Register unused, | 409 Register value_reg, Register scratch1, Register scratch2, Register unused, |
410 Label* miss_label, Label* slow) { | 410 Label* miss_label, Label* slow) { |
411 int descriptor = transition->LastAdded(); | 411 int descriptor = transition->LastAdded(); |
412 DescriptorArray* descriptors = transition->instance_descriptors(); | 412 DescriptorArray* descriptors = transition->instance_descriptors(); |
413 PropertyDetails details = descriptors->GetDetails(descriptor); | 413 PropertyDetails details = descriptors->GetDetails(descriptor); |
414 Representation representation = details.representation(); | 414 Representation representation = details.representation(); |
415 ASSERT(!representation.IsNone()); | 415 DCHECK(!representation.IsNone()); |
416 | 416 |
417 if (details.type() == CONSTANT) { | 417 if (details.type() == CONSTANT) { |
418 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate()); | 418 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate()); |
419 __ CmpObject(value_reg, constant); | 419 __ CmpObject(value_reg, constant); |
420 __ j(not_equal, miss_label); | 420 __ j(not_equal, miss_label); |
421 } else if (representation.IsSmi()) { | 421 } else if (representation.IsSmi()) { |
422 __ JumpIfNotSmi(value_reg, miss_label); | 422 __ JumpIfNotSmi(value_reg, miss_label); |
423 } else if (representation.IsHeapObject()) { | 423 } else if (representation.IsHeapObject()) { |
424 __ JumpIfSmi(value_reg, miss_label); | 424 __ JumpIfSmi(value_reg, miss_label); |
425 HeapType* field_type = descriptors->GetFieldType(descriptor); | 425 HeapType* field_type = descriptors->GetFieldType(descriptor); |
(...skipping 26 matching lines...) Expand all Loading... |
452 __ bind(&heap_number); | 452 __ bind(&heap_number); |
453 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), | 453 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), |
454 miss_label, DONT_DO_SMI_CHECK); | 454 miss_label, DONT_DO_SMI_CHECK); |
455 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset)); | 455 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset)); |
456 | 456 |
457 __ bind(&do_store); | 457 __ bind(&do_store); |
458 __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset)); | 458 __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset)); |
459 } | 459 } |
460 | 460 |
461 // Stub never generated for objects that require access checks. | 461 // Stub never generated for objects that require access checks. |
462 ASSERT(!transition->is_access_check_needed()); | 462 DCHECK(!transition->is_access_check_needed()); |
463 | 463 |
464 // Perform map transition for the receiver if necessary. | 464 // Perform map transition for the receiver if necessary. |
465 if (details.type() == FIELD && | 465 if (details.type() == FIELD && |
466 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { | 466 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { |
467 // The properties must be extended before we can store the value. | 467 // The properties must be extended before we can store the value. |
468 // We jump to a runtime call that extends the properties array. | 468 // We jump to a runtime call that extends the properties array. |
469 __ pop(scratch1); // Return address. | 469 __ pop(scratch1); // Return address. |
470 __ push(receiver_reg); | 470 __ push(receiver_reg); |
471 __ push(Immediate(transition)); | 471 __ push(Immediate(transition)); |
472 __ push(value_reg); | 472 __ push(value_reg); |
(...skipping 12 matching lines...) Expand all Loading... |
485 | 485 |
486 // Update the write barrier for the map field. | 486 // Update the write barrier for the map field. |
487 __ RecordWriteField(receiver_reg, | 487 __ RecordWriteField(receiver_reg, |
488 HeapObject::kMapOffset, | 488 HeapObject::kMapOffset, |
489 scratch1, | 489 scratch1, |
490 scratch2, | 490 scratch2, |
491 OMIT_REMEMBERED_SET, | 491 OMIT_REMEMBERED_SET, |
492 OMIT_SMI_CHECK); | 492 OMIT_SMI_CHECK); |
493 | 493 |
494 if (details.type() == CONSTANT) { | 494 if (details.type() == CONSTANT) { |
495 ASSERT(value_reg.is(eax)); | 495 DCHECK(value_reg.is(eax)); |
496 __ ret(0); | 496 __ ret(0); |
497 return; | 497 return; |
498 } | 498 } |
499 | 499 |
500 int index = transition->instance_descriptors()->GetFieldIndex( | 500 int index = transition->instance_descriptors()->GetFieldIndex( |
501 transition->LastAdded()); | 501 transition->LastAdded()); |
502 | 502 |
503 // Adjust for the number of properties stored in the object. Even in the | 503 // Adjust for the number of properties stored in the object. Even in the |
504 // face of a transition we can use the old map here because the size of the | 504 // face of a transition we can use the old map here because the size of the |
505 // object and the number of in-object properties is not going to change. | 505 // object and the number of in-object properties is not going to change. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 __ RecordWriteField(scratch1, | 548 __ RecordWriteField(scratch1, |
549 offset, | 549 offset, |
550 storage_reg, | 550 storage_reg, |
551 receiver_reg, | 551 receiver_reg, |
552 EMIT_REMEMBERED_SET, | 552 EMIT_REMEMBERED_SET, |
553 smi_check); | 553 smi_check); |
554 } | 554 } |
555 } | 555 } |
556 | 556 |
557 // Return the value (register eax). | 557 // Return the value (register eax). |
558 ASSERT(value_reg.is(eax)); | 558 DCHECK(value_reg.is(eax)); |
559 __ ret(0); | 559 __ ret(0); |
560 } | 560 } |
561 | 561 |
562 | 562 |
563 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 563 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
564 // but may be destroyed if store is successful. | 564 // but may be destroyed if store is successful. |
565 void NamedStoreHandlerCompiler::GenerateStoreField( | 565 void NamedStoreHandlerCompiler::GenerateStoreField( |
566 MacroAssembler* masm, Handle<JSObject> object, LookupResult* lookup, | 566 MacroAssembler* masm, Handle<JSObject> object, LookupResult* lookup, |
567 Register receiver_reg, Register name_reg, Register value_reg, | 567 Register receiver_reg, Register name_reg, Register value_reg, |
568 Register scratch1, Register scratch2, Label* miss_label) { | 568 Register scratch1, Register scratch2, Label* miss_label) { |
569 // Stub never generated for non-global objects that require access | 569 // Stub never generated for non-global objects that require access |
570 // checks. | 570 // checks. |
571 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 571 DCHECK(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
572 | 572 |
573 FieldIndex index = lookup->GetFieldIndex(); | 573 FieldIndex index = lookup->GetFieldIndex(); |
574 | 574 |
575 Representation representation = lookup->representation(); | 575 Representation representation = lookup->representation(); |
576 ASSERT(!representation.IsNone()); | 576 DCHECK(!representation.IsNone()); |
577 if (representation.IsSmi()) { | 577 if (representation.IsSmi()) { |
578 __ JumpIfNotSmi(value_reg, miss_label); | 578 __ JumpIfNotSmi(value_reg, miss_label); |
579 } else if (representation.IsHeapObject()) { | 579 } else if (representation.IsHeapObject()) { |
580 __ JumpIfSmi(value_reg, miss_label); | 580 __ JumpIfSmi(value_reg, miss_label); |
581 HeapType* field_type = lookup->GetFieldType(); | 581 HeapType* field_type = lookup->GetFieldType(); |
582 HeapType::Iterator<Map> it = field_type->Classes(); | 582 HeapType::Iterator<Map> it = field_type->Classes(); |
583 if (!it.Done()) { | 583 if (!it.Done()) { |
584 Label do_store; | 584 Label do_store; |
585 while (true) { | 585 while (true) { |
586 __ CompareMap(value_reg, it.Current()); | 586 __ CompareMap(value_reg, it.Current()); |
(...skipping 24 matching lines...) Expand all Loading... |
611 __ pop(value_reg); | 611 __ pop(value_reg); |
612 __ SmiTag(value_reg); | 612 __ SmiTag(value_reg); |
613 __ jmp(&do_store); | 613 __ jmp(&do_store); |
614 __ bind(&heap_number); | 614 __ bind(&heap_number); |
615 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), | 615 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), |
616 miss_label, DONT_DO_SMI_CHECK); | 616 miss_label, DONT_DO_SMI_CHECK); |
617 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset)); | 617 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset)); |
618 __ bind(&do_store); | 618 __ bind(&do_store); |
619 __ fstp_d(FieldOperand(scratch1, HeapNumber::kValueOffset)); | 619 __ fstp_d(FieldOperand(scratch1, HeapNumber::kValueOffset)); |
620 // Return the value (register eax). | 620 // Return the value (register eax). |
621 ASSERT(value_reg.is(eax)); | 621 DCHECK(value_reg.is(eax)); |
622 __ ret(0); | 622 __ ret(0); |
623 return; | 623 return; |
624 } | 624 } |
625 | 625 |
626 ASSERT(!representation.IsDouble()); | 626 DCHECK(!representation.IsDouble()); |
627 // TODO(verwaest): Share this code as a code stub. | 627 // TODO(verwaest): Share this code as a code stub. |
628 SmiCheck smi_check = representation.IsTagged() | 628 SmiCheck smi_check = representation.IsTagged() |
629 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; | 629 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; |
630 if (index.is_inobject()) { | 630 if (index.is_inobject()) { |
631 // Set the property straight into the object. | 631 // Set the property straight into the object. |
632 __ mov(FieldOperand(receiver_reg, index.offset()), value_reg); | 632 __ mov(FieldOperand(receiver_reg, index.offset()), value_reg); |
633 | 633 |
634 if (!representation.IsSmi()) { | 634 if (!representation.IsSmi()) { |
635 // Update the write barrier for the array address. | 635 // Update the write barrier for the array address. |
636 // Pass the value being stored in the now unused name_reg. | 636 // Pass the value being stored in the now unused name_reg. |
(...skipping 18 matching lines...) Expand all Loading... |
655 __ RecordWriteField(scratch1, | 655 __ RecordWriteField(scratch1, |
656 index.offset(), | 656 index.offset(), |
657 name_reg, | 657 name_reg, |
658 receiver_reg, | 658 receiver_reg, |
659 EMIT_REMEMBERED_SET, | 659 EMIT_REMEMBERED_SET, |
660 smi_check); | 660 smi_check); |
661 } | 661 } |
662 } | 662 } |
663 | 663 |
664 // Return the value (register eax). | 664 // Return the value (register eax). |
665 ASSERT(value_reg.is(eax)); | 665 DCHECK(value_reg.is(eax)); |
666 __ ret(0); | 666 __ ret(0); |
667 } | 667 } |
668 | 668 |
669 | 669 |
670 void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, | 670 void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, |
671 Handle<Code> code) { | 671 Handle<Code> code) { |
672 __ jmp(code, RelocInfo::CODE_TARGET); | 672 __ jmp(code, RelocInfo::CODE_TARGET); |
673 } | 673 } |
674 | 674 |
675 | 675 |
676 #undef __ | 676 #undef __ |
677 #define __ ACCESS_MASM(masm()) | 677 #define __ ACCESS_MASM(masm()) |
678 | 678 |
679 | 679 |
680 Register PropertyHandlerCompiler::CheckPrototypes( | 680 Register PropertyHandlerCompiler::CheckPrototypes( |
681 Register object_reg, Register holder_reg, Register scratch1, | 681 Register object_reg, Register holder_reg, Register scratch1, |
682 Register scratch2, Handle<Name> name, Label* miss, | 682 Register scratch2, Handle<Name> name, Label* miss, |
683 PrototypeCheckType check) { | 683 PrototypeCheckType check) { |
684 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); | 684 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); |
685 | 685 |
686 // Make sure there's no overlap between holder and object registers. | 686 // Make sure there's no overlap between holder and object registers. |
687 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 687 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
688 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 688 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
689 && !scratch2.is(scratch1)); | 689 && !scratch2.is(scratch1)); |
690 | 690 |
691 // Keep track of the current object in register reg. | 691 // Keep track of the current object in register reg. |
692 Register reg = object_reg; | 692 Register reg = object_reg; |
693 int depth = 0; | 693 int depth = 0; |
694 | 694 |
695 Handle<JSObject> current = Handle<JSObject>::null(); | 695 Handle<JSObject> current = Handle<JSObject>::null(); |
696 if (type()->IsConstant()) | 696 if (type()->IsConstant()) |
697 current = Handle<JSObject>::cast(type()->AsConstant()->Value()); | 697 current = Handle<JSObject>::cast(type()->AsConstant()->Value()); |
698 Handle<JSObject> prototype = Handle<JSObject>::null(); | 698 Handle<JSObject> prototype = Handle<JSObject>::null(); |
699 Handle<Map> current_map = receiver_map; | 699 Handle<Map> current_map = receiver_map; |
700 Handle<Map> holder_map(holder()->map()); | 700 Handle<Map> holder_map(holder()->map()); |
701 // Traverse the prototype chain and check the maps in the prototype chain for | 701 // Traverse the prototype chain and check the maps in the prototype chain for |
702 // fast and global objects or do negative lookup for normal objects. | 702 // fast and global objects or do negative lookup for normal objects. |
703 while (!current_map.is_identical_to(holder_map)) { | 703 while (!current_map.is_identical_to(holder_map)) { |
704 ++depth; | 704 ++depth; |
705 | 705 |
706 // Only global objects and objects that do not require access | 706 // Only global objects and objects that do not require access |
707 // checks are allowed in stubs. | 707 // checks are allowed in stubs. |
708 ASSERT(current_map->IsJSGlobalProxyMap() || | 708 DCHECK(current_map->IsJSGlobalProxyMap() || |
709 !current_map->is_access_check_needed()); | 709 !current_map->is_access_check_needed()); |
710 | 710 |
711 prototype = handle(JSObject::cast(current_map->prototype())); | 711 prototype = handle(JSObject::cast(current_map->prototype())); |
712 if (current_map->is_dictionary_map() && | 712 if (current_map->is_dictionary_map() && |
713 !current_map->IsJSGlobalObjectMap() && | 713 !current_map->IsJSGlobalObjectMap() && |
714 !current_map->IsJSGlobalProxyMap()) { | 714 !current_map->IsJSGlobalProxyMap()) { |
715 if (!name->IsUniqueName()) { | 715 if (!name->IsUniqueName()) { |
716 ASSERT(name->IsString()); | 716 DCHECK(name->IsString()); |
717 name = factory()->InternalizeString(Handle<String>::cast(name)); | 717 name = factory()->InternalizeString(Handle<String>::cast(name)); |
718 } | 718 } |
719 ASSERT(current.is_null() || | 719 DCHECK(current.is_null() || |
720 current->property_dictionary()->FindEntry(name) == | 720 current->property_dictionary()->FindEntry(name) == |
721 NameDictionary::kNotFound); | 721 NameDictionary::kNotFound); |
722 | 722 |
723 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, | 723 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, |
724 scratch1, scratch2); | 724 scratch1, scratch2); |
725 | 725 |
726 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 726 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
727 reg = holder_reg; // From now on the object will be in holder_reg. | 727 reg = holder_reg; // From now on the object will be in holder_reg. |
728 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 728 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
729 } else { | 729 } else { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 | 769 |
770 // Log the check depth. | 770 // Log the check depth. |
771 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 771 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
772 | 772 |
773 if (depth != 0 || check == CHECK_ALL_MAPS) { | 773 if (depth != 0 || check == CHECK_ALL_MAPS) { |
774 // Check the holder map. | 774 // Check the holder map. |
775 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); | 775 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); |
776 } | 776 } |
777 | 777 |
778 // Perform security check for access to the global object. | 778 // Perform security check for access to the global object. |
779 ASSERT(current_map->IsJSGlobalProxyMap() || | 779 DCHECK(current_map->IsJSGlobalProxyMap() || |
780 !current_map->is_access_check_needed()); | 780 !current_map->is_access_check_needed()); |
781 if (current_map->IsJSGlobalProxyMap()) { | 781 if (current_map->IsJSGlobalProxyMap()) { |
782 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); | 782 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); |
783 } | 783 } |
784 | 784 |
785 // Return the register containing the holder. | 785 // Return the register containing the holder. |
786 return reg; | 786 return reg; |
787 } | 787 } |
788 | 788 |
789 | 789 |
(...skipping 20 matching lines...) Expand all Loading... |
810 | 810 |
811 | 811 |
812 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, | 812 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, |
813 Handle<Name> name, | 813 Handle<Name> name, |
814 Handle<Object> callback) { | 814 Handle<Object> callback) { |
815 Label miss; | 815 Label miss; |
816 | 816 |
817 Register reg = FrontendHeader(object_reg, name, &miss); | 817 Register reg = FrontendHeader(object_reg, name, &miss); |
818 | 818 |
819 if (!holder()->HasFastProperties()) { | 819 if (!holder()->HasFastProperties()) { |
820 ASSERT(!holder()->IsGlobalObject()); | 820 DCHECK(!holder()->IsGlobalObject()); |
821 ASSERT(!reg.is(scratch2())); | 821 DCHECK(!reg.is(scratch2())); |
822 ASSERT(!reg.is(scratch3())); | 822 DCHECK(!reg.is(scratch3())); |
823 Register dictionary = scratch1(); | 823 Register dictionary = scratch1(); |
824 bool must_preserve_dictionary_reg = reg.is(dictionary); | 824 bool must_preserve_dictionary_reg = reg.is(dictionary); |
825 | 825 |
826 // Load the properties dictionary. | 826 // Load the properties dictionary. |
827 if (must_preserve_dictionary_reg) { | 827 if (must_preserve_dictionary_reg) { |
828 __ push(dictionary); | 828 __ push(dictionary); |
829 } | 829 } |
830 __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); | 830 __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); |
831 | 831 |
832 // Probe the dictionary. | 832 // Probe the dictionary. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 Register reg, FieldIndex field, Representation representation) { | 870 Register reg, FieldIndex field, Representation representation) { |
871 if (!reg.is(receiver())) __ mov(receiver(), reg); | 871 if (!reg.is(receiver())) __ mov(receiver(), reg); |
872 LoadFieldStub stub(isolate(), field); | 872 LoadFieldStub stub(isolate(), field); |
873 GenerateTailCall(masm(), stub.GetCode()); | 873 GenerateTailCall(masm(), stub.GetCode()); |
874 } | 874 } |
875 | 875 |
876 | 876 |
877 void NamedLoadHandlerCompiler::GenerateLoadCallback( | 877 void NamedLoadHandlerCompiler::GenerateLoadCallback( |
878 Register reg, Handle<ExecutableAccessorInfo> callback) { | 878 Register reg, Handle<ExecutableAccessorInfo> callback) { |
879 // Insert additional parameters into the stack frame above return address. | 879 // Insert additional parameters into the stack frame above return address. |
880 ASSERT(!scratch3().is(reg)); | 880 DCHECK(!scratch3().is(reg)); |
881 __ pop(scratch3()); // Get return address to place it below. | 881 __ pop(scratch3()); // Get return address to place it below. |
882 | 882 |
883 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); | 883 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); |
884 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); | 884 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); |
885 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); | 885 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); |
886 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); | 886 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); |
887 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); | 887 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); |
888 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); | 888 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); |
889 __ push(receiver()); // receiver | 889 __ push(receiver()); // receiver |
890 // Push data from ExecutableAccessorInfo. | 890 // Push data from ExecutableAccessorInfo. |
891 if (isolate()->heap()->InNewSpace(callback->data())) { | 891 if (isolate()->heap()->InNewSpace(callback->data())) { |
892 ASSERT(!scratch2().is(reg)); | 892 DCHECK(!scratch2().is(reg)); |
893 __ mov(scratch2(), Immediate(callback)); | 893 __ mov(scratch2(), Immediate(callback)); |
894 __ push(FieldOperand(scratch2(), ExecutableAccessorInfo::kDataOffset)); | 894 __ push(FieldOperand(scratch2(), ExecutableAccessorInfo::kDataOffset)); |
895 } else { | 895 } else { |
896 __ push(Immediate(Handle<Object>(callback->data(), isolate()))); | 896 __ push(Immediate(Handle<Object>(callback->data(), isolate()))); |
897 } | 897 } |
898 __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue | 898 __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue |
899 // ReturnValue default value | 899 // ReturnValue default value |
900 __ push(Immediate(isolate()->factory()->undefined_value())); | 900 __ push(Immediate(isolate()->factory()->undefined_value())); |
901 __ push(Immediate(reinterpret_cast<int>(isolate()))); | 901 __ push(Immediate(reinterpret_cast<int>(isolate()))); |
902 __ push(reg); // holder | 902 __ push(reg); // holder |
(...skipping 19 matching lines...) Expand all Loading... |
922 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { | 922 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { |
923 // Return the constant value. | 923 // Return the constant value. |
924 __ LoadObject(eax, value); | 924 __ LoadObject(eax, value); |
925 __ ret(0); | 925 __ ret(0); |
926 } | 926 } |
927 | 927 |
928 | 928 |
929 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg, | 929 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg, |
930 LookupResult* lookup, | 930 LookupResult* lookup, |
931 Handle<Name> name) { | 931 Handle<Name> name) { |
932 ASSERT(holder()->HasNamedInterceptor()); | 932 DCHECK(holder()->HasNamedInterceptor()); |
933 ASSERT(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); | 933 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); |
934 | 934 |
935 // So far the most popular follow ups for interceptor loads are FIELD | 935 // So far the most popular follow ups for interceptor loads are FIELD |
936 // and CALLBACKS, so inline only them, other cases may be added | 936 // and CALLBACKS, so inline only them, other cases may be added |
937 // later. | 937 // later. |
938 bool compile_followup_inline = false; | 938 bool compile_followup_inline = false; |
939 if (lookup->IsFound() && lookup->IsCacheable()) { | 939 if (lookup->IsFound() && lookup->IsCacheable()) { |
940 if (lookup->IsField()) { | 940 if (lookup->IsField()) { |
941 compile_followup_inline = true; | 941 compile_followup_inline = true; |
942 } else if (lookup->type() == CALLBACKS && | 942 } else if (lookup->type() == CALLBACKS && |
943 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { | 943 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { |
944 Handle<ExecutableAccessorInfo> callback( | 944 Handle<ExecutableAccessorInfo> callback( |
945 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); | 945 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); |
946 compile_followup_inline = | 946 compile_followup_inline = |
947 callback->getter() != NULL && | 947 callback->getter() != NULL && |
948 ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback, | 948 ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback, |
949 type()); | 949 type()); |
950 } | 950 } |
951 } | 951 } |
952 | 952 |
953 if (compile_followup_inline) { | 953 if (compile_followup_inline) { |
954 // Compile the interceptor call, followed by inline code to load the | 954 // Compile the interceptor call, followed by inline code to load the |
955 // property from further up the prototype chain if the call fails. | 955 // property from further up the prototype chain if the call fails. |
956 // Check that the maps haven't changed. | 956 // Check that the maps haven't changed. |
957 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); | 957 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
958 | 958 |
959 // Preserve the receiver register explicitly whenever it is different from | 959 // Preserve the receiver register explicitly whenever it is different from |
960 // the holder and it is needed should the interceptor return without any | 960 // the holder and it is needed should the interceptor return without any |
961 // result. The CALLBACKS case needs the receiver to be passed into C++ code, | 961 // result. The CALLBACKS case needs the receiver to be passed into C++ code, |
962 // the FIELD case might cause a miss during the prototype check. | 962 // the FIELD case might cause a miss during the prototype check. |
963 bool must_perfrom_prototype_check = *holder() != lookup->holder(); | 963 bool must_perfrom_prototype_check = *holder() != lookup->holder(); |
964 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && | 964 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && |
965 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); | 965 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); |
966 | 966 |
967 // Save necessary data before invoking an interceptor. | 967 // Save necessary data before invoking an interceptor. |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1161 Register name = LoadIC::NameRegister(); | 1161 Register name = LoadIC::NameRegister(); |
1162 static Register registers[] = { receiver, name, ebx, eax, edi, no_reg }; | 1162 static Register registers[] = { receiver, name, ebx, eax, edi, no_reg }; |
1163 return registers; | 1163 return registers; |
1164 } | 1164 } |
1165 | 1165 |
1166 | 1166 |
1167 Register* PropertyAccessCompiler::store_calling_convention() { | 1167 Register* PropertyAccessCompiler::store_calling_convention() { |
1168 // receiver, name, scratch1, scratch2, scratch3. | 1168 // receiver, name, scratch1, scratch2, scratch3. |
1169 Register receiver = StoreIC::ReceiverRegister(); | 1169 Register receiver = StoreIC::ReceiverRegister(); |
1170 Register name = StoreIC::NameRegister(); | 1170 Register name = StoreIC::NameRegister(); |
1171 ASSERT(ebx.is(KeyedStoreIC::MapRegister())); | 1171 DCHECK(ebx.is(KeyedStoreIC::MapRegister())); |
1172 static Register registers[] = { receiver, name, ebx, edi, no_reg }; | 1172 static Register registers[] = { receiver, name, ebx, edi, no_reg }; |
1173 return registers; | 1173 return registers; |
1174 } | 1174 } |
1175 | 1175 |
1176 | 1176 |
1177 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } | 1177 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } |
1178 | 1178 |
1179 | 1179 |
1180 #undef __ | 1180 #undef __ |
1181 #define __ ACCESS_MASM(masm) | 1181 #define __ ACCESS_MASM(masm) |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1269 __ j(not_equal, &miss); | 1269 __ j(not_equal, &miss); |
1270 } | 1270 } |
1271 } | 1271 } |
1272 | 1272 |
1273 Label number_case; | 1273 Label number_case; |
1274 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; | 1274 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; |
1275 __ JumpIfSmi(receiver(), smi_target); | 1275 __ JumpIfSmi(receiver(), smi_target); |
1276 | 1276 |
1277 // Polymorphic keyed stores may use the map register | 1277 // Polymorphic keyed stores may use the map register |
1278 Register map_reg = scratch1(); | 1278 Register map_reg = scratch1(); |
1279 ASSERT(kind() != Code::KEYED_STORE_IC || | 1279 DCHECK(kind() != Code::KEYED_STORE_IC || |
1280 map_reg.is(KeyedStoreIC::MapRegister())); | 1280 map_reg.is(KeyedStoreIC::MapRegister())); |
1281 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset)); | 1281 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset)); |
1282 int receiver_count = types->length(); | 1282 int receiver_count = types->length(); |
1283 int number_of_handled_maps = 0; | 1283 int number_of_handled_maps = 0; |
1284 for (int current = 0; current < receiver_count; ++current) { | 1284 for (int current = 0; current < receiver_count; ++current) { |
1285 Handle<HeapType> type = types->at(current); | 1285 Handle<HeapType> type = types->at(current); |
1286 Handle<Map> map = IC::TypeToMap(*type, isolate()); | 1286 Handle<Map> map = IC::TypeToMap(*type, isolate()); |
1287 if (!map->is_deprecated()) { | 1287 if (!map->is_deprecated()) { |
1288 number_of_handled_maps++; | 1288 number_of_handled_maps++; |
1289 __ cmp(map_reg, map); | 1289 __ cmp(map_reg, map); |
1290 if (type->Is(HeapType::Number())) { | 1290 if (type->Is(HeapType::Number())) { |
1291 ASSERT(!number_case.is_unused()); | 1291 DCHECK(!number_case.is_unused()); |
1292 __ bind(&number_case); | 1292 __ bind(&number_case); |
1293 } | 1293 } |
1294 __ j(equal, handlers->at(current)); | 1294 __ j(equal, handlers->at(current)); |
1295 } | 1295 } |
1296 } | 1296 } |
1297 ASSERT(number_of_handled_maps != 0); | 1297 DCHECK(number_of_handled_maps != 0); |
1298 | 1298 |
1299 __ bind(&miss); | 1299 __ bind(&miss); |
1300 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1300 TailCallBuiltin(masm(), MissBuiltin(kind())); |
1301 | 1301 |
1302 // Return the generated code. | 1302 // Return the generated code. |
1303 InlineCacheState state = | 1303 InlineCacheState state = |
1304 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; | 1304 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; |
1305 return GetCode(kind(), type, name, state); | 1305 return GetCode(kind(), type, name, state); |
1306 } | 1306 } |
1307 | 1307 |
1308 | 1308 |
1309 #undef __ | 1309 #undef __ |
1310 #define __ ACCESS_MASM(masm) | 1310 #define __ ACCESS_MASM(masm) |
1311 | 1311 |
1312 | 1312 |
1313 void ElementHandlerCompiler::GenerateLoadDictionaryElement( | 1313 void ElementHandlerCompiler::GenerateLoadDictionaryElement( |
1314 MacroAssembler* masm) { | 1314 MacroAssembler* masm) { |
1315 // ----------- S t a t e ------------- | 1315 // ----------- S t a t e ------------- |
1316 // -- ecx : key | 1316 // -- ecx : key |
1317 // -- edx : receiver | 1317 // -- edx : receiver |
1318 // -- esp[0] : return address | 1318 // -- esp[0] : return address |
1319 // ----------------------------------- | 1319 // ----------------------------------- |
1320 ASSERT(edx.is(LoadIC::ReceiverRegister())); | 1320 DCHECK(edx.is(LoadIC::ReceiverRegister())); |
1321 ASSERT(ecx.is(LoadIC::NameRegister())); | 1321 DCHECK(ecx.is(LoadIC::NameRegister())); |
1322 Label slow, miss; | 1322 Label slow, miss; |
1323 | 1323 |
1324 // This stub is meant to be tail-jumped to, the receiver must already | 1324 // This stub is meant to be tail-jumped to, the receiver must already |
1325 // have been verified by the caller to not be a smi. | 1325 // have been verified by the caller to not be a smi. |
1326 __ JumpIfNotSmi(ecx, &miss); | 1326 __ JumpIfNotSmi(ecx, &miss); |
1327 __ mov(ebx, ecx); | 1327 __ mov(ebx, ecx); |
1328 __ SmiUntag(ebx); | 1328 __ SmiUntag(ebx); |
1329 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); | 1329 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); |
1330 | 1330 |
1331 // Push receiver on the stack to free up a register for the dictionary | 1331 // Push receiver on the stack to free up a register for the dictionary |
(...skipping 22 matching lines...) Expand all Loading... |
1354 // ----------------------------------- | 1354 // ----------------------------------- |
1355 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1355 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
1356 } | 1356 } |
1357 | 1357 |
1358 | 1358 |
1359 #undef __ | 1359 #undef __ |
1360 | 1360 |
1361 } } // namespace v8::internal | 1361 } } // namespace v8::internal |
1362 | 1362 |
1363 #endif // V8_TARGET_ARCH_X87 | 1363 #endif // V8_TARGET_ARCH_X87 |
OLD | NEW |