Turn ElementsTransitionAndStore stub into a HydrogenCodeStub.

R=danno@chromium.org, mvstanton@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15635 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2013-07-11 14:29:00 +00:00
parent 9b856d724d
commit 6c13f097d6
12 changed files with 171 additions and 61 deletions

View File

@ -258,6 +258,17 @@ void StoreGlobalStub::InitializeInterfaceDescriptor(
} }
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { r0, r3, r1, r2 };
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
}
#define __ ACCESS_MASM(masm) #define __ ACCESS_MASM(masm)

View File

@ -909,4 +909,75 @@ Handle<Code> StoreGlobalStub::GenerateCode() {
} }
template<>
HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() {
ElementsTransitionAndStoreStub* stub = casted_stub();
ElementsKind from_kind = stub->from();
ElementsKind to_kind = stub->to();
HValue* value = GetParameter(0);
HValue* target_map = GetParameter(1);
HValue* key = GetParameter(2);
HValue* object = GetParameter(3);
if (FLAG_trace_elements_transitions) {
// Tracing elements transitions is the job of the runtime.
current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
set_current_block(NULL);
return value;
}
info()->MarkAsSavesCallerDoubles();
if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) {
Add<HTrapAllocationMemento>(object);
}
// Check if we need to transition the array elements first
// (either SMI -> Double or Double -> Object).
if (DoesTransitionChangeElementsBufferFormat(from_kind, to_kind)) {
HInstruction* array_length = NULL;
if (stub->is_jsarray()) {
array_length = AddLoad(object, HObjectAccess::ForArrayLength());
} else {
array_length = AddLoadFixedArrayLength(AddLoadElements(object));
}
array_length->set_type(HType::Smi());
IfBuilder if_builder(this);
// Check if we have any elements.
if_builder.IfNot<HCompareNumericAndBranch>(array_length,
graph()->GetConstant0(),
Token::EQ);
if_builder.Then();
HInstruction* elements = AddLoadElements(object);
HInstruction* elements_length = AddLoadFixedArrayLength(elements);
BuildGrowElementsCapacity(object, elements, from_kind, to_kind,
array_length, elements_length);
if_builder.End();
}
// Set transitioned map.
AddStore(object, HObjectAccess::ForMap(), target_map);
// Generate the actual store.
BuildUncheckedMonomorphicElementAccess(object, key, value, NULL,
stub->is_jsarray(), to_kind,
true, ALLOW_RETURN_HOLE,
stub->store_mode());
return value;
}
Handle<Code> ElementsTransitionAndStoreStub::GenerateCode() {
return DoGenerateCode(this);
}
} } // namespace v8::internal } } // namespace v8::internal

View File

