Revision: 6472
Author: [email protected]
Date: Tue Jan 25 07:51:10 2011
Log: Support StringLength in hydrogen (similar to ArrayLength).
To avoid deopts a few extra changes were needed:
o Enable megamorphic state for special property loads on
primitives. We used to flip between monomorphic stubs.
o Extract pure string (no string wrapper support) version of the
string length stub.
Review URL: http://codereview.chromium.org/6334015
http://code.google.com/p/v8/source/detail?r=6472
Modified:
/branches/bleeding_edge/src/arm/ic-arm.cc
/branches/bleeding_edge/src/arm/stub-cache-arm.cc
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/builtins.cc
/branches/bleeding_edge/src/builtins.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/ic-ia32.cc
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/ic.h
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/x64/ic-x64.cc
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc Tue Jan 25 06:52:35 2011
+++ /branches/bleeding_edge/src/arm/ic-arm.cc Tue Jan 25 07:51:10 2011
@@ -379,7 +379,7 @@
}
-void LoadIC::GenerateStringLength(MacroAssembler* masm) {
+void LoadIC::GenerateStringLength(MacroAssembler* masm, bool
support_wrappers) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
@@ -388,7 +388,8 @@
// -----------------------------------
Label miss;
- StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss);
+ StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
+ support_wrappers);
// Cache miss: Jump to runtime.
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Fri Jan 21 15:58:00
2011
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Jan 25 07:51:10
2011
@@ -370,27 +370,31 @@
Register receiver,
Register scratch1,
Register scratch2,
- Label* miss) {
+ Label* miss,
+ bool support_wrappers) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch1 register.
- GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
&check_wrapper);
+ GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
+ support_wrappers ? &check_wrapper : miss);
// Load length directly from the string.
__ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
__ Ret();
- // Check if the object is a JSValue wrapper.
- __ bind(&check_wrapper);
- __ cmp(scratch1, Operand(JS_VALUE_TYPE));
- __ b(ne, miss);
-
- // Unwrap the value and check if the wrapped value is a string.
- __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
- GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
- __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
- __ Ret();
+ if (support_wrappers) {
+ // Check if the object is a JSValue wrapper.
+ __ bind(&check_wrapper);
+ __ cmp(scratch1, Operand(JS_VALUE_TYPE));
+ __ b(ne, miss);
+
+ // Unwrap the value and check if the wrapped value is a string.
+ __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
+ GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
+ __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
+ __ Ret();
+ }
}
@@ -2995,7 +2999,7 @@
__ cmp(r0, Operand(Handle<String>(name)));
__ b(ne, &miss);
- GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
+ GenerateLoadStringLength(masm(), r1, r2, r3, &miss, true);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_string_length, 1, r2, r3);
=======================================
--- /branches/bleeding_edge/src/ast.cc Tue Jan 25 04:21:03 2011
+++ /branches/bleeding_edge/src/ast.cc Tue Jan 25 07:51:10 2011
@@ -521,6 +521,8 @@
if (key()->IsPropertyName()) {
if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_ArrayLength)) {
is_array_length_ = true;
+ } else if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_StringLength))
{
+ is_string_length_ = true;
} else if (oracle->LoadIsBuiltin(this,
Builtins::LoadIC_FunctionPrototype)) {
is_function_prototype_ = true;
=======================================
--- /branches/bleeding_edge/src/ast.h Thu Jan 20 10:51:47 2011
+++ /branches/bleeding_edge/src/ast.h Tue Jan 25 07:51:10 2011
@@ -1205,9 +1205,10 @@
key_(key),
pos_(pos),
type_(type),
- is_monomorphic_(false),
receiver_types_(NULL),
+ is_monomorphic_(false),
is_array_length_(false),
+ is_string_length_(false),
is_function_prototype_(false),
is_arguments_access_(false) { }
@@ -1221,6 +1222,7 @@
int position() const { return pos_; }
bool is_synthetic() const { return type_ == SYNTHETIC; }
+ bool IsStringLength() const { return is_string_length_; }
bool IsFunctionPrototype() const { return is_function_prototype_; }
// Marks that this is actually an argument rewritten to a keyed property
@@ -1249,11 +1251,12 @@
int pos_;
Type type_;
- bool is_monomorphic_;
ZoneMapList* receiver_types_;
- bool is_array_length_;
- bool is_function_prototype_;
- bool is_arguments_access_;
+ bool is_monomorphic_ : 1;
+ bool is_array_length_ : 1;
+ bool is_string_length_ : 1;
+ bool is_function_prototype_ : 1;
+ bool is_arguments_access_ : 1;
Handle<Map> monomorphic_receiver_type_;
// Dummy property used during preparsing.
=======================================
--- /branches/bleeding_edge/src/builtins.cc Fri Jan 21 15:58:00 2011
+++ /branches/bleeding_edge/src/builtins.cc Tue Jan 25 07:51:10 2011
@@ -1228,7 +1228,12 @@
static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
- LoadIC::GenerateStringLength(masm);
+ LoadIC::GenerateStringLength(masm, false);
+}
+
+
+static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) {
+ LoadIC::GenerateStringLength(masm, true);
}
=======================================
--- /branches/bleeding_edge/src/builtins.h Fri Jan 21 15:58:00 2011
+++ /branches/bleeding_edge/src/builtins.h Tue Jan 25 07:51:10 2011
@@ -86,6 +86,7 @@
V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \
V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \
V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \
+ V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC) \
V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \
V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \
\
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Thu Jan 20 04:56:34 2011
+++ /branches/bleeding_edge/src/hydrogen.cc Tue Jan 25 07:51:10 2011
@@ -3766,6 +3766,14 @@
AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE,
JS_ARRAY_TYPE));
instr = new HJSArrayLength(array);
+ } else if (expr->IsStringLength()) {
+ HValue* string = Pop();
+ AddInstruction(new HCheckNonSmi(string));
+ AddInstruction(new HCheckInstanceType(string,
+ FIRST_STRING_TYPE,
+ LAST_STRING_TYPE));
+ instr = new HStringLength(string);
+
} else if (expr->IsFunctionPrototype()) {
HValue* function = Pop();
AddInstruction(new HCheckNonSmi(function));
=======================================
--- /branches/bleeding_edge/src/ia32/ic-ia32.cc Fri Jan 21 15:58:00 2011
+++ /branches/bleeding_edge/src/ia32/ic-ia32.cc Tue Jan 25 07:51:10 2011
@@ -388,7 +388,8 @@
}
-void LoadIC::GenerateStringLength(MacroAssembler* masm) {
+void LoadIC::GenerateStringLength(MacroAssembler* masm,
+ bool support_wrappers) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
@@ -396,7 +397,8 @@
// -----------------------------------
Label miss;
- StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
+ StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss,
+ support_wrappers);
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
}
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Fri Jan 21 15:58:00
2011
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Jan 25 07:51:10
2011
@@ -327,28 +327,32 @@
Register receiver,
Register scratch1,
Register scratch2,
- Label* miss) {
+ Label* miss,
+ bool support_wrappers) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch register.
- GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
+ GenerateStringCheck(masm, receiver, scratch1, miss,
+ support_wrappers ? &check_wrapper : miss);
// Load length from the string and convert to a smi.
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
__ ret(0);
- // Check if the object is a JSValue wrapper.
- __ bind(&check_wrapper);
- __ cmp(scratch1, JS_VALUE_TYPE);
- __ j(not_equal, miss, not_taken);
-
- // Check if the wrapped value is a string and load the length
- // directly if it is.
- __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
- GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
- __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
- __ ret(0);
+ if (support_wrappers) {
+ // Check if the object is a JSValue wrapper.
+ __ bind(&check_wrapper);
+ __ cmp(scratch1, JS_VALUE_TYPE);
+ __ j(not_equal, miss, not_taken);
+
+ // Check if the wrapped value is a string and load the length
+ // directly if it is.
+ __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
+ GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
+ __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
+ __ ret(0);
+ }
}
@@ -3089,7 +3093,7 @@
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
- GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss);
+ GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_string_length, 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
=======================================
--- /branches/bleeding_edge/src/ic.cc Tue Jan 25 06:52:35 2011
+++ /branches/bleeding_edge/src/ic.cc Tue Jan 25 07:51:10 2011
@@ -822,6 +822,9 @@
}
if (FLAG_use_ic) {
+ Code* non_monomorphic_stub =
+ (state == UNINITIALIZED) ? pre_monomorphic_stub() :
megamorphic_stub();
+
// Use specialized code for getting the length of strings and
// string wrapper objects. The length property of string wrapper
// objects is read-only and therefore always returns the length of
@@ -829,22 +832,27 @@
if ((object->IsString() || object->IsStringWrapper()) &&
name->Equals(Heap::length_symbol())) {
HandleScope scope;
- // Get the string if we have a string wrapper object.
- if (object->IsJSValue()) {
- object = Handle<Object>(Handle<JSValue>::cast(object)->value());
- }
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
#endif
- Map* map = HeapObject::cast(*object)->map();
- if (object->IsString()) {
- const int offset = String::kLengthOffset;
- PatchInlinedLoad(address(), map, offset);
- }
-
- Code* target = NULL;
- target = Builtins::builtin(Builtins::LoadIC_StringLength);
- set_target(target);
+ if (state == PREMONOMORPHIC) {
+ if (object->IsString()) {
+ Map* map = HeapObject::cast(*object)->map();
+ const int offset = String::kLengthOffset;
+ PatchInlinedLoad(address(), map, offset);
+ set_target(Builtins::builtin(Builtins::LoadIC_StringLength));
+ } else {
+
set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength));
+ }
+ } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
+
set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength));
+ } else {
+ set_target(non_monomorphic_stub);
+ }
+ // Get the string if we have a string wrapper object.
+ if (object->IsJSValue()) {
+ object = Handle<Object>(Handle<JSValue>::cast(object)->value());
+ }
return Smi::FromInt(String::cast(*object)->length());
}
@@ -853,12 +861,14 @@
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
#endif
- Map* map = HeapObject::cast(*object)->map();
- const int offset = JSArray::kLengthOffset;
- PatchInlinedLoad(address(), map, offset);
-
- Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength);
- set_target(target);
+ if (state == PREMONOMORPHIC) {
+ Map* map = HeapObject::cast(*object)->map();
+ const int offset = JSArray::kLengthOffset;
+ PatchInlinedLoad(address(), map, offset);
+ set_target(Builtins::builtin(Builtins::LoadIC_ArrayLength));
+ } else {
+ set_target(non_monomorphic_stub);
+ }
return JSArray::cast(*object)->length();
}
@@ -868,8 +878,11 @@
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
#endif
- Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype);
- set_target(target);
+ if (state == PREMONOMORPHIC) {
+ set_target(Builtins::builtin(Builtins::LoadIC_FunctionPrototype));
+ } else {
+ set_target(non_monomorphic_stub);
+ }
return Accessors::FunctionGetPrototype(*object, 0);
}
}
@@ -1092,6 +1105,8 @@
}
if (FLAG_use_ic) {
+ // TODO(1073): don't ignore the current stub state.
+
// Use specialized code for getting the length of strings.
if (object->IsString() && name->Equals(Heap::length_symbol())) {
Handle<String> string = Handle<String>::cast(object);
=======================================
--- /branches/bleeding_edge/src/ic.h Fri Jan 21 15:58:00 2011
+++ /branches/bleeding_edge/src/ic.h Tue Jan 25 07:51:10 2011
@@ -284,7 +284,8 @@
// Specialized code generator routines.
static void GenerateArrayLength(MacroAssembler* masm);
- static void GenerateStringLength(MacroAssembler* masm);
+ static void GenerateStringLength(MacroAssembler* masm,
+ bool support_wrappers);
static void GenerateFunctionPrototype(MacroAssembler* masm);
// Clear the use of the inlined version.
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Fri Jan 21 15:58:00 2011
+++ /branches/bleeding_edge/src/stub-cache.h Tue Jan 25 07:51:10 2011
@@ -427,7 +427,8 @@
Register receiver,
Register scratch1,
Register scratch2,
- Label* miss_label);
+ Label* miss_label,
+ bool support_wrappers);
static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
=======================================
--- /branches/bleeding_edge/src/x64/ic-x64.cc Fri Jan 21 15:58:00 2011
+++ /branches/bleeding_edge/src/x64/ic-x64.cc Tue Jan 25 07:51:10 2011
@@ -397,7 +397,7 @@
}
-void LoadIC::GenerateStringLength(MacroAssembler* masm) {
+void LoadIC::GenerateStringLength(MacroAssembler* masm, bool
support_wrappers) {
// ----------- S t a t e -------------
// -- rax : receiver
// -- rcx : name
@@ -405,7 +405,8 @@
// -----------------------------------
Label miss;
- StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss);
+ StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss,
+ support_wrappers);
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
}
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Fri Jan 21 15:58:00
2011
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Jan 25 07:51:10
2011
@@ -307,28 +307,32 @@
Register receiver,
Register scratch1,
Register scratch2,
- Label* miss) {
+ Label* miss,
+ bool support_wrappers) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch register.
- GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
+ GenerateStringCheck(masm, receiver, scratch1, miss,
+ support_wrappers ? &check_wrapper : miss);
// Load length directly from the string.
__ movq(rax, FieldOperand(receiver, String::kLengthOffset));
__ ret(0);
- // Check if the object is a JSValue wrapper.
- __ bind(&check_wrapper);
- __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
- __ j(not_equal, miss);
-
- // Check if the wrapped value is a string and load the length
- // directly if it is.
- __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
- GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
- __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
- __ ret(0);
+ if (support_wrappers) {
+ // Check if the object is a JSValue wrapper.
+ __ bind(&check_wrapper);
+ __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
+ __ j(not_equal, miss);
+
+ // Check if the wrapped value is a string and load the length
+ // directly if it is.
+ __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
+ GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
+ __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
+ __ ret(0);
+ }
}
@@ -2933,7 +2937,7 @@
__ Cmp(rax, Handle<String>(name));
__ j(not_equal, &miss);
- GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss);
+ GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_string_length, 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev