Revision: 16709
Author: [email protected]
Date: Fri Sep 13 09:57:48 2013 UTC
Log: Use regular map-checks to guard string-length loading.
[email protected]
Review URL: https://chromiumcodereview.appspot.com/23702039
http://code.google.com/p/v8/source/detail?r=16709
Modified:
/branches/bleeding_edge/src/arm/code-stubs-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/code-stubs.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/mips/code-stubs-mips.cc
/branches/bleeding_edge/src/mips/stub-cache-mips.cc
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/x64/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Sep 12 17:59:41
2013 UTC
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Fri Sep 13 09:57:48
2013 UTC
@@ -3375,8 +3375,7 @@
receiver = r0;
}
- StubCompiler::GenerateLoadStringLength(masm, receiver, r3, r4, &miss,
- support_wrapper_);
+ StubCompiler::GenerateLoadStringLength(masm, receiver, r3, r4, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Thu Sep 12 14:32:14
2013 UTC
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Fri Sep 13 09:57:48
2013 UTC
@@ -380,31 +380,27 @@
Register receiver,
Register scratch1,
Register scratch2,
- Label* miss,
- bool support_wrappers) {
+ Label* miss) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch1 register.
- GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
- support_wrappers ? &check_wrapper : miss);
+ GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
&check_wrapper);
// Load length directly from the string.
__ ldr(r0, FieldMemOperand(receiver, 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);
+ // 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();
- }
+ // 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();
}
=======================================
--- /branches/bleeding_edge/src/ast.cc Tue Sep 10 14:30:36 2013 UTC
+++ /branches/bleeding_edge/src/ast.cc Fri Sep 13 09:57:48 2013 UTC
@@ -460,10 +460,7 @@
receiver_types_.Clear();
if (key()->IsPropertyName()) {
FunctionPrototypeStub proto_stub(Code::LOAD_IC);
- StringLengthStub string_stub(Code::LOAD_IC, false);
- if (oracle->LoadIsStub(this, &string_stub)) {
- is_string_length_ = true;
- } else if (oracle->LoadIsStub(this, &proto_stub)) {
+ if (oracle->LoadIsStub(this, &proto_stub)) {
is_function_prototype_ = true;
} else {
Literal* lit_key = key()->AsLiteral();
=======================================
--- /branches/bleeding_edge/src/ast.h Fri Sep 6 11:32:46 2013 UTC
+++ /branches/bleeding_edge/src/ast.h Fri Sep 13 09:57:48 2013 UTC
@@ -1646,7 +1646,6 @@
BailoutId LoadId() const { return load_id_; }
- bool IsStringLength() const { return is_string_length_; }
bool IsStringAccess() const { return is_string_access_; }
bool IsFunctionPrototype() const { return is_function_prototype_; }
@@ -1674,7 +1673,6 @@
load_id_(GetNextId(isolate)),
is_monomorphic_(false),
is_uninitialized_(false),
- is_string_length_(false),
is_string_access_(false),
is_function_prototype_(false) { }
@@ -1687,7 +1685,6 @@
SmallMapList receiver_types_;
bool is_monomorphic_ : 1;
bool is_uninitialized_ : 1;
- bool is_string_length_ : 1;
bool is_string_access_ : 1;
bool is_function_prototype_ : 1;
};
=======================================
--- /branches/bleeding_edge/src/code-stubs.h Thu Sep 12 17:59:41 2013 UTC
+++ /branches/bleeding_edge/src/code-stubs.h Fri Sep 13 09:57:48 2013 UTC
@@ -830,19 +830,12 @@
class StringLengthStub: public ICStub {
public:
- StringLengthStub(Code::Kind kind, bool support_wrapper)
- : ICStub(kind), support_wrapper_(support_wrapper) { }
+ explicit StringLengthStub(Code::Kind kind) : ICStub(kind) { }
virtual void Generate(MacroAssembler* masm);
private:
STATIC_ASSERT(KindBits::kSize == 4);
- class WrapperModeBits: public BitField<bool, 4, 1> {};
- virtual CodeStub::Major MajorKey() { return StringLength; }
- virtual int MinorKey() {
- return KindBits::encode(kind()) |
WrapperModeBits::encode(support_wrapper_);
- }
-
- bool support_wrapper_;
+ virtual CodeStub::Major MajorKey() { return StringLength; }
};
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Fri Sep 13 09:51:11 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc Fri Sep 13 09:57:48 2013 UTC
@@ -5135,9 +5135,7 @@
CHECK_ALIVE(VisitForValue(prop->obj()));
HValue* object = Top();
HValue* key = NULL;
- if ((!prop->IsStringLength() &&
- !prop->IsFunctionPrototype() &&
- !prop->key()->IsPropertyName()) ||
+ if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
prop->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(prop->key()));
key = Top();
@@ -5825,19 +5823,22 @@
if (key != NULL) Push(key);
BuildLoad(expr, position, expr->LoadId());
}
+
+
+static bool AreStringTypes(SmallMapList* types) {
+ if (types == NULL || types->length() == 0) return false;
+ for (int i = 0; i < types->length(); i++) {
+ if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return
false;
+ }
+ return true;
+}
void HOptimizedGraphBuilder::BuildLoad(Property* expr,
int position,
BailoutId ast_id) {
HInstruction* instr = NULL;
- if (expr->IsStringLength()) {
- HValue* string = Pop();
- BuildCheckHeapObject(string);
- HInstruction* checkstring =
- AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
- instr = BuildLoadStringLength(string, checkstring);
- } else if (expr->IsStringAccess()) {
+ if (expr->IsStringAccess()) {
HValue* index = Pop();
HValue* string = Pop();
HValue* context = environment()->context();
@@ -5873,6 +5874,12 @@
} else {
instr = BuildLoadNamedMonomorphic(Pop(), name, map);
}
+ } else if (AreStringTypes(types) &&
+ name->Equals(isolate()->heap()->length_string())) {
+ BuildCheckHeapObject(Pop());
+ HValue* checked_object =
+ AddInstruction(HCheckInstanceType::NewIsString(object, zone()));
+ instr = BuildLoadStringLength(object, checked_object);
} else if (types != NULL && types->length() > 1) {
return HandlePolymorphicLoadNamedField(
position, ast_id, Pop(), types, name);
@@ -5913,9 +5920,7 @@
if (TryArgumentsAccess(expr)) return;
CHECK_ALIVE(VisitForValue(expr->obj()));
- if ((!expr->IsStringLength() &&
- !expr->IsFunctionPrototype() &&
- !expr->key()->IsPropertyName()) ||
+ if ((!expr->IsFunctionPrototype() && !expr->key()->IsPropertyName()) ||
expr->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(expr->key()));
}
@@ -7566,9 +7571,7 @@
HValue* object = Top();
HValue* key = NULL;
- if ((!prop->IsStringLength() &&
- !prop->IsFunctionPrototype() &&
- !prop->key()->IsPropertyName()) ||
+ if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
prop->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(prop->key()));
key = Top();
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Fri Sep 13 07:59:48
2013 UTC
+++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Fri Sep 13 09:57:48
2013 UTC
@@ -2756,8 +2756,7 @@
__ j(not_equal, &miss);
}
- StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss,
- support_wrapper_);
+ StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(
masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Fri Sep 13 07:59:48
2013 UTC
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Fri Sep 13 09:57:48
2013 UTC
@@ -329,32 +329,28 @@
Register receiver,
Register scratch1,
Register scratch2,
- Label* miss,
- bool support_wrappers) {
+ Label* miss) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch register.
- GenerateStringCheck(masm, receiver, scratch1, miss,
- support_wrappers ? &check_wrapper : miss);
+ GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
// Load length from the string and convert to a smi.
__ mov(eax, FieldOperand(receiver, 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);
+ // Check if the object is a JSValue wrapper.
+ __ bind(&check_wrapper);
+ __ cmp(scratch1, JS_VALUE_TYPE);
+ __ j(not_equal, miss);
- // 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);
- }
+ // 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);
}
=======================================
--- /branches/bleeding_edge/src/ic.cc Thu Sep 12 22:04:04 2013 UTC
+++ /branches/bleeding_edge/src/ic.cc Fri Sep 13 09:57:48 2013 UTC
@@ -879,17 +879,14 @@
// string wrapper objects. The length property of string wrapper
// objects is read-only and therefore always returns the length of
// the underlying string value. See ECMA-262 15.5.5.1.
- if ((object->IsString() || object->IsStringWrapper()) &&
+ if (object->IsStringWrapper() &&
name->Equals(isolate()->heap()->length_string())) {
Handle<Code> stub;
if (state == UNINITIALIZED) {
stub = pre_monomorphic_stub();
- } else if (state == PREMONOMORPHIC) {
- StringLengthStub string_length_stub(kind(), !object->IsString());
+ } else if (state == PREMONOMORPHIC || state == MONOMORPHIC) {
+ StringLengthStub string_length_stub(kind());
stub = string_length_stub.GetCode(isolate());
- } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
- StringLengthStub string_length_stub(kind(), true);
- stub = string_length_stub.GetCode(isolate());
} else if (state != MEGAMORPHIC) {
ASSERT(state != GENERIC);
stub = megamorphic_stub();
@@ -897,14 +894,12 @@
if (!stub.is_null()) {
set_target(*stub);
#ifdef DEBUG
- if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
+ if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n");
#endif
}
// Get the string if we have a string wrapper object.
- Handle<Object> string = object->IsJSValue()
- ? Handle<Object>(Handle<JSValue>::cast(object)->value(),
isolate())
- : object;
- return Smi::FromInt(String::cast(*string)->length());
+ String* string = String::cast(JSValue::cast(*object)->value());
+ return Smi::FromInt(string->length());
}
// Use specialized code for getting prototype of functions.
@@ -1265,6 +1260,8 @@
State state,
Handle<Object> object,
Handle<String> name) {
+ // TODO(verwaest): It would be nice to support loading fields from smis
as
+ // well. For now just fail to update the cache.
if (!object->IsHeapObject()) return;
Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
@@ -1278,6 +1275,16 @@
} else if (!lookup->IsCacheable()) {
// Bail out if the result is not cacheable.
code = slow_stub();
+ } else if (object->IsString() &&
+ name->Equals(isolate()->heap()->length_string())) {
+ int length_index = String::kLengthOffset / kPointerSize;
+ if (target()->is_load_stub()) {
+ LoadFieldStub stub(true, length_index, Representation::Tagged());
+ code = stub.GetCode(isolate());
+ } else {
+ KeyedLoadFieldStub stub(true, length_index,
Representation::Tagged());
+ code = stub.GetCode(isolate());
+ }
} else if (!object->IsJSObject()) {
// TODO(jkummerow): It would be nice to support non-JSObjects in
// ComputeLoadHandler, then we wouldn't need to go generic here.
@@ -1362,9 +1369,9 @@
return isolate()->stub_cache()->ComputeLoadViaGetter(
name, receiver, holder, function);
} else if (receiver->IsJSArray() &&
- name->Equals(isolate()->heap()->length_string())) {
- PropertyIndex lengthIndex =
- PropertyIndex::NewHeaderIndex(JSArray::kLengthOffset /
kPointerSize);
+ name->Equals(isolate()->heap()->length_string())) {
+ PropertyIndex lengthIndex = PropertyIndex::NewHeaderIndex(
+ JSArray::kLengthOffset / kPointerSize);
return isolate()->stub_cache()->ComputeLoadField(
name, receiver, holder, lengthIndex, Representation::Tagged());
}
=======================================
--- /branches/bleeding_edge/src/mips/code-stubs-mips.cc Fri Sep 13 00:10:24
2013 UTC
+++ /branches/bleeding_edge/src/mips/code-stubs-mips.cc Fri Sep 13 09:57:48
2013 UTC
@@ -3408,8 +3408,7 @@
receiver = a0;
}
- StubCompiler::GenerateLoadStringLength(masm, receiver, a3, t0, &miss,
- support_wrapper_);
+ StubCompiler::GenerateLoadStringLength(masm, receiver, a3, t0, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Fri Sep 13 00:04:29
2013 UTC
+++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Fri Sep 13 09:57:48
2013 UTC
@@ -374,30 +374,26 @@
Register receiver,
Register scratch1,
Register scratch2,
- Label* miss,
- bool support_wrappers) {
+ Label* miss) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch1 register.
- GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
- support_wrappers ? &check_wrapper : miss);
+ GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
&check_wrapper);
// Load length directly from the string.
__ Ret(USE_DELAY_SLOT);
__ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
- if (support_wrappers) {
- // Check if the object is a JSValue wrapper.
- __ bind(&check_wrapper);
- __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
+ // Check if the object is a JSValue wrapper.
+ __ bind(&check_wrapper);
+ __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
- // Unwrap the value and check if the wrapped value is a string.
- __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
- GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
- __ Ret(USE_DELAY_SLOT);
- __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
- }
+ // Unwrap the value and check if the wrapped value is a string.
+ __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
+ GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
+ __ Ret(USE_DELAY_SLOT);
+ __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
}
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Thu Sep 12 22:04:04 2013 UTC
+++ /branches/bleeding_edge/src/stub-cache.h Fri Sep 13 09:57:48 2013 UTC
@@ -572,8 +572,7 @@
Register receiver,
Register scratch1,
Register scratch2,
- Label* miss_label,
- bool support_wrappers);
+ Label* miss_label);
static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Fri Sep 13 07:59:48
2013 UTC
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Fri Sep 13 09:57:48
2013 UTC
@@ -1902,8 +1902,7 @@
receiver = rax;
}
- StubCompiler::GenerateLoadStringLength(masm, receiver, r8, r9, &miss,
- support_wrapper_);
+ StubCompiler::GenerateLoadStringLength(masm, receiver, r8, r9, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(
masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Fri Sep 13 07:59:48
2013 UTC
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Fri Sep 13 09:57:48
2013 UTC
@@ -304,32 +304,28 @@
Register receiver,
Register scratch1,
Register scratch2,
- Label* miss,
- bool support_wrappers) {
+ Label* miss) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch register.
- GenerateStringCheck(masm, receiver, scratch1, miss,
- support_wrappers ? &check_wrapper : miss);
+ GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
// Load length directly from the string.
__ movq(rax, FieldOperand(receiver, 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 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);
- }
+ // 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);
}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.