Make setting length on arrays faster.
Review URL: http://codereview.chromium.org/647013 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3902 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
806c15e4b5
commit
f70dd176a6
@ -858,6 +858,53 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r0 : value
|
||||||
|
// -- r1 : receiver
|
||||||
|
// -- r2 : name
|
||||||
|
// -- lr : return address
|
||||||
|
// -----------------------------------
|
||||||
|
//
|
||||||
|
// This accepts as a receiver anything JSObject::SetElementsLength accepts
|
||||||
|
// (currently anything except for external and pixel arrays which means
|
||||||
|
// anything with elements of FixedArray type.), but currently is restricted
|
||||||
|
// to JSArray.
|
||||||
|
// Value must be a number, but only smis are accepted as the most common case.
|
||||||
|
|
||||||
|
Label miss;
|
||||||
|
|
||||||
|
Register receiver = r1;
|
||||||
|
Register value = r0;
|
||||||
|
Register scratch = r3;
|
||||||
|
|
||||||
|
// Check that the receiver isn't a smi.
|
||||||
|
__ BranchOnSmi(receiver, &miss);
|
||||||
|
|
||||||
|
// Check that the object is a JS array.
|
||||||
|
__ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
|
||||||
|
__ b(ne, &miss);
|
||||||
|
|
||||||
|
// Check that elements are FixedArray.
|
||||||
|
__ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
|
||||||
|
__ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
|
||||||
|
__ b(ne, &miss);
|
||||||
|
|
||||||
|
// Check that value is a smi.
|
||||||
|
__ BranchOnNotSmi(value, &miss);
|
||||||
|
|
||||||
|
// Prepare tail call to StoreIC_ArrayLength.
|
||||||
|
__ push(receiver);
|
||||||
|
__ push(value);
|
||||||
|
|
||||||
|
__ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_ArrayLength)), 2, 1);
|
||||||
|
|
||||||
|
__ bind(&miss);
|
||||||
|
|
||||||
|
GenerateMiss(masm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
|
|
||||||
|
@ -1079,6 +1079,11 @@ static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
|
||||||
|
StoreIC::GenerateArrayLength(masm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
|
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
|
||||||
KeyedStoreIC::GenerateGeneric(masm);
|
KeyedStoreIC::GenerateGeneric(masm);
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,7 @@ enum BuiltinExtraArguments {
|
|||||||
V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC) \
|
V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC) \
|
||||||
\
|
\
|
||||||
V(StoreIC_Initialize, STORE_IC, UNINITIALIZED) \
|
V(StoreIC_Initialize, STORE_IC, UNINITIALIZED) \
|
||||||
|
V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC) \
|
||||||
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \
|
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \
|
||||||
\
|
\
|
||||||
V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED) \
|
V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED) \
|
||||||
|
@ -1435,6 +1435,57 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : value
|
||||||
|
// -- ecx : name
|
||||||
|
// -- edx : receiver
|
||||||
|
// -- esp[0] : return address
|
||||||
|
// -----------------------------------
|
||||||
|
//
|
||||||
|
// This accepts as a receiver anything JSObject::SetElementsLength accepts
|
||||||
|
// (currently anything except for external and pixel arrays which means
|
||||||
|
// anything with elements of FixedArray type.), but currently is restricted
|
||||||
|
// to JSArray.
|
||||||
|
// Value must be a number, but only smis are accepted as the most common case.
|
||||||
|
|
||||||
|
Label miss;
|
||||||
|
|
||||||
|
Register receiver = edx;
|
||||||
|
Register value = eax;
|
||||||
|
Register scratch = ebx;
|
||||||
|
|
||||||
|
// Check that the receiver isn't a smi.
|
||||||
|
__ test(receiver, Immediate(kSmiTagMask));
|
||||||
|
__ j(zero, &miss, not_taken);
|
||||||
|
|
||||||
|
// Check that the object is a JS array.
|
||||||
|
__ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
|
||||||
|
__ j(not_equal, &miss, not_taken);
|
||||||
|
|
||||||
|
// Check that elements are FixedArray.
|
||||||
|
__ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
|
||||||
|
__ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
|
||||||
|
__ j(not_equal, &miss, not_taken);
|
||||||
|
|
||||||
|
// Check that value is a smi.
|
||||||
|
__ test(value, Immediate(kSmiTagMask));
|
||||||
|
__ j(not_zero, &miss, not_taken);
|
||||||
|
|
||||||
|
// Prepare tail call to StoreIC_ArrayLength.
|
||||||
|
__ pop(scratch);
|
||||||
|
__ push(receiver);
|
||||||
|
__ push(value);
|
||||||
|
__ push(scratch); // return address
|
||||||
|
|
||||||
|
__ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_ArrayLength)), 2, 1);
|
||||||
|
|
||||||
|
__ bind(&miss);
|
||||||
|
|
||||||
|
GenerateMiss(masm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Defined in ic.cc.
|
// Defined in ic.cc.
|
||||||
Object* KeyedStoreIC_Miss(Arguments args);
|
Object* KeyedStoreIC_Miss(Arguments args);
|
||||||
|
|
||||||
|
25
src/ic.cc
25
src/ic.cc
@ -1049,6 +1049,20 @@ Object* StoreIC::Store(State state,
|
|||||||
return *value;
|
return *value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Use specialized code for setting the length of arrays.
|
||||||
|
if (receiver->IsJSArray()
|
||||||
|
&& name->Equals(Heap::length_symbol())
|
||||||
|
&& receiver->AllowsSetElementsLength()) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
|
||||||
|
#endif
|
||||||
|
Code* target = Builtins::builtin(Builtins::StoreIC_ArrayLength);
|
||||||
|
set_target(target);
|
||||||
|
StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
|
||||||
|
return receiver->SetProperty(*name, *value, NONE);
|
||||||
|
}
|
||||||
|
|
||||||
// Lookup the property locally in the receiver.
|
// Lookup the property locally in the receiver.
|
||||||
if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
|
if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
|
||||||
LookupResult lookup;
|
LookupResult lookup;
|
||||||
@ -1344,6 +1358,17 @@ Object* StoreIC_Miss(Arguments args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Object* StoreIC_ArrayLength(Arguments args) {
|
||||||
|
NoHandleAllocation nha;
|
||||||
|
|
||||||
|
ASSERT(args.length() == 2);
|
||||||
|
JSObject* receiver = JSObject::cast(args[0]);
|
||||||
|
Object* len = args[1];
|
||||||
|
|
||||||
|
return receiver->SetElementsLength(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Extend storage is called in a store inline cache when
|
// Extend storage is called in a store inline cache when
|
||||||
// it is necessary to extend the properties array of a
|
// it is necessary to extend the properties array of a
|
||||||
// JSObject.
|
// JSObject.
|
||||||
|
2
src/ic.h
2
src/ic.h
@ -45,6 +45,7 @@ enum DictionaryCheck { CHECK_DICTIONARY, DICTIONARY_CHECK_DONE };
|
|||||||
ICU(KeyedLoadIC_Miss) \
|
ICU(KeyedLoadIC_Miss) \
|
||||||
ICU(CallIC_Miss) \
|
ICU(CallIC_Miss) \
|
||||||
ICU(StoreIC_Miss) \
|
ICU(StoreIC_Miss) \
|
||||||
|
ICU(StoreIC_ArrayLength) \
|
||||||
ICU(SharedStoreIC_ExtendStorage) \
|
ICU(SharedStoreIC_ExtendStorage) \
|
||||||
ICU(KeyedStoreIC_Miss) \
|
ICU(KeyedStoreIC_Miss) \
|
||||||
/* Utilities for IC stubs. */ \
|
/* Utilities for IC stubs. */ \
|
||||||
@ -358,6 +359,7 @@ class StoreIC: public IC {
|
|||||||
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
|
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
|
||||||
static void GenerateMiss(MacroAssembler* masm);
|
static void GenerateMiss(MacroAssembler* masm);
|
||||||
static void GenerateMegamorphic(MacroAssembler* masm);
|
static void GenerateMegamorphic(MacroAssembler* masm);
|
||||||
|
static void GenerateArrayLength(MacroAssembler* masm);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Update the inline cache and the global stub cache based on the
|
// Update the inline cache and the global stub cache based on the
|
||||||
|
@ -2773,6 +2773,13 @@ bool JSObject::HasIndexedInterceptor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool JSObject::AllowsSetElementsLength() {
|
||||||
|
bool result = elements()->IsFixedArray();
|
||||||
|
ASSERT(result == (!HasPixelElements() && !HasExternalArrayElements()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StringDictionary* JSObject::property_dictionary() {
|
StringDictionary* JSObject::property_dictionary() {
|
||||||
ASSERT(!HasFastProperties());
|
ASSERT(!HasFastProperties());
|
||||||
return StringDictionary::cast(properties());
|
return StringDictionary::cast(properties());
|
||||||
|
@ -5304,7 +5304,7 @@ static Object* ArrayLengthRangeError() {
|
|||||||
|
|
||||||
Object* JSObject::SetElementsLength(Object* len) {
|
Object* JSObject::SetElementsLength(Object* len) {
|
||||||
// We should never end in here with a pixel or external array.
|
// We should never end in here with a pixel or external array.
|
||||||
ASSERT(!HasPixelElements() && !HasExternalArrayElements());
|
ASSERT(AllowsSetElementsLength());
|
||||||
|
|
||||||
Object* smi_length = len->ToSmi();
|
Object* smi_length = len->ToSmi();
|
||||||
if (smi_length->IsSmi()) {
|
if (smi_length->IsSmi()) {
|
||||||
|
@ -1161,6 +1161,7 @@ class JSObject: public HeapObject {
|
|||||||
inline bool HasExternalIntElements();
|
inline bool HasExternalIntElements();
|
||||||
inline bool HasExternalUnsignedIntElements();
|
inline bool HasExternalUnsignedIntElements();
|
||||||
inline bool HasExternalFloatElements();
|
inline bool HasExternalFloatElements();
|
||||||
|
inline bool AllowsSetElementsLength();
|
||||||
inline NumberDictionary* element_dictionary(); // Gets slow elements.
|
inline NumberDictionary* element_dictionary(); // Gets slow elements.
|
||||||
|
|
||||||
// Collects elements starting at index 0.
|
// Collects elements starting at index 0.
|
||||||
|
@ -1408,6 +1408,55 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- rax : value
|
||||||
|
// -- rcx : name
|
||||||
|
// -- rdx : receiver
|
||||||
|
// -- rsp[0] : return address
|
||||||
|
// -----------------------------------
|
||||||
|
//
|
||||||
|
// This accepts as a receiver anything JSObject::SetElementsLength accepts
|
||||||
|
// (currently anything except for external and pixel arrays which means
|
||||||
|
// anything with elements of FixedArray type.), but currently is restricted
|
||||||
|
// to JSArray.
|
||||||
|
// Value must be a number, but only smis are accepted as the most common case.
|
||||||
|
|
||||||
|
Label miss;
|
||||||
|
|
||||||
|
Register receiver = rdx;
|
||||||
|
Register value = rax;
|
||||||
|
Register scratch = rbx;
|
||||||
|
|
||||||
|
// Check that the receiver isn't a smi.
|
||||||
|
__ JumpIfSmi(receiver, &miss);
|
||||||
|
|
||||||
|
// Check that the object is a JS array.
|
||||||
|
__ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
|
||||||
|
__ j(not_equal, &miss);
|
||||||
|
|
||||||
|
// Check that elements are FixedArray.
|
||||||
|
__ movq(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
|
||||||
|
__ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
|
||||||
|
__ j(not_equal, &miss);
|
||||||
|
|
||||||
|
// Check that value is a smi.
|
||||||
|
__ JumpIfNotSmi(value, &miss);
|
||||||
|
|
||||||
|
// Prepare tail call to StoreIC_ArrayLength.
|
||||||
|
__ pop(scratch);
|
||||||
|
__ push(receiver);
|
||||||
|
__ push(value);
|
||||||
|
__ push(scratch); // return address
|
||||||
|
|
||||||
|
__ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_ArrayLength)), 2, 1);
|
||||||
|
|
||||||
|
__ bind(&miss);
|
||||||
|
|
||||||
|
GenerateMiss(masm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user