@ -811,44 +811,6 @@ bool ToBooleanStub::Types::CanBeUndetectable() const {
} }
void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
Label fail;
AllocationSiteMode mode = AllocationSite::GetMode(from_, to_);
ASSERT(!IsFastHoleyElementsKind(from_) || IsFastHoleyElementsKind(to_));
if (!FLAG_trace_elements_transitions) {
if (IsFastSmiOrObjectElementsKind(to_)) {
if (IsFastSmiOrObjectElementsKind(from_)) {
ElementsTransitionGenerator::
GenerateMapChangeElementsTransition(masm, mode, &fail);
} else if (IsFastDoubleElementsKind(from_)) {
ASSERT(!IsFastSmiElementsKind(to_));
ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
} else {
UNREACHABLE();
}
KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
is_jsarray_,
to_,
store_mode_);
} else if (IsFastSmiElementsKind(from_) &&
IsFastDoubleElementsKind(to_)) {
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
is_jsarray_,
store_mode_);
} else if (IsFastDoubleElementsKind(from_)) {
ASSERT(to_ == FAST_HOLEY_DOUBLE_ELEMENTS);
ElementsTransitionGenerator::
GenerateMapChangeElementsTransition(masm, mode, &fail);
} else {
UNREACHABLE();
}
}
masm->bind(&fail);
KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
}
void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) { void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
StubFailureTrampolineStub stub1(NOT_JS_FUNCTION_STUB_MODE); StubFailureTrampolineStub stub1(NOT_JS_FUNCTION_STUB_MODE);
StubFailureTrampolineStub stub2(JS_FUNCTION_STUB_MODE); StubFailureTrampolineStub stub2(JS_FUNCTION_STUB_MODE);

View File

@ -2210,41 +2210,47 @@ class ToBooleanStub: public HydrogenCodeStub {
}; };
class ElementsTransitionAndStoreStub : public PlatformCodeStub { class ElementsTransitionAndStoreStub : public HydrogenCodeStub {
public: public:
ElementsTransitionAndStoreStub(ElementsKind from, ElementsTransitionAndStoreStub(ElementsKind from,
ElementsKind to, ElementsKind to,
bool is_jsarray, bool is_jsarray,
StrictModeFlag strict_mode,
KeyedAccessStoreMode store_mode) KeyedAccessStoreMode store_mode)
: from_(from), : from_(from),
to_(to), to_(to),
is_jsarray_(is_jsarray), is_jsarray_(is_jsarray),
strict_mode_(strict_mode), store_mode_(store_mode) {
store_mode_(store_mode) {} ASSERT(!IsFastHoleyElementsKind(from) || IsFastHoleyElementsKind(to));
private:
class FromBits: public BitField<ElementsKind, 0, 8> {};
class ToBits: public BitField<ElementsKind, 8, 8> {};
class IsJSArrayBits: public BitField<bool, 16, 1> {};
class StrictModeBits: public BitField<StrictModeFlag, 17, 1> {};
class StoreModeBits: public BitField<KeyedAccessStoreMode, 18, 4> {};
Major MajorKey() { return ElementsTransitionAndStore; }
int MinorKey() {
return FromBits::encode(from_) |
ToBits::encode(to_) |
IsJSArrayBits::encode(is_jsarray_) |
StrictModeBits::encode(strict_mode_) |
StoreModeBits::encode(store_mode_);
} }
void Generate(MacroAssembler* masm); ElementsKind from() const { return from_; }
ElementsKind to() const { return to_; }
bool is_jsarray() const { return is_jsarray_; }
KeyedAccessStoreMode store_mode() const { return store_mode_; }
Handle<Code> GenerateCode();
void InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor);
private:
class FromBits: public BitField<ElementsKind, 0, 8> {};
class ToBits: public BitField<ElementsKind, 8, 8> {};
class IsJSArrayBits: public BitField<bool, 16, 1> {};
class StoreModeBits: public BitField<KeyedAccessStoreMode, 17, 4> {};
Major MajorKey() { return ElementsTransitionAndStore; }
int NotMissMinorKey() {
return FromBits::encode(from()) |
ToBits::encode(to()) |
IsJSArrayBits::encode(is_jsarray()) |
StoreModeBits::encode(store_mode());
}
ElementsKind from_; ElementsKind from_;
ElementsKind to_; ElementsKind to_;
bool is_jsarray_; bool is_jsarray_;
StrictModeFlag strict_mode_;
KeyedAccessStoreMode store_mode_; KeyedAccessStoreMode store_mode_;
DISALLOW_COPY_AND_ASSIGN(ElementsTransitionAndStoreStub); DISALLOW_COPY_AND_ASSIGN(ElementsTransitionAndStoreStub);

View File

@ -229,6 +229,15 @@ inline bool CanTransitionToMoreGeneralFastElementsKind(
} }
inline bool DoesTransitionChangeElementsBufferFormat(ElementsKind from_kind,
ElementsKind to_kind) {
return (IsFastSmiElementsKind(from_kind) &&
IsFastDoubleElementsKind(to_kind)) ||
(IsFastDoubleElementsKind(from_kind) &&
IsFastObjectElementsKind(to_kind));
}
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_ELEMENTS_KIND_H_ #endif // V8_ELEMENTS_KIND_H_

View File

@ -187,7 +187,7 @@ DEFINE_implication(harmony_observation, harmony_collections)
// Flags for experimental implementation features. // Flags for experimental implementation features.
DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes") DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values") DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
DEFINE_bool(compiled_transitions, true, "use optimizing compiler to " DEFINE_bool(compiled_transitions, false, "use optimizing compiler to "
"generate array elements transition stubs") "generate array elements transition stubs")
DEFINE_bool(compiled_keyed_stores, true, "use optimizing compiler to " DEFINE_bool(compiled_keyed_stores, true, "use optimizing compiler to "
"generate keyed store stubs") "generate keyed store stubs")

View File

@ -262,6 +262,17 @@ void StoreGlobalStub::InitializeInterfaceDescriptor(
} }
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { eax, ebx, ecx, edx };
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
}
#define __ ACCESS_MASM(masm) #define __ ACCESS_MASM(masm)

View File

@ -2476,6 +2476,24 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
} }
RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) {
SealHandleScope scope(isolate);
ASSERT(args.length() == 4);
KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
Handle<Object> value = args.at<Object>(0);
Handle<Object> key = args.at<Object>(2);
Handle<Object> object = args.at<Object>(3);
StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state);
return Runtime::SetObjectProperty(isolate,
object,
key,
value,
NONE,
strict_mode);
}
void BinaryOpIC::patch(Code* code) { void BinaryOpIC::patch(Code* code) {
set_target(code); set_target(code);
} }

View File

@ -858,6 +858,7 @@ DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure); DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss); DECLARE_RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure); DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss); DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss); DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss);

View File

@ -259,6 +259,17 @@ void StoreGlobalStub::InitializeInterfaceDescriptor(
} }
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { a0, a3, a1, a2 };
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
}
#define __ ACCESS_MASM(masm) #define __ ACCESS_MASM(masm)

View File

@ -1997,7 +1997,6 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
elements_kind, elements_kind,
transitioned_map->elements_kind(), transitioned_map->elements_kind(),
is_js_array, is_js_array,
strict_mode(),
store_mode_).GetCode(isolate()); store_mode_).GetCode(isolate());
} else { } else {
if (FLAG_compiled_keyed_stores && if (FLAG_compiled_keyed_stores &&

View File

@ -258,6 +258,17 @@ void StoreGlobalStub::InitializeInterfaceDescriptor(
} }
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { rax, rbx, rcx, rdx };
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
}
#define __ ACCESS_MASM(masm) #define __ ACCESS_MASM(masm)