Make KeyedLoads from a sloppy arguments array use a handler.

Before, a custom stub was installed.

R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/546683003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24120 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6ca218cf
......@@ -1289,11 +1289,6 @@ static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
}
static void Generate_KeyedLoadIC_SloppyArguments(MacroAssembler* masm) {
KeyedLoadIC::GenerateSloppyArguments(masm);
}
static void Generate_StoreIC_Miss(MacroAssembler* masm) {
StoreIC::GenerateMiss(masm);
}
......
......@@ -89,7 +89,6 @@ enum BuiltinExtraArguments {
kNoExtraICState) \
V(KeyedLoadIC_Generic, KEYED_LOAD_IC, GENERIC, kNoExtraICState) \
V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC, kNoExtraICState) \
V(KeyedLoadIC_SloppyArguments, KEYED_LOAD_IC, MONOMORPHIC, kNoExtraICState) \
\
V(StoreIC_Setter_ForDeopt, STORE_IC, MONOMORPHIC, StoreIC::kStrictModeState) \
\
......
......@@ -71,6 +71,8 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
MULTIPLE
};
HValue* UnmappedCase(HValue* elements, HValue* key);
HValue* BuildArrayConstructor(ElementsKind kind,
AllocationSiteOverrideMode override_mode,
ArgumentClass argument_class);
......@@ -600,6 +602,122 @@ HValue* CodeStubGraphBuilder<LoadConstantStub>::BuildCodeStub() {
Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); }
HValue* CodeStubGraphBuilderBase::UnmappedCase(HValue* elements, HValue* key) {
HValue* result;
HInstruction* backing_store = Add<HLoadKeyed>(
elements, graph()->GetConstant1(), static_cast<HValue*>(NULL),
FAST_ELEMENTS, ALLOW_RETURN_HOLE);
Add<HCheckMaps>(backing_store, isolate()->factory()->fixed_array_map());
HValue* backing_store_length =
Add<HLoadNamedField>(backing_store, static_cast<HValue*>(NULL),
HObjectAccess::ForFixedArrayLength());
IfBuilder in_unmapped_range(this);
in_unmapped_range.If<HCompareNumericAndBranch>(key, backing_store_length,
Token::LT);
in_unmapped_range.Then();
{
result = Add<HLoadKeyed>(backing_store, key, static_cast<HValue*>(NULL),
FAST_HOLEY_ELEMENTS, NEVER_RETURN_HOLE);
}
in_unmapped_range.ElseDeopt("Outside of range");
in_unmapped_range.End();
return result;
}
template <>
HValue* CodeStubGraphBuilder<KeyedLoadSloppyArgumentsStub>::BuildCodeStub() {
HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex);
HValue* key = GetParameter(LoadDescriptor::kNameIndex);
// Mapped arguments are actual arguments. Unmapped arguments are values added
// to the arguments object after it was created for the call. Mapped arguments
// are stored in the context at indexes given by elements[key + 2]. Unmapped
// arguments are stored as regular indexed properties in the arguments array,
// held at elements[1]. See NewSloppyArguments() in runtime.cc for a detailed
// look at argument object construction.
//
// The sloppy arguments elements array has a special format:
//
// 0: context
// 1: unmapped arguments array
// 2: mapped_index0,
// 3: mapped_index1,
// ...
//
// length is 2 + min(number_of_actual_arguments, number_of_formal_arguments).
// If key + 2 >= elements.length then attempt to look in the unmapped
// arguments array (given by elements[1]) and return the value at key, missing
// to the runtime if the unmapped arguments array is not a fixed array or if
// key >= unmapped_arguments_array.length.
//
// Otherwise, t = elements[key + 2]. If t is the hole, then look up the value
// in the unmapped arguments array, as described above. Otherwise, t is a Smi
// index into the context array given at elements[0]. Return the value at
// context[t].
key = AddUncasted<HForceRepresentation>(key, Representation::Smi());
IfBuilder positive_smi(this);
positive_smi.If<HCompareNumericAndBranch>(key, graph()->GetConstant0(),
Token::LT);
positive_smi.ThenDeopt("key is negative");
positive_smi.End();
HValue* constant_two = Add<HConstant>(2);
HValue* elements = AddLoadElements(receiver, static_cast<HValue*>(NULL));
HValue* elements_length =
Add<HLoadNamedField>(elements, static_cast<HValue*>(NULL),
HObjectAccess::ForFixedArrayLength());
HValue* adjusted_length = AddUncasted<HSub>(elements_length, constant_two);
IfBuilder in_range(this);
in_range.If<HCompareNumericAndBranch>(key, adjusted_length, Token::LT);
in_range.Then();
{
HValue* index = AddUncasted<HAdd>(key, constant_two);
HInstruction* mapped_index =
Add<HLoadKeyed>(elements, index, static_cast<HValue*>(NULL),
FAST_HOLEY_ELEMENTS, ALLOW_RETURN_HOLE);
IfBuilder is_valid(this);
is_valid.IfNot<HCompareObjectEqAndBranch>(mapped_index,
graph()->GetConstantHole());
is_valid.Then();
{
// TODO(mvstanton): I'd like to assert from this point, that if the
// mapped_index is not the hole that it is indeed, a smi. An unnecessary
// smi check is being emitted.
HValue* the_context =
Add<HLoadKeyed>(elements, graph()->GetConstant0(),
static_cast<HValue*>(NULL), FAST_ELEMENTS);
DCHECK(Context::kHeaderSize == FixedArray::kHeaderSize);
HValue* result =
Add<HLoadKeyed>(the_context, mapped_index, static_cast<HValue*>(NULL),
FAST_ELEMENTS, ALLOW_RETURN_HOLE);
environment()->Push(result);
}
is_valid.Else();
{
HValue* result = UnmappedCase(elements, key);
environment()->Push(result);
}
is_valid.End();
}
in_range.Else();
{
HValue* result = UnmappedCase(elements, key);
environment()->Push(result);
}
in_range.End();
return environment()->Pop();
}
Handle<Code> KeyedLoadSloppyArgumentsStub::GenerateCode() {
return DoGenerateCode(this);
}
void CodeStubGraphBuilderBase::BuildStoreNamedField(
HValue* object, HValue* value, FieldIndex index,
Representation representation) {
......@@ -1092,7 +1210,6 @@ Handle<Code> ToBooleanStub::GenerateCode() {
template <>
HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
StoreGlobalStub* stub = casted_stub();
Handle<Object> hole(isolate()->heap()->the_hole_value(), isolate());
Handle<Object> placeholer_value(Smi::FromInt(0), isolate());
Handle<PropertyCell> placeholder_cell =
isolate()->factory()->NewPropertyCell(placeholer_value);
......@@ -1124,7 +1241,7 @@ HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
// property has been deleted and that the store must be handled by the
// runtime.
IfBuilder builder(this);
HValue* hole_value = Add<HConstant>(hole);
HValue* hole_value = graph()->GetConstantHole();
builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value);
builder.Then();
builder.Deopt("Unexpected cell contents in global store");
......
......@@ -586,12 +586,14 @@ void KeyedLoadGenericStub::InitializeDescriptor(
void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
if (kind() == Code::STORE_IC) {
descriptor->Initialize(FUNCTION_ADDR(StoreIC_MissFromStubFailure));
} else if (kind() == Code::KEYED_LOAD_IC) {
descriptor->Initialize(FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure));
}
}
CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() {
if (kind() == Code::LOAD_IC) {
if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
return LoadDescriptor(isolate());
} else {
DCHECK_EQ(Code::STORE_IC, kind());
......
......@@ -82,6 +82,7 @@ namespace internal {
/* IC Handler stubs */ \
V(LoadConstant) \
V(LoadField) \
V(KeyedLoadSloppyArguments) \
V(StoreField) \
V(StoreGlobal) \
V(StringLength)
......@@ -914,6 +915,20 @@ class LoadFieldStub: public HandlerStub {
};
class KeyedLoadSloppyArgumentsStub : public HandlerStub {
public:
explicit KeyedLoadSloppyArgumentsStub(Isolate* isolate)
: HandlerStub(isolate) {}
protected:
virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
virtual Code::StubType GetStubType() { return Code::FAST; }
private:
DEFINE_HANDLER_CODE_STUB(KeyedLoadSloppyArguments, HandlerStub);
};
class LoadConstantStub : public HandlerStub {
public:
LoadConstantStub(Isolate* isolate, int constant_index)
......
......@@ -87,6 +87,11 @@ inline bool IsDictionaryElementsKind(ElementsKind kind) {
}
inline bool IsSloppyArgumentsElements(ElementsKind kind) {
return kind == SLOPPY_ARGUMENTS_ELEMENTS;
}
inline bool IsExternalArrayElementsKind(ElementsKind kind) {
return kind >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
kind <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND;
......
......@@ -369,32 +369,6 @@ static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
}
void KeyedLoadIC::GenerateSloppyArguments(MacroAssembler* masm) {
// The return address is in lr.
Register receiver = LoadDescriptor::ReceiverRegister();
Register key = LoadDescriptor::NameRegister();
DCHECK(receiver.is(r1));
DCHECK(key.is(r2));
Label slow, notin;
MemOperand mapped_location = GenerateMappedArgumentsLookup(
masm, receiver, key, r0, r3, r4, &notin, &slow);
__ ldr(r0, mapped_location);
__ Ret();
__ bind(&notin);
// The unmapped lookup expects that the parameter map is in r0.
MemOperand unmapped_location =
GenerateUnmappedArgumentsLookup(masm, key, r0, r3, &slow);
__ ldr(r0, unmapped_location);
__ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
__ cmp(r0, r3);
__ b(eq, &slow);
__ Ret();
__ bind(&slow);
GenerateMiss(masm);
}
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register key = StoreDescriptor::NameRegister();
......
......@@ -370,35 +370,6 @@ void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
}
void KeyedLoadIC::GenerateSloppyArguments(MacroAssembler* masm) {
// The return address is in lr.
Register result = x0;
Register receiver = LoadDescriptor::ReceiverRegister();
Register key = LoadDescriptor::NameRegister();
DCHECK(receiver.is(x1));
DCHECK(key.is(x2));
Label miss, unmapped;
Register map_scratch = x0;
MemOperand mapped_location = GenerateMappedArgumentsLookup(
masm, receiver, key, map_scratch, x3, x4, &unmapped, &miss);
__ Ldr(result, mapped_location);
__ Ret();
__ Bind(&unmapped);
// Parameter map is left in map_scratch when a jump on unmapped is done.
MemOperand unmapped_location =
GenerateUnmappedArgumentsLookup(masm, key, map_scratch, x3, &miss);
__ Ldr(result, unmapped_location);
__ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
__ Ret();
__ Bind(&miss);
GenerateMiss(masm);
}
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
ASM_LOCATION("KeyedStoreIC::GenerateSloppyArguments");
Label slow, notin;
......
......@@ -390,13 +390,13 @@ void ElementHandlerCompiler::CompileElementHandlers(
ElementsKind elements_kind = receiver_map->elements_kind();
if (receiver_map->has_indexed_interceptor()) {
cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
} else if (IsSloppyArgumentsElements(elements_kind)) {
cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
} else if (IsFastElementsKind(elements_kind) ||
IsExternalArrayElementsKind(elements_kind) ||
IsFixedTypedArrayElementsKind(elements_kind)) {
cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind)
.GetCode();
} else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments();
} else {
DCHECK(elements_kind == DICTIONARY_ELEMENTS);
cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
......
......@@ -503,32 +503,6 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
}
void KeyedLoadIC::GenerateSloppyArguments(MacroAssembler* masm) {
// The return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register key = LoadDescriptor::NameRegister();
DCHECK(receiver.is(edx));
DCHECK(key.is(ecx));
Label slow, notin;
Factory* factory = masm->isolate()->factory();
Operand mapped_location = GenerateMappedArgumentsLookup(
masm, receiver, key, ebx, eax, &notin, &slow);
__ mov(eax, mapped_location);
__ Ret();
__ bind(&notin);
// The unmapped lookup expects that the parameter map is in ebx.
Operand unmapped_location =
GenerateUnmappedArgumentsLookup(masm, key, ebx, eax, &slow);
__ cmp(unmapped_location, factory->the_hole_value());
__ j(equal, &slow);
__ mov(eax, unmapped_location);
__ Ret();
__ bind(&slow);
GenerateMiss(masm);
}
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
// Return address is on the stack.
Label slow, notin;
......
......@@ -96,6 +96,8 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
Handle<Code> stub;
if (receiver_map->has_indexed_interceptor()) {
stub = LoadIndexedInterceptorStub(isolate).GetCode();
} else if (receiver_map->has_sloppy_arguments_elements()) {
stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
} else if (receiver_map->has_fast_elements() ||
receiver_map->has_external_array_elements() ||
receiver_map->has_fixed_typed_array_elements()) {
......
......@@ -1187,11 +1187,7 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
if (state() == UNINITIALIZED) stub = string_stub();
} else if (object->IsJSObject()) {
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (receiver->elements()->map() ==
isolate()->heap()->sloppy_arguments_elements_map()) {
stub = sloppy_arguments_stub();
} else if (!Object::ToSmi(isolate(), key).is_null() &&
(!target().is_identical_to(sloppy_arguments_stub()))) {
if (!Object::ToSmi(isolate(), key).is_null()) {
stub = LoadElementStub(receiver);
}
}
......
......@@ -414,7 +414,6 @@ class KeyedLoadIC : public LoadIC {
}
static void GenerateGeneric(MacroAssembler* masm);
static void GenerateString(MacroAssembler* masm);
static void GenerateSloppyArguments(MacroAssembler* masm);
// Bit mask to be tested against bit field for the cases when
// generic stub should go into slow case.
......@@ -434,9 +433,6 @@ class KeyedLoadIC : public LoadIC {
private:
Handle<Code> generic_stub() const { return generic_stub(isolate()); }
Handle<Code> sloppy_arguments_stub() {
return isolate()->builtins()->KeyedLoadIC_SloppyArguments();
}
Handle<Code> string_stub() {
return isolate()->builtins()->KeyedLoadIC_String();
}
......
......@@ -374,32 +374,6 @@ static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
}
void KeyedLoadIC::GenerateSloppyArguments(MacroAssembler* masm) {
// The return address is in ra.
Register receiver = LoadDescriptor::ReceiverRegister();
Register key = LoadDescriptor::NameRegister();
DCHECK(receiver.is(a1));
DCHECK(key.is(a2));
Label slow, notin;
MemOperand mapped_location = GenerateMappedArgumentsLookup(
masm, receiver, key, a0, a3, t0, &notin, &slow);
__ Ret(USE_DELAY_SLOT);
__ lw(v0, mapped_location);
__ bind(&notin);
// The unmapped lookup expects that the parameter map is in a0.
MemOperand unmapped_location =
GenerateUnmappedArgumentsLookup(masm, key, a0, a3, &slow);
__ lw(a0, unmapped_location);
__ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
__ Branch(&slow, eq, a0, Operand(a3));
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
__ bind(&slow);
GenerateMiss(masm);
}
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register key = StoreDescriptor::NameRegister();
......
......@@ -722,31 +722,6 @@ static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
}
void KeyedLoadIC::GenerateSloppyArguments(MacroAssembler* masm) {
// The return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register key = LoadDescriptor::NameRegister();
DCHECK(receiver.is(rdx));
DCHECK(key.is(rcx));
Label slow, notin;
Operand mapped_location = GenerateMappedArgumentsLookup(
masm, receiver, key, rbx, rax, rdi, &notin, &slow);
__ movp(rax, mapped_location);
__ Ret();
__ bind(&notin);
// The unmapped lookup expects that the parameter map is in rbx.
Operand unmapped_location =
GenerateUnmappedArgumentsLookup(masm, key, rbx, rax, &slow);
__ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex);
__ j(equal, &slow);
__ movp(rax, unmapped_location);
__ Ret();
__ bind(&slow);
GenerateMiss(masm);
}
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
// The return address is on the stack.
Label slow, notin;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment