Turn StringLengthStub (used by string wrappers only) into a hydrogen stub.
BUG= R=yangguo@chromium.org Review URL: https://codereview.chromium.org/197603002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19889 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
717c4d3bb5
commit
c2af96ba7b
@ -187,6 +187,26 @@ void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void StringLengthStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { x0, x2 };
|
||||
descriptor->register_param_count_ = 2;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void KeyedStringLengthStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { x1, x0 };
|
||||
descriptor->register_param_count_ = 2;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
@ -1969,38 +1989,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void StringLengthStub::Generate(MacroAssembler* masm) {
|
||||
Label miss;
|
||||
Register receiver;
|
||||
if (kind() == Code::KEYED_LOAD_IC) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- lr : return address
|
||||
// -- x1 : receiver
|
||||
// -- x0 : key
|
||||
// -----------------------------------
|
||||
Register key = x0;
|
||||
receiver = x1;
|
||||
__ Cmp(key, Operand(masm->isolate()->factory()->length_string()));
|
||||
__ B(ne, &miss);
|
||||
} else {
|
||||
ASSERT(kind() == Code::LOAD_IC);
|
||||
// ----------- S t a t e -------------
|
||||
// -- lr : return address
|
||||
// -- x2 : name
|
||||
// -- x0 : receiver
|
||||
// -- sp[0] : receiver
|
||||
// -----------------------------------
|
||||
receiver = x0;
|
||||
}
|
||||
|
||||
StubCompiler::GenerateLoadStringLength(masm, receiver, x10, x11, &miss);
|
||||
|
||||
__ Bind(&miss);
|
||||
StubCompiler::TailCallBuiltin(masm,
|
||||
BaseLoadStoreStubCompiler::MissBuiltin(kind()));
|
||||
}
|
||||
|
||||
|
||||
void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
|
||||
ASM_LOCATION("StoreArrayLengthStub::Generate");
|
||||
// This accepts as a receiver anything JSArray::SetElementsLength accepts
|
||||
|
@ -306,60 +306,6 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Generate code to check if an object is a string. If the object is a
|
||||
// heap object, its map's instance type is left in the scratch1 register.
|
||||
static void GenerateStringCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
Label* smi,
|
||||
Label* non_string_object) {
|
||||
// Check that the receiver isn't a smi.
|
||||
__ JumpIfSmi(receiver, smi);
|
||||
|
||||
// Get the object's instance type filed.
|
||||
__ Ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
|
||||
__ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
|
||||
// Check if the "not string" bit is set.
|
||||
__ Tbnz(scratch1, MaskToBit(kNotStringTag), non_string_object);
|
||||
}
|
||||
|
||||
|
||||
// Generate code to load the length from a string object and return the length.
|
||||
// If the receiver object is not a string or a wrapped string object the
|
||||
// execution continues at the miss label. The register containing the
|
||||
// receiver is not clobbered if the receiver is not a string.
|
||||
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Label* miss) {
|
||||
// Input registers can't alias because we don't want to clobber the
|
||||
// receiver register if the object is not a string.
|
||||
ASSERT(!AreAliased(receiver, scratch1, scratch2));
|
||||
|
||||
Label check_wrapper;
|
||||
|
||||
// Check if the object is a string leaving the instance type in the
|
||||
// scratch1 register.
|
||||
GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
|
||||
|
||||
// Load length directly from the string.
|
||||
__ Ldr(x0, 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, miss, miss);
|
||||
__ Ldr(x0, FieldMemOperand(scratch1, String::kLengthOffset));
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
|
@ -165,6 +165,26 @@ void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void StringLengthStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { r0, r2 };
|
||||
descriptor->register_param_count_ = 2;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void KeyedStringLengthStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { r1, r0 };
|
||||
descriptor->register_param_count_ = 2;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
@ -2100,37 +2120,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void StringLengthStub::Generate(MacroAssembler* masm) {
|
||||
Label miss;
|
||||
Register receiver;
|
||||
if (kind() == Code::KEYED_LOAD_IC) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- lr : return address
|
||||
// -- r0 : key
|
||||
// -- r1 : receiver
|
||||
// -----------------------------------
|
||||
__ cmp(r0, Operand(masm->isolate()->factory()->length_string()));
|
||||
__ b(ne, &miss);
|
||||
receiver = r1;
|
||||
} else {
|
||||
ASSERT(kind() == Code::LOAD_IC);
|
||||
// ----------- S t a t e -------------
|
||||
// -- r2 : name
|
||||
// -- lr : return address
|
||||
// -- r0 : receiver
|
||||
// -- sp[0] : receiver
|
||||
// -----------------------------------
|
||||
receiver = r0;
|
||||
}
|
||||
|
||||
StubCompiler::GenerateLoadStringLength(masm, receiver, r3, r4, &miss);
|
||||
|
||||
__ bind(&miss);
|
||||
StubCompiler::TailCallBuiltin(
|
||||
masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
|
||||
}
|
||||
|
||||
|
||||
void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
|
||||
// This accepts as a receiver anything JSArray::SetElementsLength accepts
|
||||
// (currently anything except for external arrays which means anything with
|
||||
|
@ -351,60 +351,6 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Generate code to check if an object is a string. If the object is a
|
||||
// heap object, its map's instance type is left in the scratch1 register.
|
||||
// If this is not needed, scratch1 and scratch2 may be the same register.
|
||||
static void GenerateStringCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Label* smi,
|
||||
Label* non_string_object) {
|
||||
// Check that the receiver isn't a smi.
|
||||
__ JumpIfSmi(receiver, smi);
|
||||
|
||||
// Check that the object is a string.
|
||||
__ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
|
||||
__ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
|
||||
__ and_(scratch2, scratch1, Operand(kIsNotStringMask));
|
||||
// The cast is to resolve the overload for the argument of 0x0.
|
||||
__ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
|
||||
__ b(ne, non_string_object);
|
||||
}
|
||||
|
||||
|
||||
// Generate code to load the length from a string object and return the length.
|
||||
// If the receiver object is not a string or a wrapped string object the
|
||||
// execution continues at the miss label. The register containing the
|
||||
// receiver is potentially clobbered.
|
||||
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
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, &check_wrapper);
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
|
@ -608,15 +608,15 @@ Handle<Code> LoadFieldStub::GenerateCode(Isolate* isolate) {
|
||||
|
||||
|
||||
template<>
|
||||
HValue* CodeStubGraphBuilder<KeyedLoadFieldStub>::BuildCodeStub() {
|
||||
return BuildLoadNamedField(GetParameter(0),
|
||||
casted_stub()->representation(),
|
||||
casted_stub()->offset(),
|
||||
casted_stub()->is_inobject());
|
||||
HValue* CodeStubGraphBuilder<StringLengthStub>::BuildCodeStub() {
|
||||
HValue* string = BuildLoadNamedField(
|
||||
GetParameter(0), Representation::Tagged(), JSValue::kValueOffset, true);
|
||||
return BuildLoadNamedField(
|
||||
string, Representation::Tagged(), String::kLengthOffset, true);
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> KeyedLoadFieldStub::GenerateCode(Isolate* isolate) {
|
||||
Handle<Code> StringLengthStub::GenerateCode(Isolate* isolate) {
|
||||
return DoGenerateCode(isolate, this);
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,6 @@ namespace internal {
|
||||
V(CompareIC) \
|
||||
V(CompareNilIC) \
|
||||
V(MathPow) \
|
||||
V(StringLength) \
|
||||
V(FunctionPrototype) \
|
||||
V(StoreArrayLength) \
|
||||
V(RecordWrite) \
|
||||
@ -98,7 +97,9 @@ namespace internal {
|
||||
V(CallApiGetter) \
|
||||
/* IC Handler stubs */ \
|
||||
V(LoadField) \
|
||||
V(KeyedLoadField)
|
||||
V(KeyedLoadField) \
|
||||
V(StringLength) \
|
||||
V(KeyedStringLength)
|
||||
|
||||
// List of code stubs only used on ARM platforms.
|
||||
#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_A64)
|
||||
@ -833,17 +834,6 @@ class FunctionPrototypeStub: public ICStub {
|
||||
};
|
||||
|
||||
|
||||
class StringLengthStub: public ICStub {
|
||||
public:
|
||||
explicit StringLengthStub(Code::Kind kind) : ICStub(kind) { }
|
||||
virtual void Generate(MacroAssembler* masm);
|
||||
|
||||
private:
|
||||
STATIC_ASSERT(KindBits::kSize == 4);
|
||||
virtual CodeStub::Major MajorKey() { return StringLength; }
|
||||
};
|
||||
|
||||
|
||||
class StoreICStub: public ICStub {
|
||||
public:
|
||||
StoreICStub(Code::Kind kind, StrictMode strict_mode)
|
||||
@ -959,6 +949,44 @@ class LoadFieldStub: public HandlerStub {
|
||||
};
|
||||
|
||||
|
||||
class StringLengthStub: public HandlerStub {
|
||||
public:
|
||||
explicit StringLengthStub() : HandlerStub() {
|
||||
Initialize(Code::LOAD_IC);
|
||||
}
|
||||
virtual Handle<Code> GenerateCode(Isolate* isolate);
|
||||
virtual void InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor);
|
||||
|
||||
protected:
|
||||
virtual Code::Kind kind() const {
|
||||
return KindBits::decode(bit_field_);
|
||||
}
|
||||
|
||||
void Initialize(Code::Kind kind) {
|
||||
bit_field_ = KindBits::encode(kind);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual CodeStub::Major MajorKey() { return StringLength; }
|
||||
};
|
||||
|
||||
|
||||
class KeyedStringLengthStub: public StringLengthStub {
|
||||
public:
|
||||
explicit KeyedStringLengthStub() : StringLengthStub() {
|
||||
Initialize(Code::KEYED_LOAD_IC);
|
||||
}
|
||||
virtual void InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor);
|
||||
|
||||
private:
|
||||
virtual CodeStub::Major MajorKey() { return KeyedStringLength; }
|
||||
};
|
||||
|
||||
|
||||
class StoreGlobalStub : public HandlerStub {
|
||||
public:
|
||||
explicit StoreGlobalStub(bool is_constant, bool check_global) {
|
||||
@ -1072,8 +1100,6 @@ class KeyedLoadFieldStub: public LoadFieldStub {
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor);
|
||||
|
||||
virtual Handle<Code> GenerateCode(Isolate* isolate);
|
||||
|
||||
private:
|
||||
virtual CodeStub::Major MajorKey() { return KeyedLoadField; }
|
||||
};
|
||||
|
@ -170,6 +170,26 @@ void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void StringLengthStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { edx, ecx };
|
||||
descriptor->register_param_count_ = 2;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void KeyedStringLengthStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { edx, ecx };
|
||||
descriptor->register_param_count_ = 2;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
@ -1046,26 +1066,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void StringLengthStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- ecx : name
|
||||
// -- edx : receiver
|
||||
// -- esp[0] : return address
|
||||
// -----------------------------------
|
||||
Label miss;
|
||||
|
||||
if (kind() == Code::KEYED_LOAD_IC) {
|
||||
__ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
|
||||
__ j(not_equal, &miss);
|
||||
}
|
||||
|
||||
StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss);
|
||||
__ bind(&miss);
|
||||
StubCompiler::TailCallBuiltin(
|
||||
masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
|
||||
}
|
||||
|
||||
|
||||
void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : value
|
||||
|
@ -306,54 +306,6 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Generate code to check if an object is a string. If the object is
|
||||
// a string, the map's instance type is left in the scratch register.
|
||||
static void GenerateStringCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* smi,
|
||||
Label* non_string_object) {
|
||||
// Check that the object isn't a smi.
|
||||
__ JumpIfSmi(receiver, smi);
|
||||
|
||||
// Check that the object is a string.
|
||||
__ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
|
||||
STATIC_ASSERT(kNotStringTag != 0);
|
||||
__ test(scratch, Immediate(kNotStringTag));
|
||||
__ j(not_zero, non_string_object);
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
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, &check_wrapper);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
|
36
src/ic.cc
36
src/ic.cc
@ -536,31 +536,6 @@ MaybeObject* LoadIC::Load(Handle<Object> object,
|
||||
}
|
||||
|
||||
if (FLAG_use_ic) {
|
||||
// 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
|
||||
// the underlying string value. See ECMA-262 15.5.5.1.
|
||||
if (object->IsStringWrapper() &&
|
||||
name->Equals(isolate()->heap()->length_string())) {
|
||||
Handle<Code> stub;
|
||||
if (state() == UNINITIALIZED) {
|
||||
stub = pre_monomorphic_stub();
|
||||
} else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) {
|
||||
StringLengthStub string_length_stub(kind());
|
||||
stub = string_length_stub.GetCode(isolate());
|
||||
} else if (state() != MEGAMORPHIC) {
|
||||
ASSERT(state() != GENERIC);
|
||||
stub = megamorphic_stub();
|
||||
}
|
||||
if (!stub.is_null()) {
|
||||
set_target(*stub);
|
||||
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n");
|
||||
}
|
||||
// Get the string if we have a string wrapper object.
|
||||
String* string = String::cast(JSValue::cast(*object)->value());
|
||||
return Smi::FromInt(string->length());
|
||||
}
|
||||
|
||||
// Use specialized code for getting prototype of functions.
|
||||
if (object->IsJSFunction() &&
|
||||
name->Equals(isolate()->heap()->prototype_string()) &&
|
||||
@ -910,6 +885,17 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
|
||||
return SimpleFieldLoad(length_index);
|
||||
}
|
||||
|
||||
if (object->IsStringWrapper() &&
|
||||
name->Equals(isolate()->heap()->length_string())) {
|
||||
if (kind() == Code::LOAD_IC) {
|
||||
StringLengthStub string_length_stub;
|
||||
return string_length_stub.GetCode(isolate());
|
||||
} else {
|
||||
KeyedStringLengthStub string_length_stub;
|
||||
return string_length_stub.GetCode(isolate());
|
||||
}
|
||||
}
|
||||
|
||||
Handle<HeapType> type = CurrentTypeOf(object, isolate());
|
||||
Handle<JSObject> holder(lookup->holder());
|
||||
LoadStubCompiler compiler(isolate(), kNoExtraICState, cache_holder, kind());
|
||||
|
@ -360,12 +360,6 @@ class StubCompiler BASE_EMBEDDED {
|
||||
Register scratch,
|
||||
Label* miss_label);
|
||||
|
||||
static void GenerateLoadStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Label* miss_label);
|
||||
|
||||
static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
|
@ -166,6 +166,26 @@ void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void StringLengthStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { rax, rcx };
|
||||
descriptor->register_param_count_ = 2;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void KeyedStringLengthStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { rdx, rax };
|
||||
descriptor->register_param_count_ = 2;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
@ -913,35 +933,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void StringLengthStub::Generate(MacroAssembler* masm) {
|
||||
Label miss;
|
||||
Register receiver;
|
||||
if (kind() == Code::KEYED_LOAD_IC) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : key
|
||||
// -- rdx : receiver
|
||||
// -- rsp[0] : return address
|
||||
// -----------------------------------
|
||||
__ Cmp(rax, masm->isolate()->factory()->length_string());
|
||||
__ j(not_equal, &miss);
|
||||
receiver = rdx;
|
||||
} else {
|
||||
ASSERT(kind() == Code::LOAD_IC);
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : receiver
|
||||
// -- rcx : name
|
||||
// -- rsp[0] : return address
|
||||
// -----------------------------------
|
||||
receiver = rax;
|
||||
}
|
||||
|
||||
StubCompiler::GenerateLoadStringLength(masm, receiver, r8, r9, &miss);
|
||||
__ bind(&miss);
|
||||
StubCompiler::TailCallBuiltin(
|
||||
masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
|
||||
}
|
||||
|
||||
|
||||
void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : value
|
||||
|
@ -281,54 +281,6 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Generate code to check if an object is a string. If the object is
|
||||
// a string, the map's instance type is left in the scratch register.
|
||||
static void GenerateStringCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch,
|
||||
Label* smi,
|
||||
Label* non_string_object) {
|
||||
// Check that the object isn't a smi.
|
||||
__ JumpIfSmi(receiver, smi);
|
||||
|
||||
// Check that the object is a string.
|
||||
__ movp(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
|
||||
STATIC_ASSERT(kNotStringTag != 0);
|
||||
__ testl(scratch, Immediate(kNotStringTag));
|
||||
__ j(not_zero, non_string_object);
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
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, &check_wrapper);
|
||||
|
||||
// Load length directly from the string.
|
||||
__ movp(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.
|
||||
__ movp(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
|
||||
GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
|
||||
__ movp(rax, FieldOperand(scratch2, String::kLengthOffset));
|
||||
__ ret(0);
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register result,
|
||||
|
Loading…
Reference in New Issue
Block a user