Improve keyed loads on strings by using a new stub.

Instead of going through a runtime function for keyed loads
on strings we invoke a separate specialized stub that
assumes string as receiver type and the key to be a number.

The stub calls a JS builtin function to return the corresponding one-character string.


Review URL: http://codereview.chromium.org/521041

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3556 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 33079fb8
...@@ -544,6 +544,11 @@ static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) { ...@@ -544,6 +544,11 @@ static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
} }
static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
KeyedLoadIC::GenerateString(masm);
}
static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) { static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray); KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
} }
......
...@@ -74,6 +74,7 @@ namespace internal { ...@@ -74,6 +74,7 @@ namespace internal {
V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED) \ V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED) \
V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \ V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \
V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \ V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_ExternalByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \ V(KeyedLoadIC_ExternalByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_ExternalUnsignedByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \ V(KeyedLoadIC_ExternalUnsignedByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_ExternalShortArray, KEYED_LOAD_IC, MEGAMORPHIC) \ V(KeyedLoadIC_ExternalShortArray, KEYED_LOAD_IC, MEGAMORPHIC) \
...@@ -147,7 +148,8 @@ namespace internal { ...@@ -147,7 +148,8 @@ namespace internal {
V(STRING_ADD_LEFT, 1) \ V(STRING_ADD_LEFT, 1) \
V(STRING_ADD_RIGHT, 1) \ V(STRING_ADD_RIGHT, 1) \
V(APPLY_PREPARE, 1) \ V(APPLY_PREPARE, 1) \
V(APPLY_OVERFLOW, 1) V(APPLY_OVERFLOW, 1) \
V(STRING_CHAR_AT, 1)
class ObjectVisitor; class ObjectVisitor;
......
...@@ -391,6 +391,48 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -391,6 +391,48 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
} }
void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- esp[0] : return address
// -- esp[4] : key
// -- esp[8] : receiver
// -----------------------------------
Label miss, index_ok;
// Pop return address.
// Performing the load early is better in the common case.
__ pop(eax);
__ mov(ebx, Operand(esp, 1 * kPointerSize));
__ test(ebx, Immediate(kSmiTagMask));
__ j(zero, &miss);
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ test(ecx, Immediate(kIsNotStringMask));
__ j(not_zero, &miss);
// Check if key is a smi or a heap number.
__ mov(edx, Operand(esp, 0));
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &index_ok);
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
__ cmp(ecx, Factory::heap_number_map());
__ j(not_equal, &miss);
__ bind(&index_ok);
// Duplicate receiver and key since they are expected on the stack after
// the KeyedLoadIC call.
__ push(ebx); // receiver
__ push(edx); // key
__ push(eax); // return address
__ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_FUNCTION);
__ bind(&miss);
__ push(eax);
GenerateMiss(masm);
}
void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
ExternalArrayType array_type) { ExternalArrayType array_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
......
...@@ -874,7 +874,9 @@ Object* KeyedLoadIC::Load(State state, ...@@ -874,7 +874,9 @@ Object* KeyedLoadIC::Load(State state,
if (use_ic) { if (use_ic) {
Code* stub = generic_stub(); Code* stub = generic_stub();
if (object->IsJSObject()) { if (object->IsString() && key->IsNumber()) {
stub = string_stub();
} else if (object->IsJSObject()) {
Handle<JSObject> receiver = Handle<JSObject>::cast(object); Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (receiver->HasExternalArrayElements()) { if (receiver->HasExternalArrayElements()) {
stub = external_array_stub(receiver->GetElementsKind()); stub = external_array_stub(receiver->GetElementsKind());
......
...@@ -280,6 +280,7 @@ class KeyedLoadIC: public IC { ...@@ -280,6 +280,7 @@ class KeyedLoadIC: public IC {
static void GenerateInitialize(MacroAssembler* masm); static void GenerateInitialize(MacroAssembler* masm);
static void GeneratePreMonomorphic(MacroAssembler* masm); static void GeneratePreMonomorphic(MacroAssembler* masm);
static void GenerateGeneric(MacroAssembler* masm); static void GenerateGeneric(MacroAssembler* masm);
static void GenerateString(MacroAssembler* masm);
// Generators for external array types. See objects.h. // Generators for external array types. See objects.h.
// These are similar to the generic IC; they optimize the case of // These are similar to the generic IC; they optimize the case of
...@@ -313,6 +314,9 @@ class KeyedLoadIC: public IC { ...@@ -313,6 +314,9 @@ class KeyedLoadIC: public IC {
static Code* pre_monomorphic_stub() { static Code* pre_monomorphic_stub() {
return Builtins::builtin(Builtins::KeyedLoadIC_PreMonomorphic); return Builtins::builtin(Builtins::KeyedLoadIC_PreMonomorphic);
} }
static Code* string_stub() {
return Builtins::builtin(Builtins::KeyedLoadIC_String);
}
static Code* external_array_stub(JSObject::ElementsKind elements_kind); static Code* external_array_stub(JSObject::ElementsKind elements_kind);
static void Clear(Address address, Code* target); static void Clear(Address address, Code* target);
......
...@@ -1384,6 +1384,17 @@ static Object* CharCodeAt(String* subject, Object* index) { ...@@ -1384,6 +1384,17 @@ static Object* CharCodeAt(String* subject, Object* index) {
} }
static Object* CharFromCode(Object* char_code) {
uint32_t code;
if (Array::IndexFromObject(char_code, &code)) {
if (code <= 0xffff) {
return Heap::LookupSingleCharacterStringFromCode(code);
}
}
return Heap::empty_string();
}
static Object* Runtime_StringCharCodeAt(Arguments args) { static Object* Runtime_StringCharCodeAt(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
...@@ -1394,16 +1405,17 @@ static Object* Runtime_StringCharCodeAt(Arguments args) { ...@@ -1394,16 +1405,17 @@ static Object* Runtime_StringCharCodeAt(Arguments args) {
} }
static Object* Runtime_StringCharAt(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
return CharFromCode(Runtime_StringCharCodeAt(args));
}
static Object* Runtime_CharFromCode(Arguments args) { static Object* Runtime_CharFromCode(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
uint32_t code; return CharFromCode(args[0]);
if (Array::IndexFromObject(args[0], &code)) {
if (code <= 0xffff) {
return Heap::LookupSingleCharacterStringFromCode(code);
}
}
return Heap::empty_string();
} }
// Forward declarations. // Forward declarations.
......
...@@ -146,6 +146,7 @@ namespace internal { ...@@ -146,6 +146,7 @@ namespace internal {
\ \
/* Strings */ \ /* Strings */ \
F(StringCharCodeAt, 2, 1) \ F(StringCharCodeAt, 2, 1) \
F(StringCharAt, 2, 1) \
F(StringIndexOf, 3, 1) \ F(StringIndexOf, 3, 1) \
F(StringLastIndexOf, 3, 1) \ F(StringLastIndexOf, 3, 1) \
F(StringLocaleCompare, 2, 1) \ F(StringLocaleCompare, 2, 1) \
......
...@@ -477,6 +477,17 @@ function TO_STRING() { ...@@ -477,6 +477,17 @@ function TO_STRING() {
} }
// Specialized version of String.charAt. It assumes string as
// the receiver type and that the index is a number.
function STRING_CHAR_AT(pos) {
var char_code = %_FastCharCodeAt(this, pos);
if (!%_IsSmi(char_code)) {
return %StringCharAt(this, pos);
}
return %CharFromCode(char_code);
}
/* ------------------------------------- /* -------------------------------------
- - - C o n v e r s i o n s - - - - - - C o n v e r s i o n s - - -
------------------------------------- -------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment