From 903301248e3afb6b237aa84e96689cf6f988ba06 Mon Sep 17 00:00:00 2001 From: "fschneider@chromium.org" Date: Thu, 7 Jan 2010 10:25:20 +0000 Subject: [PATCH] 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 --- src/builtins.cc | 5 +++++ src/builtins.h | 4 +++- src/ia32/ic-ia32.cc | 42 ++++++++++++++++++++++++++++++++++++++++++ src/ic.cc | 4 +++- src/ic.h | 4 ++++ src/runtime.cc | 26 +++++++++++++++++++------- src/runtime.h | 1 + src/runtime.js | 11 +++++++++++ 8 files changed, 88 insertions(+), 9 deletions(-) diff --git a/src/builtins.cc b/src/builtins.cc index b66635c..aa680d7 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -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); } diff --git a/src/builtins.h b/src/builtins.h index bc32c49..f0ceab6 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -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; diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index 58fe2dc..91950dc 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -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 ------------- diff --git a/src/ic.cc b/src/ic.cc index 2661a10..4edf6f1 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -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 receiver = Handle::cast(object); if (receiver->HasExternalArrayElements()) { stub = external_array_stub(receiver->GetElementsKind()); diff --git a/src/ic.h b/src/ic.h index f53c6dd..1dd7edf 100644 --- a/src/ic.h +++ b/src/ic.h @@ -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); diff --git a/src/runtime.cc b/src/runtime.cc index 28f0b15..2f1a025 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -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. diff --git a/src/runtime.h b/src/runtime.h index 5a2a9d2..a06b970 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -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) \ diff --git a/src/runtime.js b/src/runtime.js index 1a9c96c..9351a23 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -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 - - - ------------------------------------- -- 2.7.4