Move for-in cache validity check to generated code.
Review URL: http://codereview.chromium.org/464002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3407 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
1d9eac1b7c
commit
f568fc6d13
@ -1775,19 +1775,77 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
|
||||
|
||||
jsobject.Bind();
|
||||
// Get the set of properties (as a FixedArray or Map).
|
||||
frame_->EmitPush(r0); // duplicate the object being enumerated
|
||||
frame_->EmitPush(r0);
|
||||
// r0: value to be iterated over
|
||||
frame_->EmitPush(r0); // Push the object being iterated over.
|
||||
|
||||
// Check cache validity in generated code. This is a fast case for
|
||||
// the JSObject::IsSimpleEnum cache validity checks. If we cannot
|
||||
// guarantee cache validity, call the runtime system to check cache
|
||||
// validity or get the property names in a fixed array.
|
||||
JumpTarget call_runtime;
|
||||
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
|
||||
JumpTarget check_prototype;
|
||||
JumpTarget use_cache;
|
||||
__ mov(r1, Operand(r0));
|
||||
loop.Bind();
|
||||
// Check that there are no elements.
|
||||
__ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
|
||||
__ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
|
||||
__ cmp(r2, r4);
|
||||
call_runtime.Branch(ne);
|
||||
// Check that instance descriptors are not empty so that we can
|
||||
// check for an enum cache. Leave the map in r3 for the subsequent
|
||||
// prototype load.
|
||||
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
|
||||
__ ldr(r2, FieldMemOperand(r3, Map::kInstanceDescriptorsOffset));
|
||||
__ LoadRoot(ip, Heap::kEmptyDescriptorArrayRootIndex);
|
||||
__ cmp(r2, ip);
|
||||
call_runtime.Branch(eq);
|
||||
// Check that there in an enum cache in the non-empty instance
|
||||
// descriptors. This is the case if the next enumeration index
|
||||
// field does not contain a smi.
|
||||
__ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumerationIndexOffset));
|
||||
__ tst(r2, Operand(kSmiTagMask));
|
||||
call_runtime.Branch(eq);
|
||||
// For all objects but the receiver, check that the cache is empty.
|
||||
// r4: empty fixed array root.
|
||||
__ cmp(r1, r0);
|
||||
check_prototype.Branch(eq);
|
||||
__ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
||||
__ cmp(r2, r4);
|
||||
call_runtime.Branch(ne);
|
||||
check_prototype.Bind();
|
||||
// Load the prototype from the map and loop if non-null.
|
||||
__ ldr(r1, FieldMemOperand(r3, Map::kPrototypeOffset));
|
||||
__ LoadRoot(ip, Heap::kNullValueRootIndex);
|
||||
__ cmp(r1, ip);
|
||||
loop.Branch(ne);
|
||||
// The enum cache is valid. Load the map of the object being
|
||||
// iterated over and use the cache for the iteration.
|
||||
__ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
|
||||
use_cache.Jump();
|
||||
|
||||
call_runtime.Bind();
|
||||
// Call the runtime to get the property names for the object.
|
||||
frame_->EmitPush(r0); // push the object (slot 4) for the runtime call
|
||||
frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
|
||||
|
||||
// If we got a Map, we can do a fast modification check.
|
||||
// Otherwise, we got a FixedArray, and we have to do a slow check.
|
||||
// If we got a map from the runtime call, we can do a fast
|
||||
// modification check. Otherwise, we got a fixed array, and we have
|
||||
// to do a slow check.
|
||||
// r0: map or fixed array (result from call to
|
||||
// Runtime::kGetPropertyNamesFast)
|
||||
__ mov(r2, Operand(r0));
|
||||
__ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
|
||||
__ LoadRoot(ip, Heap::kMetaMapRootIndex);
|
||||
__ cmp(r1, ip);
|
||||
fixed_array.Branch(ne);
|
||||
|
||||
use_cache.Bind();
|
||||
// Get enum cache
|
||||
// r0: map (either the result from a call to
|
||||
// Runtime::kGetPropertyNamesFast or has been fetched directly from
|
||||
// the object)
|
||||
__ mov(r1, Operand(r0));
|
||||
__ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
|
||||
__ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
|
||||
@ -6396,7 +6454,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
__ b(eq, &adaptor);
|
||||
|
||||
// Check index against formal parameters count limit passed in
|
||||
// through register eax. Use unsigned comparison to get negative
|
||||
// through register r0. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ cmp(r1, r0);
|
||||
__ b(cs, &slow);
|
||||
|
@ -3056,13 +3056,59 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
|
||||
jsobject.Bind();
|
||||
// Get the set of properties (as a FixedArray or Map).
|
||||
// eax: value to be iterated over
|
||||
frame_->EmitPush(eax); // push the object being iterated over (slot 4)
|
||||
frame_->EmitPush(eax); // Push the object being iterated over.
|
||||
|
||||
// Check cache validity in generated code. This is a fast case for
|
||||
// the JSObject::IsSimpleEnum cache validity checks. If we cannot
|
||||
// guarantee cache validity, call the runtime system to check cache
|
||||
// validity or get the property names in a fixed array.
|
||||
JumpTarget call_runtime;
|
||||
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
|
||||
JumpTarget check_prototype;
|
||||
JumpTarget use_cache;
|
||||
__ mov(ecx, eax);
|
||||
loop.Bind();
|
||||
// Check that there are no elements.
|
||||
__ mov(edx, FieldOperand(ecx, JSObject::kElementsOffset));
|
||||
__ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
|
||||
call_runtime.Branch(not_equal);
|
||||
// Check that instance descriptors are not empty so that we can
|
||||
// check for an enum cache. Leave the map in ebx for the subsequent
|
||||
// prototype load.
|
||||
__ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
|
||||
__ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
|
||||
__ cmp(Operand(edx), Immediate(Factory::empty_descriptor_array()));
|
||||
call_runtime.Branch(equal);
|
||||
// Check that there in an enum cache in the non-empty instance
|
||||
// descriptors. This is the case if the next enumeration index
|
||||
// field does not contain a smi.
|
||||
__ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
|
||||
__ test(edx, Immediate(kSmiTagMask));
|
||||
call_runtime.Branch(zero);
|
||||
// For all objects but the receiver, check that the cache is empty.
|
||||
__ cmp(ecx, Operand(eax));
|
||||
check_prototype.Branch(equal);
|
||||
__ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
||||
__ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
|
||||
call_runtime.Branch(not_equal);
|
||||
check_prototype.Bind();
|
||||
// Load the prototype from the map and loop if non-null.
|
||||
__ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
|
||||
__ cmp(Operand(ecx), Immediate(Factory::null_value()));
|
||||
loop.Branch(not_equal);
|
||||
// The enum cache is valid. Load the map of the object being
|
||||
// iterated over and use the cache for the iteration.
|
||||
__ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
use_cache.Jump();
|
||||
|
||||
call_runtime.Bind();
|
||||
// Call the runtime to get the property names for the object.
|
||||
frame_->EmitPush(eax); // push the Object (slot 4) for the runtime call
|
||||
frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
|
||||
|
||||
// If we got a Map, we can do a fast modification check.
|
||||
// Otherwise, we got a FixedArray, and we have to do a slow check.
|
||||
// If we got a map from the runtime call, we can do a fast
|
||||
// modification check. Otherwise, we got a fixed array, and we have
|
||||
// to do a slow check.
|
||||
// eax: map or fixed array (result from call to
|
||||
// Runtime::kGetPropertyNamesFast)
|
||||
__ mov(edx, Operand(eax));
|
||||
@ -3070,9 +3116,13 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
|
||||
__ cmp(ecx, Factory::meta_map());
|
||||
fixed_array.Branch(not_equal);
|
||||
|
||||
use_cache.Bind();
|
||||
// Get enum cache
|
||||
// eax: map (result from call to Runtime::kGetPropertyNamesFast)
|
||||
// eax: map (either the result from a call to
|
||||
// Runtime::kGetPropertyNamesFast or has been fetched directly from
|
||||
// the object)
|
||||
__ mov(ecx, Operand(eax));
|
||||
|
||||
__ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset));
|
||||
// Get the bridge array held in the enumeration index field.
|
||||
__ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
|
||||
|
@ -1662,8 +1662,54 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
|
||||
jsobject.Bind();
|
||||
// Get the set of properties (as a FixedArray or Map).
|
||||
// rax: value to be iterated over
|
||||
frame_->EmitPush(rax); // push the object being iterated over (slot 4)
|
||||
frame_->EmitPush(rax); // Push the object being iterated over.
|
||||
|
||||
|
||||
// Check cache validity in generated code. This is a fast case for
|
||||
// the JSObject::IsSimpleEnum cache validity checks. If we cannot
|
||||
// guarantee cache validity, call the runtime system to check cache
|
||||
// validity or get the property names in a fixed array.
|
||||
JumpTarget call_runtime;
|
||||
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
|
||||
JumpTarget check_prototype;
|
||||
JumpTarget use_cache;
|
||||
__ movq(rcx, rax);
|
||||
loop.Bind();
|
||||
// Check that there are no elements.
|
||||
__ movq(rdx, FieldOperand(rcx, JSObject::kElementsOffset));
|
||||
__ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
|
||||
call_runtime.Branch(not_equal);
|
||||
// Check that instance descriptors are not empty so that we can
|
||||
// check for an enum cache. Leave the map in ebx for the subsequent
|
||||
// prototype load.
|
||||
__ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
|
||||
__ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset));
|
||||
__ CompareRoot(rdx, Heap::kEmptyDescriptorArrayRootIndex);
|
||||
call_runtime.Branch(equal);
|
||||
// Check that there in an enum cache in the non-empty instance
|
||||
// descriptors. This is the case if the next enumeration index
|
||||
// field does not contain a smi.
|
||||
__ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
|
||||
is_smi = masm_->CheckSmi(rdx);
|
||||
call_runtime.Branch(is_smi);
|
||||
// For all objects but the receiver, check that the cache is empty.
|
||||
__ cmpq(rcx, rax);
|
||||
check_prototype.Branch(equal);
|
||||
__ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
||||
__ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
|
||||
call_runtime.Branch(not_equal);
|
||||
check_prototype.Bind();
|
||||
// Load the prototype from the map and loop if non-null.
|
||||
__ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
|
||||
__ CompareRoot(rcx, Heap::kNullValueRootIndex);
|
||||
loop.Branch(not_equal);
|
||||
// The enum cache is valid. Load the map of the object being
|
||||
// iterated over and use the cache for the iteration.
|
||||
__ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
|
||||
use_cache.Jump();
|
||||
|
||||
call_runtime.Bind();
|
||||
// Call the runtime to get the property names for the object.
|
||||
frame_->EmitPush(rax); // push the Object (slot 4) for the runtime call
|
||||
frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
|
||||
|
||||
@ -1676,8 +1722,11 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
|
||||
__ CompareRoot(rcx, Heap::kMetaMapRootIndex);
|
||||
fixed_array.Branch(not_equal);
|
||||
|
||||
use_cache.Bind();
|
||||
// Get enum cache
|
||||
// rax: map (result from call to Runtime::kGetPropertyNamesFast)
|
||||
// rax: map (either the result from a call to
|
||||
// Runtime::kGetPropertyNamesFast or has been fetched directly from
|
||||
// the object)
|
||||
__ movq(rcx, rax);
|
||||
__ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset));
|
||||
// Get the bridge array held in the enumeration index field.
|
||||
|
Loading…
Reference in New Issue
Block a user