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
This commit is contained in:
fschneider@chromium.org 2010-01-07 10:25:20 +00:00
parent 33079fb851
commit 903301248e
8 changed files with 88 additions and 9 deletions

View File

@ -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) {
KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
}

View File

@ -74,6 +74,7 @@ namespace internal {
V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED) \
V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \
V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_ExternalByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_ExternalUnsignedByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_ExternalShortArray, KEYED_LOAD_IC, MEGAMORPHIC) \
@ -147,7 +148,8 @@ namespace internal {
V(STRING_ADD_LEFT, 1) \
V(STRING_ADD_RIGHT, 1) \
V(APPLY_PREPARE, 1) \
V(APPLY_OVERFLOW, 1)
V(APPLY_OVERFLOW, 1) \
V(STRING_CHAR_AT, 1)
class ObjectVisitor;

View File

@ -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,
ExternalArrayType array_type) {
// ----------- S t a t e -------------

View File

@ -874,7 +874,9 @@ Object* KeyedLoadIC::Load(State state,
if (use_ic) {
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);
if (receiver->HasExternalArrayElements()) {
stub = external_array_stub(receiver->GetElementsKind());

View File

@ -280,6 +280,7 @@ class KeyedLoadIC: public IC {
static void GenerateInitialize(MacroAssembler* masm);
static void GeneratePreMonomorphic(MacroAssembler* masm);
static void GenerateGeneric(MacroAssembler* masm);
static void GenerateString(MacroAssembler* masm);
// Generators for external array types. See objects.h.
// These are similar to the generic IC; they optimize the case of
@ -313,6 +314,9 @@ class KeyedLoadIC: public IC {
static Code* pre_monomorphic_stub() {
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 void Clear(Address address, Code* target);

View File

@ -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) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@ -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) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
uint32_t code;
if (Array::IndexFromObject(args[0], &code)) {
if (code <= 0xffff) {
return Heap::LookupSingleCharacterStringFromCode(code);
}
}
return Heap::empty_string();
return CharFromCode(args[0]);
}
// Forward declarations.

View File

@ -146,6 +146,7 @@ namespace internal {
\
/* Strings */ \
F(StringCharCodeAt, 2, 1) \
F(StringCharAt, 2, 1) \
F(StringIndexOf, 3, 1) \
F(StringLastIndexOf, 3, 1) \
F(StringLocaleCompare, 2, 1) \

View File

@ -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 - - -
-------------------------------------