Commit b9b350cb authored by ishell's avatar ishell Committed by Commit bot

[stubs] Port KeyedLoadSloppyArgumentsStub and KeyedStoreSloppyArgumentsStub to TurboFan.

BUG=v8:5269

Review-Url: https://codereview.chromium.org/2327103002
Cr-Commit-Position: refs/heads/master@{#39372}
parent ae9a39b0
......@@ -4520,6 +4520,105 @@ void CodeStubAssembler::StoreNamedField(Node* object, FieldIndex index,
}
}
Node* CodeStubAssembler::EmitKeyedSloppyArguments(Node* receiver, Node* key,
Node* value, Label* bailout) {
// 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].
bool is_load = value == nullptr;
GotoUnless(WordIsSmi(key), bailout);
key = SmiUntag(key);
GotoIf(IntPtrLessThan(key, IntPtrConstant(0)), bailout);
Node* elements = LoadElements(receiver);
Node* elements_length = LoadAndUntagFixedArrayBaseLength(elements);
Variable var_result(this, MachineRepresentation::kTagged);
if (!is_load) {
var_result.Bind(value);
}
Label if_mapped(this), if_unmapped(this), end(this, &var_result);
Node* intptr_two = IntPtrConstant(2);
Node* adjusted_length = IntPtrSub(elements_length, intptr_two);
GotoIf(UintPtrGreaterThanOrEqual(key, adjusted_length), &if_unmapped);
Node* mapped_index = LoadFixedArrayElement(
elements, IntPtrAdd(key, intptr_two), 0, INTPTR_PARAMETERS);
Branch(WordEqual(mapped_index, TheHoleConstant()), &if_unmapped, &if_mapped);
Bind(&if_mapped);
{
Assert(WordIsSmi(mapped_index));
mapped_index = SmiUntag(mapped_index);
Node* the_context = LoadFixedArrayElement(elements, IntPtrConstant(0), 0,
INTPTR_PARAMETERS);
STATIC_ASSERT(Context::kHeaderSize == FixedArray::kHeaderSize);
if (is_load) {
Node* result = LoadFixedArrayElement(the_context, mapped_index, 0,
INTPTR_PARAMETERS);
Assert(WordNotEqual(result, TheHoleConstant()));
var_result.Bind(result);
} else {
StoreFixedArrayElement(the_context, mapped_index, value,
UPDATE_WRITE_BARRIER, INTPTR_PARAMETERS);
}
Goto(&end);
}
Bind(&if_unmapped);
{
Node* backing_store = LoadFixedArrayElement(elements, IntPtrConstant(1), 0,
INTPTR_PARAMETERS);
GotoIf(WordNotEqual(LoadMap(backing_store),
LoadRoot(Heap::kFixedArrayMapRootIndex)),
bailout);
Node* backing_store_length =
LoadAndUntagFixedArrayBaseLength(backing_store);
GotoIf(UintPtrGreaterThanOrEqual(key, backing_store_length), bailout);
// The key falls into unmapped range.
if (is_load) {
Node* result =
LoadFixedArrayElement(backing_store, key, 0, INTPTR_PARAMETERS);
GotoIf(WordEqual(result, TheHoleConstant()), bailout);
var_result.Bind(result);
} else {
StoreFixedArrayElement(backing_store, key, value, UPDATE_WRITE_BARRIER,
INTPTR_PARAMETERS);
}
Goto(&end);
}
Bind(&end);
return var_result.value();
}
Node* CodeStubAssembler::EnumLength(Node* map) {
Node* bitfield_3 = LoadMapBitField3(map);
Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3);
......
......@@ -644,6 +644,20 @@ class CodeStubAssembler : public compiler::CodeAssembler {
Representation representation, compiler::Node* value,
bool transition_to_field);
// Emits keyed sloppy arguments load. Returns either the loaded value.
compiler::Node* LoadKeyedSloppyArguments(compiler::Node* receiver,
compiler::Node* key,
Label* bailout) {
return EmitKeyedSloppyArguments(receiver, key, nullptr, bailout);
}
// Emits keyed sloppy arguments store.
void StoreKeyedSloppyArguments(compiler::Node* receiver, compiler::Node* key,
compiler::Node* value, Label* bailout) {
DCHECK_NOT_NULL(value);
EmitKeyedSloppyArguments(receiver, key, value, bailout);
}
void LoadIC(const LoadICParameters* p);
void LoadGlobalIC(const LoadICParameters* p);
void KeyedLoadIC(const LoadICParameters* p);
......@@ -708,6 +722,13 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* SmiShiftBitsConstant();
// Emits keyed sloppy arguments load if the |value| is nullptr or store
// otherwise. Returns either the loaded value or |value|.
compiler::Node* EmitKeyedSloppyArguments(compiler::Node* receiver,
compiler::Node* key,
compiler::Node* value,
Label* bailout);
static const int kElementLoopUnrollThreshold = 8;
};
......
......@@ -84,10 +84,6 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
HValue* BuildPushElement(HValue* object, HValue* argc,
HValue* argument_elements, ElementsKind kind);
HValue* UnmappedCase(HValue* elements, HValue* key, HValue* value);
HValue* EmitKeyedSloppyArguments(HValue* receiver, HValue* key,
HValue* value);
HValue* BuildToString(HValue* input, bool convert);
HValue* BuildToPrimitive(HValue* input, HValue* input_map);
......@@ -905,155 +901,6 @@ HValue* CodeStubGraphBuilder<LoadConstantStub>::BuildCodeStub() {
Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); }
HValue* CodeStubGraphBuilderBase::UnmappedCase(HValue* elements, HValue* key,
HValue* value) {
HValue* result = NULL;
HInstruction* backing_store =
Add<HLoadKeyed>(elements, graph()->GetConstant1(), nullptr, nullptr,
FAST_ELEMENTS, ALLOW_RETURN_HOLE);
Add<HCheckMaps>(backing_store, isolate()->factory()->fixed_array_map());
HValue* backing_store_length = Add<HLoadNamedField>(
backing_store, nullptr, HObjectAccess::ForFixedArrayLength());
IfBuilder in_unmapped_range(this);
in_unmapped_range.If<HCompareNumericAndBranch>(key, backing_store_length,
Token::LT);
in_unmapped_range.Then();
{
if (value == NULL) {
result = Add<HLoadKeyed>(backing_store, key, nullptr, nullptr,
FAST_HOLEY_ELEMENTS, NEVER_RETURN_HOLE);
} else {
Add<HStoreKeyed>(backing_store, key, value, nullptr, FAST_HOLEY_ELEMENTS);
}
}
in_unmapped_range.ElseDeopt(DeoptimizeReason::kOutsideOfRange);
in_unmapped_range.End();
return result;
}
HValue* CodeStubGraphBuilderBase::EmitKeyedSloppyArguments(HValue* receiver,
HValue* key,
HValue* value) {
// 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].
bool is_load = value == NULL;
key = AddUncasted<HForceRepresentation>(key, Representation::Smi());
IfBuilder positive_smi(this);
positive_smi.If<HCompareNumericAndBranch>(key, graph()->GetConstant0(),
Token::LT);
positive_smi.ThenDeopt(DeoptimizeReason::kKeyIsNegative);
positive_smi.End();
HValue* constant_two = Add<HConstant>(2);
HValue* elements = AddLoadElements(receiver, nullptr);
HValue* elements_length = Add<HLoadNamedField>(
elements, nullptr, 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, nullptr, nullptr, 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(),
nullptr, nullptr, FAST_ELEMENTS);
STATIC_ASSERT(Context::kHeaderSize == FixedArray::kHeaderSize);
if (is_load) {
HValue* result =
Add<HLoadKeyed>(the_context, mapped_index, nullptr, nullptr,
FAST_ELEMENTS, ALLOW_RETURN_HOLE);
environment()->Push(result);
} else {
DCHECK(value != NULL);
Add<HStoreKeyed>(the_context, mapped_index, value, nullptr,
FAST_ELEMENTS);
environment()->Push(value);
}
}
is_valid.Else();
{
HValue* result = UnmappedCase(elements, key, value);
environment()->Push(is_load ? result : value);
}
is_valid.End();
}
in_range.Else();
{
HValue* result = UnmappedCase(elements, key, value);
environment()->Push(is_load ? result : value);
}
in_range.End();
return environment()->Pop();
}
template <>
HValue* CodeStubGraphBuilder<KeyedLoadSloppyArgumentsStub>::BuildCodeStub() {
HValue* receiver = GetParameter(Descriptor::kReceiver);
HValue* key = GetParameter(Descriptor::kName);
return EmitKeyedSloppyArguments(receiver, key, NULL);
}
Handle<Code> KeyedLoadSloppyArgumentsStub::GenerateCode() {
return DoGenerateCode(this);
}
template <>
HValue* CodeStubGraphBuilder<KeyedStoreSloppyArgumentsStub>::BuildCodeStub() {
HValue* receiver = GetParameter(Descriptor::kReceiver);
HValue* key = GetParameter(Descriptor::kName);
HValue* value = GetParameter(Descriptor::kValue);
return EmitKeyedSloppyArguments(receiver, key, value);
}
Handle<Code> KeyedStoreSloppyArgumentsStub::GenerateCode() {
return DoGenerateCode(this);
}
void CodeStubGraphBuilderBase::BuildStoreNamedField(
HValue* object, HValue* value, FieldIndex index,
Representation representation, bool transition_to_field) {
......
......@@ -4566,6 +4566,55 @@ void StoreGlobalStub::GenerateAssembly(CodeStubAssembler* assembler) const {
}
}
void KeyedLoadSloppyArgumentsStub::GenerateAssembly(
CodeStubAssembler* assembler) const {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* receiver = assembler->Parameter(Descriptor::kReceiver);
Node* key = assembler->Parameter(Descriptor::kName);
Node* slot = assembler->Parameter(Descriptor::kSlot);
Node* vector = assembler->Parameter(Descriptor::kVector);
Node* context = assembler->Parameter(Descriptor::kContext);
Label miss(assembler);
Node* result = assembler->LoadKeyedSloppyArguments(receiver, key, &miss);
assembler->Return(result);
assembler->Bind(&miss);
{
assembler->Comment("Miss");
assembler->TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver,
key, slot, vector);
}
}
void KeyedStoreSloppyArgumentsStub::GenerateAssembly(
CodeStubAssembler* assembler) const {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* receiver = assembler->Parameter(Descriptor::kReceiver);
Node* key = assembler->Parameter(Descriptor::kName);
Node* value = assembler->Parameter(Descriptor::kValue);
Node* slot = assembler->Parameter(Descriptor::kSlot);
Node* vector = assembler->Parameter(Descriptor::kVector);
Node* context = assembler->Parameter(Descriptor::kContext);
Label miss(assembler);
assembler->StoreKeyedSloppyArguments(receiver, key, value, &miss);
assembler->Return(value);
assembler->Bind(&miss);
{
assembler->Comment("Miss");
assembler->TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, receiver,
key, value, slot, vector);
}
}
// static
compiler::Node* LessThanStub::Generate(CodeStubAssembler* assembler,
compiler::Node* lhs, compiler::Node* rhs,
......
......@@ -82,8 +82,6 @@ class ObjectLiteral;
/* as part of the new IC system, ask */ \
/* ishell before doing anything */ \
V(KeyedLoadGeneric) \
V(KeyedLoadSloppyArguments) \
V(KeyedStoreSloppyArguments) \
V(LoadConstant) \
V(LoadDictionaryElement) \
V(LoadFastElement) \
......@@ -150,6 +148,8 @@ class ObjectLiteral;
V(GreaterThanOrEqual) \
V(Equal) \
V(NotEqual) \
V(KeyedLoadSloppyArguments) \
V(KeyedStoreSloppyArguments) \
V(StrictEqual) \
V(StrictNotEqual) \
V(StringEqual) \
......@@ -1550,35 +1550,36 @@ class LoadFieldStub: public HandlerStub {
DEFINE_HANDLER_CODE_STUB(LoadField, HandlerStub);
};
class KeyedLoadSloppyArgumentsStub : public HandlerStub {
class KeyedLoadSloppyArgumentsStub : public TurboFanCodeStub {
public:
explicit KeyedLoadSloppyArgumentsStub(Isolate* isolate)
: HandlerStub(isolate) {}
: TurboFanCodeStub(isolate) {}
protected:
Code::Kind kind() const override { return Code::KEYED_LOAD_IC; }
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
ExtraICState GetExtraICState() const override { return Code::LOAD_IC; }
protected:
DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadWithVector);
DEFINE_HANDLER_CODE_STUB(KeyedLoadSloppyArguments, HandlerStub);
DEFINE_TURBOFAN_CODE_STUB(KeyedLoadSloppyArguments, TurboFanCodeStub);
};
class CommonStoreModeBits : public BitField<KeyedAccessStoreMode, 0, 3> {};
class KeyedStoreSloppyArgumentsStub : public HandlerStub {
class KeyedStoreSloppyArgumentsStub : public TurboFanCodeStub {
public:
explicit KeyedStoreSloppyArgumentsStub(Isolate* isolate,
KeyedAccessStoreMode mode)
: HandlerStub(isolate) {
set_sub_minor_key(CommonStoreModeBits::encode(mode));
: TurboFanCodeStub(isolate) {
minor_key_ = CommonStoreModeBits::encode(mode);
}
protected:
Code::Kind kind() const override { return Code::KEYED_STORE_IC; }
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
ExtraICState GetExtraICState() const override { return Code::STORE_IC; }
protected:
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
DEFINE_HANDLER_CODE_STUB(KeyedStoreSloppyArguments, HandlerStub);
DEFINE_TURBOFAN_CODE_STUB(KeyedStoreSloppyArguments, TurboFanCodeStub);
};
......
......@@ -244,6 +244,7 @@ void FullCodeGenerator::CallKeyedStoreIC() {
Handle<Code> ic =
CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
CallIC(ic);
RestoreContext();
}
void FullCodeGenerator::RecordJSReturnSite(Call* call) {
......@@ -1093,7 +1094,7 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
__ Move(LoadDescriptor::SlotRegister(),
SmiFromSlot(prop->PropertyFeedbackSlot()));
CallIC(ic);
if (FLAG_tf_load_ic_stub) RestoreContext();
RestoreContext();
}
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
......
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