Revision: 15512
Author: [email protected]
Date: Fri Jul 5 03:34:02 2013
Log: Generate StoreGlobal stubs with Hydrogen
- Constants globals are inlined into Hydrogen code using code dependencies
that invalidate the Crankshafted code when global PropertyCells or the
global object change.
- The more general case generates code that is just as good as the
hand-written assembly stubs on all platforms.
[email protected], [email protected]
Committed: http://code.google.com/p/v8/source/detail?r=15419
Review URL: https://codereview.chromium.org/16925008
http://code.google.com/p/v8/source/detail?r=15512
Modified:
/branches/bleeding_edge/src/arm/code-stubs-arm.cc
/branches/bleeding_edge/src/arm/lithium-gap-resolver-arm.cc
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/code-stubs-hydrogen.cc
/branches/bleeding_edge/src/code-stubs.cc
/branches/bleeding_edge/src/code-stubs.h
/branches/bleeding_edge/src/heap.cc
/branches/bleeding_edge/src/heap.h
/branches/bleeding_edge/src/hydrogen-instructions.cc
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h
/branches/bleeding_edge/src/ia32/lithium-gap-resolver-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/ic.h
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/stub-cache.cc
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/x64/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/lithium-gap-resolver-x64.cc
/branches/bleeding_edge/test/mjsunit/regress/regress-2618.js
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Fri Jul 5 02:52:11
2013
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Fri Jul 5 03:34:02
2013
@@ -235,6 +235,17 @@
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(UnaryOpIC_Miss);
}
+
+
+void StoreGlobalStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { r1, r2, r0 };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(StoreIC_MissFromStubFailure);
+}
#define __ ACCESS_MASM(masm)
=======================================
--- /branches/bleeding_edge/src/arm/lithium-gap-resolver-arm.cc Mon Jul 1
08:12:21 2013
+++ /branches/bleeding_edge/src/arm/lithium-gap-resolver-arm.cc Fri Jul 5
03:34:02 2013
@@ -219,7 +219,6 @@
ASSERT(destination->IsStackSlot());
__ str(source_register, cgen_->ToMemOperand(destination));
}
-
} else if (source->IsStackSlot()) {
MemOperand source_operand = cgen_->ToMemOperand(source);
if (destination->IsRegister()) {
@@ -255,6 +254,10 @@
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
}
+ } else if (source->IsDoubleRegister()) {
+ DwVfpRegister result = cgen_->ToDoubleRegister(destination);
+ double v = cgen_->ToDouble(constant_source);
+ __ Vmov(result, v, ip);
} else {
ASSERT(destination->IsStackSlot());
ASSERT(!in_cycle_); // Constant moves happen after all cycles are
gone.
=======================================
--- /branches/bleeding_edge/src/ast.cc Mon Jul 1 08:12:21 2013
+++ /branches/bleeding_edge/src/ast.cc Fri Jul 5 03:34:02 2013
@@ -675,6 +675,7 @@
if (is_monomorphic_) {
target_ = oracle->GetCallNewTarget(this);
Object* value = allocation_info_cell_->value();
+ ASSERT(!value->IsTheHole());
if (value->IsSmi()) {
elements_kind_ =
static_cast<ElementsKind>(Smi::cast(value)->value());
}
=======================================
--- /branches/bleeding_edge/src/code-stubs-hydrogen.cc Fri Jul 5 02:26:22
2013
+++ /branches/bleeding_edge/src/code-stubs-hydrogen.cc Fri Jul 5 03:34:02
2013
@@ -809,7 +809,7 @@
IfBuilder if_true(this);
if_true.If<HBranch>(GetParameter(0), stub->GetTypes());
if_true.Then();
- if_true.Return(graph()->GetConstant1());
+ if_true.Return(graph()->GetConstant1());
if_true.Else();
if_true.End();
return graph()->GetConstant0();
@@ -819,6 +819,51 @@
Handle<Code> ToBooleanStub::GenerateCode() {
return DoGenerateCode(this);
}
+
+
+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);
+
+ HParameter* receiver = GetParameter(0);
+ HParameter* value = GetParameter(2);
+
+ if (stub->is_constant()) {
+ // Assume every store to a constant value changes it.
+ current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
+ set_current_block(NULL);
+ } else {
+ HValue* cell = Add<HConstant>(placeholder_cell,
Representation::Tagged());
+ // Check that the map of the global has not changed.
+ AddInstruction(HCheckMaps::New(receiver,
+
Handle<Map>(isolate()->heap()->meta_map()),
+ zone()));
+
+ // Load the payload of the global parameter cell. A hole indicates
that the
+ // property has been deleted and that the store must be handled by the
+ // runtime.
+ HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
+ HValue* cell_contents = Add<HLoadNamedField>(cell, access);
+ IfBuilder builder(this);
+ HValue* hole_value = Add<HConstant>(hole, Representation::Tagged());
+ builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value);
+ builder.Then();
+ builder.Deopt();
+ builder.Else();
+ Add<HStoreNamedField>(cell, access, value);
+ builder.End();
+ }
+ return value;
+}
+
+
+Handle<Code> StoreGlobalStub::GenerateCode() {
+ return DoGenerateCode(this);
+}
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/code-stubs.cc Fri Jul 5 02:52:11 2013
+++ /branches/bleeding_edge/src/code-stubs.cc Fri Jul 5 03:34:02 2013
@@ -83,6 +83,14 @@
Code::Kind CodeStub::GetCodeKind() const {
return Code::STUB;
}
+
+
+Handle<Code> CodeStub::GetCodeCopyFromTemplate(Isolate* isolate) {
+ Handle<Code> ic = GetCode(isolate);
+ ic = isolate->factory()->CopyCode(ic);
+ RecordCodeGeneration(*ic, isolate);
+ return ic;
+}
Handle<Code> PlatformCodeStub::GenerateCode() {
=======================================
--- /branches/bleeding_edge/src/code-stubs.h Fri Jul 5 02:26:22 2013
+++ /branches/bleeding_edge/src/code-stubs.h Fri Jul 5 03:34:02 2013
@@ -90,6 +90,7 @@
V(ArrayConstructor) \
V(InternalArrayConstructor) \
V(ProfileEntryHook) \
+ V(StoreGlobal) \
/* IC Handler stubs */ \
V(LoadField) \
V(KeyedLoadField)
@@ -138,6 +139,8 @@
// Retrieve the code for the stub. Generate the code if needed.
Handle<Code> GetCode(Isolate* isolate);
+ // Retrieve the code for the stub, make and return a copy of the code.
+ Handle<Code> GetCodeCopyFromTemplate(Isolate* isolate);
static Major MajorKeyFromKey(uint32_t key) {
return static_cast<Major>(MajorKeyBits::decode(key));
}
@@ -523,6 +526,50 @@
int MinorKey() { return slots_; }
};
+class StoreGlobalStub : public HydrogenCodeStub {
+ public:
+ StoreGlobalStub(StrictModeFlag strict_mode, bool is_constant) {
+ bit_field_ = StrictModeBits::encode(strict_mode) |
+ IsConstantBits::encode(is_constant);
+ }
+
+ virtual Handle<Code> GenerateCode();
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
+
+ virtual Code::Kind GetCodeKind() const { return Code::STORE_IC; }
+ virtual InlineCacheState GetICState() { return MONOMORPHIC; }
+ virtual Code::ExtraICState GetExtraICState() { return bit_field_; }
+
+ bool is_constant() {
+ return IsConstantBits::decode(bit_field_);
+ }
+ void set_is_constant(bool value) {
+ bit_field_ = IsConstantBits::update(bit_field_, value);
+ }
+
+ Representation representation() {
+ return
Representation::FromKind(RepresentationBits::decode(bit_field_));
+ }
+ void set_representation(Representation r) {
+ bit_field_ = RepresentationBits::update(bit_field_, r.kind());
+ }
+
+ private:
+ virtual int NotMissMinorKey() { return GetExtraICState(); }
+ Major MajorKey() { return StoreGlobal; }
+
+ class StrictModeBits: public BitField<StrictModeFlag, 0, 1> {};
+ class IsConstantBits: public BitField<bool, 1, 1> {};
+ class RepresentationBits: public BitField<Representation::Kind, 2, 8> {};
+
+ int bit_field_;
+
+ DISALLOW_COPY_AND_ASSIGN(StoreGlobalStub);
+};
+
class UnaryOpStub : public HydrogenCodeStub {
public:
=======================================
--- /branches/bleeding_edge/src/heap.cc Fri Jul 5 02:52:11 2013
+++ /branches/bleeding_edge/src/heap.cc Fri Jul 5 03:34:02 2013
@@ -2855,9 +2855,9 @@
MaybeObject* Heap::AllocatePropertyCell(Object* value) {
Object* result;
- { MaybeObject* maybe_result = AllocateRawPropertyCell();
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ MaybeObject* maybe_result = AllocateRawPropertyCell();
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+
HeapObject::cast(result)->set_map_no_write_barrier(
global_property_cell_map());
PropertyCell* cell = PropertyCell::cast(result);
@@ -2865,6 +2865,8 @@
SKIP_WRITE_BARRIER);
cell->set_value(value);
cell->set_type(Type::None());
+ maybe_result = cell->SetValueInferType(value);
+ if (maybe_result->IsFailure()) return maybe_result;
return result;
}
=======================================
--- /branches/bleeding_edge/src/heap.h Fri Jul 5 02:36:11 2013
+++ /branches/bleeding_edge/src/heap.h Fri Jul 5 03:34:02 2013
@@ -261,6 +261,7 @@
V(map_field_string, "%map") \
V(elements_field_string, "%elements") \
V(length_field_string, "%length") \
+ V(cell_value_string, "%cell_value") \
V(function_class_string, "Function") \
V(properties_field_symbol, "%properties") \
V(payload_field_symbol, "%payload") \
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Fri Jul 5
02:52:11 2013
+++ /branches/bleeding_edge/src/hydrogen-instructions.cc Fri Jul 5
03:34:02 2013
@@ -2175,6 +2175,7 @@
has_double_value_(false),
is_internalized_string_(false),
is_not_in_new_space_(true),
+ is_cell_(false),
boolean_value_(handle->BooleanValue()) {
if (handle_->IsHeapObject()) {
Heap* heap = Handle<HeapObject>::cast(handle)->GetHeap();
@@ -2191,6 +2192,9 @@
type_from_value_ = HType::TypeFromValue(handle_);
is_internalized_string_ = handle_->IsInternalizedString();
}
+
+ is_cell_ = !handle_.is_null() &&
+ (handle_->IsCell() || handle_->IsPropertyCell());
Initialize(r);
}
@@ -2201,6 +2205,7 @@
HType type,
bool is_internalize_string,
bool is_not_in_new_space,
+ bool is_cell,
bool boolean_value)
: handle_(handle),
unique_id_(unique_id),
@@ -2209,6 +2214,7 @@
has_double_value_(false),
is_internalized_string_(is_internalize_string),
is_not_in_new_space_(is_not_in_new_space),
+ is_cell_(is_cell),
boolean_value_(boolean_value),
type_from_value_(type) {
ASSERT(!handle.is_null());
@@ -2228,6 +2234,7 @@
has_double_value_(true),
is_internalized_string_(false),
is_not_in_new_space_(is_not_in_new_space),
+ is_cell_(false),
boolean_value_(integer_value != 0),
int32_value_(integer_value),
double_value_(FastI2D(integer_value)) {
@@ -2246,6 +2253,7 @@
has_double_value_(true),
is_internalized_string_(false),
is_not_in_new_space_(is_not_in_new_space),
+ is_cell_(false),
boolean_value_(double_value != 0 && !std::isnan(double_value)),
int32_value_(DoubleToInt32(double_value)),
double_value_(double_value) {
@@ -2268,9 +2276,17 @@
}
set_representation(r);
SetFlag(kUseGVN);
- if (representation().IsInteger32()) {
- ClearGVNFlag(kDependsOnOsrEntries);
+}
+
+
+bool HConstant::EmitAtUses() {
+ ASSERT(IsLinked());
+ if (block()->graph()->has_osr()) {
+ return block()->graph()->IsStandardConstant(this);
}
+ if (IsCell()) return false;
+ if (representation().IsDouble()) return false;
+ return true;
}
@@ -2291,6 +2307,7 @@
type_from_value_,
is_internalized_string_,
is_not_in_new_space_,
+ is_cell_,
boolean_value_);
}
@@ -3828,6 +3845,13 @@
return HObjectAccess(kBackingStore, offset, name);
}
}
+
+
+HObjectAccess HObjectAccess::ForCellPayload(Isolate* isolate) {
+ return HObjectAccess(
+ kInobject, Cell::kValueOffset,
+ Handle<String>(isolate->heap()->cell_value_string()));
+}
void HObjectAccess::SetGVNFlags(HValue *instr, bool is_store) {
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Fri Jul 5 02:26:22
2013
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Fri Jul 5 03:34:02
2013
@@ -3291,6 +3291,7 @@
HType type,
bool is_internalized_string,
bool is_not_in_new_space,
+ bool is_cell,
bool boolean_value);
Handle<Object> handle() {
@@ -3338,6 +3339,10 @@
unique_id_ == UniqueValueId(heap->the_hole_value()) ||
unique_id_ == UniqueValueId(heap->empty_string());
}
+
+ bool IsCell() const {
+ return is_cell_;
+ }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
@@ -3350,7 +3355,7 @@
return Representation::Tagged();
}
- virtual bool EmitAtUses() { return !representation().IsDouble(); }
+ virtual bool EmitAtUses();
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
bool IsInteger() { return handle()->IsSmi(); }
@@ -3465,6 +3470,7 @@
bool has_double_value_ : 1;
bool is_internalized_string_ : 1; // TODO(yangguo): make this part of
HType.
bool is_not_in_new_space_ : 1;
+ bool is_cell_ : 1;
bool boolean_value_ : 1;
int32_t int32_value_;
double double_value_;
@@ -5118,6 +5124,9 @@
HInnerAllocatedObject::cast(object)->base_object(),
new_space_dominator);
}
+ if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
+ return false;
+ }
if (object != new_space_dominator) return true;
if (object->IsAllocateObject()) return false;
if (object->IsAllocate()) {
@@ -5379,6 +5388,9 @@
static HObjectAccess ForField(Handle<Map> map,
LookupResult *lookup, Handle<String> name = Handle<String>::null());
+ // Create an access for the payload of a Cell or JSGlobalPropertyCell.
+ static HObjectAccess ForCellPayload(Isolate* isolate);
+
void PrintTo(StringStream* stream);
inline bool Equals(HObjectAccess that) const {
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Fri Jul 5 02:52:11 2013
+++ /branches/bleeding_edge/src/hydrogen.cc Fri Jul 5 03:34:02 2013
@@ -1,4 +1,4 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
+// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -649,6 +649,7 @@
htype, \
false, \
true, \
+
false, \
boolean_value); \
constant->InsertAfter(GetConstantUndefined()); \
constant_##name##_.set(constant); \
@@ -669,6 +670,19 @@
HConstant* HGraph::GetInvalidContext() {
return GetConstant(&constant_invalid_context_, 0xFFFFC0C7);
}
+
+
+bool HGraph::IsStandardConstant(HConstant* constant) {
+ if (constant == GetConstantUndefined()) return true;
+ if (constant == GetConstant0()) return true;
+ if (constant == GetConstant1()) return true;
+ if (constant == GetConstantMinus1()) return true;
+ if (constant == GetConstantTrue()) return true;
+ if (constant == GetConstantFalse()) return true;
+ if (constant == GetConstantHole()) return true;
+ if (constant == GetConstantNull()) return true;
+ return false;
+}
HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, int position)
@@ -1005,9 +1019,9 @@
}
-void HGraphBuilder::AddSoftDeoptimize() {
+void HGraphBuilder::AddSoftDeoptimize(SoftDeoptimizeMode mode) {
isolate()->counters()->soft_deopts_requested()->Increment();
- if (FLAG_always_opt) return;
+ if (FLAG_always_opt && mode == CAN_OMIT_SOFT_DEOPT) return;
if (current_block()->IsDeoptimizing()) return;
Add<HSoftDeoptimize>();
isolate()->counters()->soft_deopts_inserted()->Increment();
@@ -4998,9 +5012,20 @@
if (type == kUseCell) {
Handle<GlobalObject> global(current_info()->global_object());
Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
- HLoadGlobalCell* instr =
- new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails());
- return ast_context()->ReturnInstruction(instr, expr->id());
+ if (cell->type()->IsConstant()) {
+ cell->AddDependentCompilationInfo(top_info());
+ Handle<Object> constant_object = cell->type()->AsConstant();
+ if (constant_object->IsConsString()) {
+ constant_object =
+ FlattenGetString(Handle<String>::cast(constant_object));
+ }
+ HConstant* constant = new(zone()) HConstant(constant_object);
+ return ast_context()->ReturnInstruction(constant, expr->id());
+ } else {
+ HLoadGlobalCell* instr =
+ new(zone()) HLoadGlobalCell(cell,
lookup.GetPropertyDetails());
+ return ast_context()->ReturnInstruction(instr, expr->id());
+ }
} else {
HValue* context = environment()->LookupContext();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
@@ -5911,8 +5936,21 @@
if (type == kUseCell) {
Handle<GlobalObject> global(current_info()->global_object());
Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
- HInstruction* instr = Add<HStoreGlobalCell>(value, cell,
-
lookup.GetPropertyDetails());
+ if (cell->type()->IsConstant()) {
+ IfBuilder builder(this);
+ HValue* constant = Add<HConstant>(cell->type()->AsConstant());
+ if (cell->type()->AsConstant()->IsNumber()) {
+ builder.IfCompare(value, constant, Token::EQ);
+ } else {
+ builder.If<HCompareObjectEqAndBranch>(value, constant);
+ }
+ builder.Then();
+ builder.Else();
+ AddSoftDeoptimize(MUST_EMIT_SOFT_DEOPT);
+ builder.End();
+ }
+ HInstruction* instr =
+ Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails());
instr->set_position(position);
if (instr->HasObservableSideEffects()) {
AddSimulate(ast_id, REMOVABLE_SIMULATE);
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Fri Jul 5 02:26:22 2013
+++ /branches/bleeding_edge/src/hydrogen.h Fri Jul 5 03:34:02 2013
@@ -333,6 +333,8 @@
HConstant* GetConstantNull();
HConstant* GetInvalidContext();
+ bool IsStandardConstant(HConstant* constant);
+
HBasicBlock* CreateBasicBlock();
HArgumentsObject* GetArgumentsObject() const {
return arguments_object_.get();
@@ -1131,7 +1133,12 @@
HValue* AddLoadJSBuiltin(Builtins::JavaScript builtin, HContext*
context);
- void AddSoftDeoptimize();
+ enum SoftDeoptimizeMode {
+ MUST_EMIT_SOFT_DEOPT,
+ CAN_OMIT_SOFT_DEOPT
+ };
+
+ void AddSoftDeoptimize(SoftDeoptimizeMode mode = CAN_OMIT_SOFT_DEOPT);
class IfBuilder {
public:
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Fri Jul 5 02:26:22
2013
+++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Fri Jul 5 03:34:02
2013
@@ -239,6 +239,17 @@
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(UnaryOpIC_Miss);
}
+
+
+void StoreGlobalStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { edx, ecx, eax };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(StoreIC_MissFromStubFailure);
+}
#define __ ACCESS_MASM(masm)
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Mon Jul 1
08:12:21 2013
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Fri Jul 5
03:34:02 2013
@@ -115,6 +115,7 @@
Immediate ToSmiImmediate(LOperand* op) const {
return
Immediate(Smi::FromInt(ToInteger32(LConstantOperand::cast(op))));
}
+ double ToDouble(LConstantOperand* op) const;
// Support for non-sse2 (x87) floating point stack handling.
// These functions maintain the depth of the stack (either 0 or 1)
@@ -293,7 +294,6 @@
XMMRegister ToDoubleRegister(int index) const;
int ToInteger32(LConstantOperand* op) const;
- double ToDouble(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
Representation key_representation,
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-gap-resolver-ia32.cc Mon Jul
1 08:12:21 2013
+++ /branches/bleeding_edge/src/ia32/lithium-gap-resolver-ia32.cc Fri Jul
5 03:34:02 2013
@@ -313,6 +313,31 @@
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
}
+ } else if (destination->IsDoubleRegister()) {
+ double v = cgen_->ToDouble(constant_source);
+ uint64_t int_val = BitCast<uint64_t, double>(v);
+ int32_t lower = static_cast<int32_t>(int_val);
+ int32_t upper = static_cast<int32_t>(int_val >> kBitsPerInt);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatureScope scope(cgen_->masm(), SSE2);
+ XMMRegister dst = cgen_->ToDoubleRegister(destination);
+ if (int_val == 0) {
+ __ xorps(dst, dst);
+ } else {
+ __ push(Immediate(upper));
+ __ push(Immediate(lower));
+ __ movdbl(dst, Operand(esp, 0));
+ __ add(esp, Immediate(kDoubleSize));
+ }
+ } else {
+ __ push(Immediate(upper));
+ __ push(Immediate(lower));
+ if (cgen_->X87StackNonEmpty()) {
+ cgen_->PopX87();
+ }
+ cgen_->PushX87DoubleOperand(MemOperand(esp, 0));
+ __ add(esp, Immediate(kDoubleSize));
+ }
} else {
ASSERT(destination->IsStackSlot());
Operand dst = cgen_->ToOperand(destination);
=======================================
--- /branches/bleeding_edge/src/ic.cc Fri Jul 5 02:26:22 2013
+++ /branches/bleeding_edge/src/ic.cc Fri Jul 5 03:34:02 2013
@@ -1668,7 +1668,7 @@
ASSERT(!lookup->IsHandler());
Handle<Code> code = ComputeStoreMonomorphic(
- lookup, strict_mode, receiver, name);
+ lookup, strict_mode, receiver, name, value);
if (code.is_null()) {
Handle<Code> stub = strict_mode == kStrictMode
? generic_stub_strict() : generic_stub();
@@ -1684,7 +1684,8 @@
Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
- Handle<String> name) {
+ Handle<String> name,
+ Handle<Object> value) {
Handle<JSObject> holder(lookup->holder());
switch (lookup->type()) {
case FIELD:
@@ -1699,7 +1700,7 @@
Handle<PropertyCell> cell(
global->GetPropertyCell(lookup), isolate());
return isolate()->stub_cache()->ComputeStoreGlobal(
- name, global, cell, strict_mode);
+ name, global, cell, value, strict_mode);
}
ASSERT(holder.is_identical_to(receiver));
return isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
@@ -2093,7 +2094,8 @@
Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag
strict_mode,
Handle<JSObject>
receiver,
- Handle<String> name) {
+ Handle<String> name,
+ Handle<Object> value) {
// If the property has a non-field type allowing map transitions
// where there is extra room in the object, we leave the IC in its
// current state.
@@ -2243,6 +2245,20 @@
args.at<String>(1),
args.at<Object>(2));
}
+
+
+RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 3);
+ StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
+ Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
+ return ic.Store(state,
+ Code::GetStrictMode(extra_ic_state),
+ args.at<Object>(0),
+ args.at<String>(1),
+ args.at<Object>(2));
+}
RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
=======================================
--- /branches/bleeding_edge/src/ic.h Fri Jul 5 02:26:22 2013
+++ /branches/bleeding_edge/src/ic.h Fri Jul 5 03:34:02 2013
@@ -559,7 +559,8 @@
virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
- Handle<String> name);
+ Handle<String> name,
+ Handle<Object> value);
private:
void set_target(Code* code) {
@@ -626,7 +627,8 @@
virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
- Handle<String> name);
+ Handle<String> name,
+ Handle<Object> value);
virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { }
virtual Handle<Code> megamorphic_stub() {
@@ -819,6 +821,7 @@
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss);
+DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss);
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Tue Jul 2 08:32:46 2013
+++ /branches/bleeding_edge/src/objects-inl.h Fri Jul 5 03:34:02 2013
@@ -3787,6 +3787,7 @@
kind() == BINARY_OP_IC ||
kind() == COMPARE_IC ||
kind() == COMPARE_NIL_IC ||
+ kind() == STORE_IC ||
kind() == LOAD_IC ||
kind() == KEYED_LOAD_IC ||
kind() == TO_BOOLEAN_IC);
=======================================
--- /branches/bleeding_edge/src/objects.cc Fri Jul 5 02:52:11 2013
+++ /branches/bleeding_edge/src/objects.cc Fri Jul 5 03:34:02 2013
@@ -630,12 +630,23 @@
}
-Object* JSObject::SetNormalizedProperty(LookupResult* result, Object*
value) {
+Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
+ LookupResult* result,
+ Handle<Object> value) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetNormalizedProperty(result, *value),
+ Object);
+}
+
+
+MaybeObject* JSObject::SetNormalizedProperty(LookupResult* result,
+ Object* value) {
ASSERT(!HasFastProperties());
if (IsGlobalObject()) {
PropertyCell* cell = PropertyCell::cast(
property_dictionary()->ValueAt(result->GetDictionaryEntry()));
- cell->set_value(value);
+ MaybeObject* maybe_type = cell->SetValueInferType(value);
+ if (maybe_type->IsFailure()) return maybe_type;
} else {
property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
}
@@ -691,7 +702,8 @@
if (IsGlobalObject()) {
PropertyCell* cell =
PropertyCell::cast(property_dictionary()->ValueAt(entry));
- cell->set_value(value);
+ MaybeObject* maybe_type = cell->SetValueInferType(value);
+ if (maybe_type->IsFailure()) return maybe_type;
// Please note we have to update the property details.
property_dictionary()->DetailsAtPut(entry, details);
} else {
@@ -723,7 +735,9 @@
set_map(new_map);
}
PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry));
- cell->set_value(cell->GetHeap()->the_hole_value());
+ MaybeObject* maybe_type =
+ cell->SetValueInferType(cell->GetHeap()->the_hole_value());
+ if (maybe_type->IsFailure()) return maybe_type;
dictionary->DetailsAtPut(entry, details.AsDeleted());
} else {
Object* deleted = dictionary->DeleteProperty(entry, mode);
@@ -1930,7 +1944,9 @@
int entry = dict->FindEntry(name);
if (entry != NameDictionary::kNotFound) {
store_value = dict->ValueAt(entry);
- PropertyCell::cast(store_value)->set_value(value);
+ MaybeObject* maybe_type =
+ PropertyCell::cast(store_value)->SetValueInferType(value);
+ if (maybe_type->IsFailure()) return maybe_type;
// Assign an enumeration index to the property and update
// SetNextEnumerationIndex.
int index = dict->NextEnumerationIndex();
@@ -1944,7 +1960,9 @@
heap->AllocatePropertyCell(value);
if (!maybe_store_value->ToObject(&store_value)) return
maybe_store_value;
}
- PropertyCell::cast(store_value)->set_value(value);
+ MaybeObject* maybe_type =
+ PropertyCell::cast(store_value)->SetValueInferType(value);
+ if (maybe_type->IsFailure()) return maybe_type;
}
PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
Object* result;
@@ -15811,6 +15829,46 @@
void PropertyCell::set_type(Type* type, WriteBarrierMode ignored) {
set_type_raw(type, ignored);
}
+
+
+Type* PropertyCell::UpdateType(Handle<PropertyCell> cell,
+ Handle<Object> value) {
+ Isolate* isolate = cell->GetIsolate();
+ Handle<Type> old_type(cell->type(), isolate);
+ Handle<Type> new_type((value->IsSmi() || value->IsUndefined())
+ ? Type::Constant(value, isolate)
+ : Type::Any(), isolate);
+
+ if (new_type->Is(old_type)) {
+ return *old_type;
+ }
+
+ cell->dependent_code()->DeoptimizeDependentCodeGroup(
+ isolate, DependentCode::kPropertyCellChangedGroup);
+
+ if (old_type->Is(Type::None()) || old_type->Is(Type::Undefined())) {
+ return *new_type;
+ }
+
+ return Type::Any();
+}
+
+
+MaybeObject* PropertyCell::SetValueInferType(Object* value,
+ WriteBarrierMode ignored) {
+ set_value(value, ignored);
+ if (!Type::Any()->Is(type())) {
+ IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
+ MaybeObject* maybe_type = trampoline.CallWithReturnValue(
+ &PropertyCell::UpdateType,
+ Handle<PropertyCell>(this),
+ Handle<Object>(value, GetIsolate()));
+ if (maybe_type->IsFailure()) return maybe_type;
+ Type* new_type = static_cast<Type*>(maybe_type);
+ set_type(new_type);
+ }
+ return value;
+}
void PropertyCell::AddDependentCompilationInfo(CompilationInfo* info) {
=======================================
--- /branches/bleeding_edge/src/objects.h Fri Jul 5 03:12:36 2013
+++ /branches/bleeding_edge/src/objects.h Fri Jul 5 03:34:02 2013
@@ -1886,9 +1886,16 @@
// Handles the special representation of JS global objects.
Object* GetNormalizedProperty(LookupResult* result);
+ // Sets the property value in a normalized object given (key, value).
+ // Handles the special representation of JS global objects.
+ static Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
+ LookupResult* result,
+ Handle<Object> value);
+
// Sets the property value in a normalized object given a lookup result.
// Handles the special representation of JS global objects.
- Object* SetNormalizedProperty(LookupResult* result, Object* value);
+ MUST_USE_RESULT MaybeObject* SetNormalizedProperty(LookupResult* result,
+ Object* value);
// Sets the property value in a normalized object given (key, value,
details).
// Handles the special representation of JS global objects.
@@ -8583,6 +8590,14 @@
// property.
DECL_ACCESSORS(dependent_code, DependentCode)
+ // Sets the value of the cell and updates the type field to be the union
+ // of the cell's current type and the value's type. If the change causes
+ // a change of the type of the cell's contents, code dependent on the
cell
+ // will be deoptimized.
+ MUST_USE_RESULT MaybeObject* SetValueInferType(
+ Object* value,
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
// Casting.
static inline PropertyCell* cast(Object* obj);
@@ -8610,6 +8625,9 @@
void AddDependentCode(Handle<Code> code);
+ static Type* UpdateType(Handle<PropertyCell> cell,
+ Handle<Object> value);
+
private:
DECL_ACCESSORS(type_raw, Object)
DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyCell);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Fri Jul 5 03:12:36 2013
+++ /branches/bleeding_edge/src/runtime.cc Fri Jul 5 03:34:02 2013
@@ -2121,7 +2121,8 @@
} else if (lookup.IsNormal()) {
if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
!lookup.IsReadOnly()) {
- global->SetNormalizedProperty(&lookup, *value);
+ HandleScope scope(isolate);
+ JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup,
value);
}
} else {
// Ignore re-initialization of constants that have already been
@@ -2210,7 +2211,7 @@
}
} else if (lookup.IsNormal()) {
if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
- object->SetNormalizedProperty(&lookup, *value);
+ JSObject::SetNormalizedProperty(object, &lookup, value);
}
} else {
// We should not reach here. Any real, named property should be
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc Fri Jul 5 02:52:11 2013
+++ /branches/bleeding_edge/src/stub-cache.cc Fri Jul 5 03:34:02 2013
@@ -499,15 +499,30 @@
Handle<Code> StubCache::ComputeStoreGlobal(Handle<Name> name,
Handle<GlobalObject> receiver,
Handle<PropertyCell> cell,
+ Handle<Object> value,
StrictModeFlag strict_mode) {
- Handle<Code> stub = FindIC(
+ Isolate* isolate = cell->GetIsolate();
+ Handle<Type> union_type(PropertyCell::UpdateType(cell, value), isolate);
+ bool is_constant = union_type->IsConstant();
+ StoreGlobalStub stub(strict_mode, is_constant);
+
+ Handle<Code> code = FindIC(
name, Handle<JSObject>::cast(receiver),
- Code::STORE_IC, Code::NORMAL, strict_mode);
- if (!stub.is_null()) return stub;
+ Code::STORE_IC, Code::NORMAL, stub.GetExtraICState());
+ if (!code.is_null()) return code;
- StoreStubCompiler compiler(isolate_, strict_mode);
- Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
+ if (is_constant) return stub.GetCode(isolate_);
+
+ // Replace the placeholder cell and global object map with the actual
global
+ // cell and receiver map.
+ Handle<Map> cell_map(isolate_->heap()->global_property_cell_map());
+ Handle<Map> meta_map(isolate_->heap()->meta_map());
+ Handle<Object> receiver_map(receiver->map(), isolate_);
+ code = stub.GetCodeCopyFromTemplate(isolate_);
+ code->ReplaceNthObject(1, *meta_map, *receiver_map);
+ code->ReplaceNthObject(1, *cell_map, *cell);
JSObject::UpdateMapCodeCache(receiver, name, code);
+
return code;
}
@@ -922,12 +937,8 @@
if (!cached_ic.is_null()) return cached_ic;
}
- Handle<Code> ic = stub.GetCode(isolate_);
-
- // For monomorphic maps, use the code as a template, copying and
replacing
- // the monomorphic map that checks the object's type.
- ic = isolate_->factory()->CopyCode(ic);
- ic->ReplaceFirstMap(*receiver_map);
+ Handle<Code> ic = stub.GetCodeCopyFromTemplate(isolate_);
+ ic->ReplaceNthObject(1, isolate_->heap()->meta_map(), *receiver_map);
if (!receiver_map->is_shared()) {
Map::UpdateCodeCache(receiver_map, name, ic);
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Mon Jul 1 08:12:21 2013
+++ /branches/bleeding_edge/src/stub-cache.h Fri Jul 5 03:34:02 2013
@@ -184,6 +184,7 @@
Handle<Code> ComputeStoreGlobal(Handle<Name> name,
Handle<GlobalObject> object,
Handle<PropertyCell> cell,
+ Handle<Object> value,
StrictModeFlag strict_mode);
Handle<Code> ComputeStoreCallback(Handle<Name> name,
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Fri Jul 5 02:52:11
2013
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Fri Jul 5 03:34:02
2013
@@ -1,4 +1,4 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
+// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -235,6 +235,17 @@
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(UnaryOpIC_Miss);
}
+
+
+void StoreGlobalStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { rdx, rcx, rax };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(StoreIC_MissFromStubFailure);
+}
#define __ ACCESS_MASM(masm)
=======================================
--- /branches/bleeding_edge/src/x64/lithium-gap-resolver-x64.cc Mon Jul 1
08:12:21 2013
+++ /branches/bleeding_edge/src/x64/lithium-gap-resolver-x64.cc Fri Jul 5
03:34:02 2013
@@ -202,6 +202,20 @@
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
}
+ } else if (destination->IsDoubleRegister()) {
+ double v = cgen_->ToDouble(constant_source);
+ uint64_t int_val = BitCast<uint64_t, double>(v);
+ int32_t lower = static_cast<int32_t>(int_val);
+ int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
+ XMMRegister dst = cgen_->ToDoubleRegister(destination);
+ if (int_val == 0) {
+ __ xorps(dst, dst);
+ } else {
+ __ push(Immediate(upper));
+ __ push(Immediate(lower));
+ __ movsd(dst, Operand(rsp, 0));
+ __ addq(rsp, Immediate(kDoubleSize));
+ }
} else {
ASSERT(destination->IsStackSlot());
Operand dst = cgen_->ToOperand(destination);
=======================================
--- /branches/bleeding_edge/test/mjsunit/regress/regress-2618.js Mon Jul 1
08:12:21 2013
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-2618.js Fri Jul 5
03:34:02 2013
@@ -30,7 +30,7 @@
function f() {
do {
do {
- for (i = 0; i < 10000000; i++) {
+ for (var i = 0; i < 10000000; i++) {
// This should run long enough to trigger OSR.
}
} while (false);
@@ -46,7 +46,7 @@
do {
do {
- for (i = 0; i < 1; i++) { }
+ for (var i = 0; i < 1; i++) { }
} while (false);
} while (false);
@@ -58,7 +58,7 @@
do {
do {
do {
- for (i = 0; i < 10000000; i++) { }
+ for (var i = 0; i < 10000000; i++) { }
} while (false);
} while (false);
} while (false);
--
--
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.