Don't add code dependencies eagerly for HCheckMaps.

Instead of adding code dependencies on stable during
graph creation, we now add them during code generation
for those HCheckMaps that survived dead code elimination.

R=svenpanne@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@21139 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-05-05 11:03:14 +00:00
parent 5883de41cc
commit 785bdf7c1e
25 changed files with 217 additions and 172 deletions

View File

@ -1976,15 +1976,12 @@ LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
LOperand* value = NULL; if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
if (!instr->CanOmitMapChecks()) { LOperand* value = UseRegisterAtStart(instr->value());
value = UseRegisterAtStart(instr->value()); LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); if (instr->HasMigrationTarget()) {
} info()->MarkAsDeferredCalling();
LInstruction* result = new(zone()) LCheckMaps(value); result = AssignPointerMap(result);
if (!instr->CanOmitMapChecks()) {
result = AssignEnvironment(result);
if (instr->has_migration_target()) result = AssignPointerMap(result);
} }
return result; return result;
} }

View File

@ -2375,7 +2375,7 @@ class LCheckInstanceType V8_FINAL : public LTemplateInstruction<0, 1, 0> {
class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 0> { class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 0> {
public: public:
explicit LCheckMaps(LOperand* value) { explicit LCheckMaps(LOperand* value = NULL) {
inputs_[0] = value; inputs_[0] = value;
} }

View File

@ -5140,7 +5140,14 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
Register object_; Register object_;
}; };
if (instr->hydrogen()->CanOmitMapChecks()) return; if (instr->hydrogen()->IsStabilityCheck()) {
const UniqueSet<Map>* maps = instr->hydrogen()->maps();
for (int i = 0; i < maps->size(); ++i) {
AddStabilityDependency(maps->at(i).handle());
}
return;
}
Register map_reg = scratch0(); Register map_reg = scratch0();
LOperand* input = instr->value(); LOperand* input = instr->value();
@ -5150,7 +5157,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
__ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
DeferredCheckMaps* deferred = NULL; DeferredCheckMaps* deferred = NULL;
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
deferred = new(zone()) DeferredCheckMaps(this, instr, reg); deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
__ bind(deferred->check_maps()); __ bind(deferred->check_maps());
} }
@ -5165,7 +5172,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
Handle<Map> map = maps->at(maps->size() - 1).handle(); Handle<Map> map = maps->at(maps->size() - 1).handle();
__ CompareMap(map_reg, map, &success); __ CompareMap(map_reg, map, &success);
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
__ b(ne, deferred->entry()); __ b(ne, deferred->entry());
} else { } else {
DeoptimizeIf(ne, instr->environment()); DeoptimizeIf(ne, instr->environment());

View File

@ -1169,17 +1169,13 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
LOperand* value = NULL; if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
LOperand* temp = NULL; LOperand* value = UseRegisterAtStart(instr->value());
if (!instr->CanOmitMapChecks()) { LOperand* temp = TempRegister();
value = UseRegisterAtStart(instr->value()); LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value, temp));
temp = TempRegister(); if (instr->HasMigrationTarget()) {
if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); info()->MarkAsDeferredCalling();
} result = AssignPointerMap(result);
LInstruction* result = new(zone()) LCheckMaps(value, temp);
if (!instr->CanOmitMapChecks()) {
result = AssignEnvironment(result);
if (instr->has_migration_target()) result = AssignPointerMap(result);
} }
return result; return result;
} }

View File

@ -908,7 +908,7 @@ class LCheckInstanceType V8_FINAL : public LTemplateInstruction<0, 1, 1> {
class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 1> { class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 1> {
public: public:
explicit LCheckMaps(LOperand* value, LOperand* temp) { LCheckMaps(LOperand* value = NULL, LOperand* temp = NULL) {
inputs_[0] = value; inputs_[0] = value;
temps_[0] = temp; temps_[0] = temp;
} }

View File

@ -2115,9 +2115,11 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
Register object_; Register object_;
}; };
if (instr->hydrogen()->CanOmitMapChecks()) { if (instr->hydrogen()->IsStabilityCheck()) {
ASSERT(instr->value() == NULL); const UniqueSet<Map>* maps = instr->hydrogen()->maps();
ASSERT(instr->temp() == NULL); for (int i = 0; i < maps->size(); ++i) {
AddStabilityDependency(maps->at(i).handle());
}
return; return;
} }
@ -2127,7 +2129,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
__ Ldr(map_reg, FieldMemOperand(object, HeapObject::kMapOffset)); __ Ldr(map_reg, FieldMemOperand(object, HeapObject::kMapOffset));
DeferredCheckMaps* deferred = NULL; DeferredCheckMaps* deferred = NULL;
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
deferred = new(zone()) DeferredCheckMaps(this, instr, object); deferred = new(zone()) DeferredCheckMaps(this, instr, object);
__ Bind(deferred->check_maps()); __ Bind(deferred->check_maps());
} }
@ -2143,7 +2145,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
__ CompareMap(map_reg, map); __ CompareMap(map_reg, map);
// We didn't match a map. // We didn't match a map.
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
__ B(ne, deferred->entry()); __ B(ne, deferred->entry());
} else { } else {
DeoptimizeIf(ne, instr->environment()); DeoptimizeIf(ne, instr->environment());

View File

@ -1042,7 +1042,7 @@ HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
Handle<Map> placeholder_map = isolate()->factory()->meta_map(); Handle<Map> placeholder_map = isolate()->factory()->meta_map();
HValue* global = Add<HConstant>( HValue* global = Add<HConstant>(
StoreGlobalStub::global_placeholder(isolate())); StoreGlobalStub::global_placeholder(isolate()));
Add<HCheckMaps>(global, placeholder_map, top_info()); Add<HCheckMaps>(global, placeholder_map);
} }
HValue* cell = Add<HConstant>(placeholder_cell); HValue* cell = Add<HConstant>(placeholder_cell);

View File

@ -1675,7 +1675,27 @@ void HCheckMaps::PrintDataTo(StringStream* stream) {
for (int i = 1; i < maps()->size(); ++i) { for (int i = 1; i < maps()->size(); ++i) {
stream->Add(",%p", *maps()->at(i).handle()); stream->Add(",%p", *maps()->at(i).handle());
} }
stream->Add("]%s", CanOmitMapChecks() ? "(omitted)" : ""); stream->Add("]%s", IsStabilityCheck() ? "(stability-check)" : "");
}
HValue* HCheckMaps::Canonicalize() {
if (!IsStabilityCheck() && maps_are_stable() && value()->IsConstant()) {
HConstant* c_value = HConstant::cast(value());
if (c_value->HasObjectMap() && c_value->ObjectMapIsStable()) {
for (int i = 0; i < maps()->size(); ++i) {
if (c_value->ObjectMap() == maps()->at(i)) {
if (maps()->size() > 1) {
set_maps(new(block()->graph()->zone()) UniqueSet<Map>(
maps()->at(i), block()->graph()->zone()));
}
MarkAsStabilityCheck();
break;
}
}
}
}
return this;
} }
@ -2661,26 +2681,30 @@ static bool IsInteger32(double value) {
} }
HConstant::HConstant(Handle<Object> handle, Representation r) HConstant::HConstant(Handle<Object> object, Representation r)
: HTemplateInstruction<0>(HType::TypeFromValue(handle)), : HTemplateInstruction<0>(HType::TypeFromValue(object)),
object_(Unique<Object>::CreateUninitialized(handle)), object_(Unique<Object>::CreateUninitialized(object)),
object_map_(Handle<Map>::null()),
object_map_is_stable_(false),
has_smi_value_(false), has_smi_value_(false),
has_int32_value_(false), has_int32_value_(false),
has_double_value_(false), has_double_value_(false),
has_external_reference_value_(false), has_external_reference_value_(false),
is_not_in_new_space_(true), is_not_in_new_space_(true),
boolean_value_(handle->BooleanValue()), boolean_value_(object->BooleanValue()),
is_undetectable_(false), is_undetectable_(false),
instance_type_(kUnknownInstanceType) { instance_type_(kUnknownInstanceType) {
if (handle->IsHeapObject()) { if (object->IsHeapObject()) {
Handle<HeapObject> heap_obj = Handle<HeapObject>::cast(handle); Isolate* isolate = Handle<HeapObject>::cast(object)->GetIsolate();
Heap* heap = heap_obj->GetHeap(); Handle<Map> map(Handle<HeapObject>::cast(object)->map(), isolate);
is_not_in_new_space_ = !heap->InNewSpace(*handle); is_not_in_new_space_ = !isolate->heap()->InNewSpace(*object);
instance_type_ = heap_obj->map()->instance_type(); instance_type_ = map->instance_type();
is_undetectable_ = heap_obj->map()->is_undetectable(); is_undetectable_ = map->is_undetectable();
object_map_ = Unique<Map>::CreateImmovable(map);
object_map_is_stable_ = map->is_stable();
} }
if (handle->IsNumber()) { if (object->IsNumber()) {
double n = handle->Number(); double n = object->Number();
has_int32_value_ = IsInteger32(n); has_int32_value_ = IsInteger32(n);
int32_value_ = DoubleToInt32(n); int32_value_ = DoubleToInt32(n);
has_smi_value_ = has_int32_value_ && Smi::IsValid(int32_value_); has_smi_value_ = has_int32_value_ && Smi::IsValid(int32_value_);
@ -2702,6 +2726,8 @@ HConstant::HConstant(Unique<Object> unique,
InstanceType instance_type) InstanceType instance_type)
: HTemplateInstruction<0>(type), : HTemplateInstruction<0>(type),
object_(unique), object_(unique),
object_map_(Handle<Map>::null()),
object_map_is_stable_(false),
has_smi_value_(false), has_smi_value_(false),
has_int32_value_(false), has_int32_value_(false),
has_double_value_(false), has_double_value_(false),
@ -2721,6 +2747,8 @@ HConstant::HConstant(int32_t integer_value,
bool is_not_in_new_space, bool is_not_in_new_space,
Unique<Object> object) Unique<Object> object)
: object_(object), : object_(object),
object_map_(Handle<Map>::null()),
object_map_is_stable_(false),
has_smi_value_(Smi::IsValid(integer_value)), has_smi_value_(Smi::IsValid(integer_value)),
has_int32_value_(true), has_int32_value_(true),
has_double_value_(true), has_double_value_(true),
@ -2745,6 +2773,8 @@ HConstant::HConstant(double double_value,
bool is_not_in_new_space, bool is_not_in_new_space,
Unique<Object> object) Unique<Object> object)
: object_(object), : object_(object),
object_map_(Handle<Map>::null()),
object_map_is_stable_(false),
has_int32_value_(IsInteger32(double_value)), has_int32_value_(IsInteger32(double_value)),
has_double_value_(true), has_double_value_(true),
has_external_reference_value_(false), has_external_reference_value_(false),
@ -2767,6 +2797,8 @@ HConstant::HConstant(double double_value,
HConstant::HConstant(ExternalReference reference) HConstant::HConstant(ExternalReference reference)
: HTemplateInstruction<0>(HType::None()), : HTemplateInstruction<0>(HType::None()),
object_(Unique<Object>(Handle<Object>::null())), object_(Unique<Object>(Handle<Object>::null())),
object_map_(Handle<Map>::null()),
object_map_is_stable_(false),
has_smi_value_(false), has_smi_value_(false),
has_int32_value_(false), has_int32_value_(false),
has_double_value_(false), has_double_value_(false),
@ -3377,29 +3409,6 @@ void HLoadNamedField::PrintDataTo(StringStream* stream) {
} }
HCheckMaps* HCheckMaps::New(Zone* zone,
HValue* context,
HValue* value,
Handle<Map> map,
CompilationInfo* info,
HValue* typecheck) {
HCheckMaps* check_map = new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
Unique<Map>::CreateImmovable(map), zone), typecheck);
// TODO(bmeurer): Get rid of this shit!
if (map->CanOmitMapChecks() &&
value->IsConstant() &&
HConstant::cast(value)->HasMap(map)) {
// TODO(titzer): collect dependent map checks into a list.
check_map->omit_ = true;
if (map->CanTransition()) {
Map::AddDependentCompilationInfo(
map, DependentCode::kPrototypeCheckGroup, info);
}
}
return check_map;
}
void HLoadNamedGeneric::PrintDataTo(StringStream* stream) { void HLoadNamedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream); object()->PrintNameTo(stream);
stream->Add("."); stream->Add(".");
@ -3914,12 +3923,9 @@ void HAllocate::CreateFreeSpaceFiller(int32_t free_space_size) {
HInnerAllocatedObject::New(zone, context(), dominating_allocate_, HInnerAllocatedObject::New(zone, context(), dominating_allocate_,
dominating_allocate_->size(), type()); dominating_allocate_->size(), type());
free_space_instr->InsertBefore(this); free_space_instr->InsertBefore(this);
HConstant* filler_map = HConstant::New( HConstant* filler_map = HConstant::CreateAndInsertAfter(
zone, zone, Unique<Map>::CreateImmovable(
context(), isolate()->factory()->free_space_map()), free_space_instr);
isolate()->factory()->free_space_map());
filler_map->FinalizeUniqueness(); // TODO(titzer): should be init'd a'ready
filler_map->InsertAfter(free_space_instr);
HInstruction* store_map = HStoreNamedField::New(zone, context(), HInstruction* store_map = HStoreNamedField::New(zone, context(),
free_space_instr, HObjectAccess::ForMap(), filler_map); free_space_instr, HObjectAccess::ForMap(), filler_map);
store_map->SetFlag(HValue::kHasNoObservableSideEffects); store_map->SetFlag(HValue::kHasNoObservableSideEffects);

View File

@ -2744,8 +2744,10 @@ class HLoadRoot V8_FINAL : public HTemplateInstruction<0> {
class HCheckMaps V8_FINAL : public HTemplateInstruction<2> { class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
public: public:
static HCheckMaps* New(Zone* zone, HValue* context, HValue* value, static HCheckMaps* New(Zone* zone, HValue* context, HValue* value,
Handle<Map> map, CompilationInfo* info, Handle<Map> map, HValue* typecheck = NULL) {
HValue* typecheck = NULL); return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
Unique<Map>::CreateImmovable(map), zone), typecheck);
}
static HCheckMaps* New(Zone* zone, HValue* context, static HCheckMaps* New(Zone* zone, HValue* context,
HValue* value, SmallMapList* map_list, HValue* value, SmallMapList* map_list,
HValue* typecheck = NULL) { HValue* typecheck = NULL) {
@ -2756,7 +2758,14 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
return new(zone) HCheckMaps(value, maps, typecheck); return new(zone) HCheckMaps(value, maps, typecheck);
} }
bool CanOmitMapChecks() { return omit_; } bool IsStabilityCheck() const { return is_stability_check_; }
void MarkAsStabilityCheck() {
has_migration_target_ = false;
is_stability_check_ = true;
ClearChangesFlag(kNewSpacePromotion);
ClearDependsOnFlag(kElementsKind);
ClearDependsOnFlag(kMaps);
}
virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
@ -2770,9 +2779,11 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
const UniqueSet<Map>* maps() const { return maps_; } const UniqueSet<Map>* maps() const { return maps_; }
void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; } void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
bool has_migration_target() const { bool maps_are_stable() const { return maps_are_stable_; }
return has_migration_target_;
} bool HasMigrationTarget() const { return has_migration_target_; }
virtual HValue* Canonicalize() V8_OVERRIDE;
DECLARE_CONCRETE_INSTRUCTION(CheckMaps) DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
@ -2787,7 +2798,8 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
// Clients should use one of the static New* methods above. // Clients should use one of the static New* methods above.
HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck) HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
: HTemplateInstruction<2>(value->type()), maps_(maps), : HTemplateInstruction<2>(value->type()), maps_(maps),
omit_(false), has_migration_target_(false) { has_migration_target_(false), is_stability_check_(false),
maps_are_stable_(true) {
ASSERT_NE(0, maps->size()); ASSERT_NE(0, maps->size());
SetOperandAt(0, value); SetOperandAt(0, value);
// Use the object value for the dependency if NULL is passed. // Use the object value for the dependency if NULL is passed.
@ -2797,17 +2809,17 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
SetDependsOnFlag(kMaps); SetDependsOnFlag(kMaps);
SetDependsOnFlag(kElementsKind); SetDependsOnFlag(kElementsKind);
for (int i = 0; i < maps->size(); ++i) { for (int i = 0; i < maps->size(); ++i) {
if (maps->at(i).handle()->is_migration_target()) { Handle<Map> map = maps->at(i).handle();
SetChangesFlag(kNewSpacePromotion); if (map->is_migration_target()) has_migration_target_ = true;
has_migration_target_ = true; if (!map->is_stable()) maps_are_stable_ = false;
break;
}
} }
if (has_migration_target_) SetChangesFlag(kNewSpacePromotion);
} }
const UniqueSet<Map>* maps_; const UniqueSet<Map>* maps_;
bool omit_ : 1;
bool has_migration_target_ : 1; bool has_migration_target_ : 1;
bool is_stability_check_ : 1;
bool maps_are_stable_ : 1;
}; };
@ -3459,6 +3471,14 @@ class HConstant V8_FINAL : public HTemplateInstruction<0> {
is_not_in_new_space, false, false, kUnknownInstanceType)); is_not_in_new_space, false, false, kUnknownInstanceType));
} }
static HConstant* CreateAndInsertAfter(Zone* zone,
Unique<Map> unique,
HInstruction* instruction) {
return instruction->Append(new(zone) HConstant(
unique, Representation::Tagged(), HType::Tagged(),
true, false, false, MAP_TYPE));
}
Handle<Object> handle(Isolate* isolate) { Handle<Object> handle(Isolate* isolate) {
if (object_.handle().is_null()) { if (object_.handle().is_null()) {
// Default arguments to is_not_in_new_space depend on this heap number // Default arguments to is_not_in_new_space depend on this heap number
@ -3471,12 +3491,6 @@ class HConstant V8_FINAL : public HTemplateInstruction<0> {
return object_.handle(); return object_.handle();
} }
bool HasMap(Handle<Map> map) {
Handle<Object> constant_object = handle(map->GetIsolate());
return constant_object->IsHeapObject() &&
Handle<HeapObject>::cast(constant_object)->map() == *map;
}
bool IsSpecialDouble() const { bool IsSpecialDouble() const {
return has_double_value_ && return has_double_value_ &&
(BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) || (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
@ -3561,6 +3575,16 @@ class HConstant V8_FINAL : public HTemplateInstruction<0> {
bool IsUndetectable() const { return is_undetectable_; } bool IsUndetectable() const { return is_undetectable_; }
InstanceType GetInstanceType() const { return instance_type_; } InstanceType GetInstanceType() const { return instance_type_; }
bool HasObjectMap() const { return !object_map_.IsNull(); }
Unique<Map> ObjectMap() const {
ASSERT(HasObjectMap());
return object_map_;
}
bool ObjectMapIsStable() const {
ASSERT(HasObjectMap());
return object_map_is_stable_;
}
virtual intptr_t Hashcode() V8_OVERRIDE { virtual intptr_t Hashcode() V8_OVERRIDE {
if (has_int32_value_) { if (has_int32_value_) {
return static_cast<intptr_t>(int32_value_); return static_cast<intptr_t>(int32_value_);
@ -3653,6 +3677,10 @@ class HConstant V8_FINAL : public HTemplateInstruction<0> {
// constant HeapObject. // constant HeapObject.
Unique<Object> object_; Unique<Object> object_;
// If this is a heap object, this points to the Map of the object.
Unique<Map> object_map_;
bool object_map_is_stable_ : 1;
// We store the HConstant in the most specific form safely possible. // We store the HConstant in the most specific form safely possible.
// The two flags, has_int32_value_ and has_double_value_ tell us if // The two flags, has_int32_value_ and has_double_value_ tell us if
// int32_value_ and double_value_ hold valid, safe representations // int32_value_ and double_value_ hold valid, safe representations

View File

@ -1237,11 +1237,6 @@ void HGraphBuilder::FinishExitWithHardDeoptimization(const char* reason) {
} }
HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) {
return Add<HCheckMaps>(obj, map, top_info());
}
HValue* HGraphBuilder::BuildCheckString(HValue* string) { HValue* HGraphBuilder::BuildCheckString(HValue* string) {
if (!string->type().IsString()) { if (!string->type().IsString()) {
ASSERT(!string->IsConstant() || ASSERT(!string->IsConstant() ||
@ -2142,7 +2137,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
if (access_type == STORE && (fast_elements || fast_smi_only_elements) && if (access_type == STORE && (fast_elements || fast_smi_only_elements) &&
store_mode != STORE_NO_TRANSITION_HANDLE_COW) { store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
HCheckMaps* check_cow_map = Add<HCheckMaps>( HCheckMaps* check_cow_map = Add<HCheckMaps>(
elements, isolate()->factory()->fixed_array_map(), top_info()); elements, isolate()->factory()->fixed_array_map());
check_cow_map->ClearDependsOnFlag(kElementsKind); check_cow_map->ClearDependsOnFlag(kElementsKind);
} }
HInstruction* length = NULL; HInstruction* length = NULL;
@ -2216,7 +2211,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
elements_kind, length); elements_kind, length);
} else { } else {
HCheckMaps* check_cow_map = Add<HCheckMaps>( HCheckMaps* check_cow_map = Add<HCheckMaps>(
elements, isolate()->factory()->fixed_array_map(), top_info()); elements, isolate()->factory()->fixed_array_map());
check_cow_map->ClearDependsOnFlag(kElementsKind); check_cow_map->ClearDependsOnFlag(kElementsKind);
} }
} }
@ -2684,7 +2679,7 @@ void HGraphBuilder::BuildCompareNil(
// the monomorphic map when the code is used as a template to generate a // the monomorphic map when the code is used as a template to generate a
// new IC. For optimized functions, there is no sentinel map, the map // new IC. For optimized functions, there is no sentinel map, the map
// emitted below is the actual monomorphic map. // emitted below is the actual monomorphic map.
BuildCheckMap(value, type->Classes().Current()); Add<HCheckMaps>(value, type->Classes().Current());
} else { } else {
if_nil.Deopt("Too many undetectable types"); if_nil.Deopt("Too many undetectable types");
} }
@ -5136,7 +5131,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
} else { } else {
PropertyAccessInfo info(this, STORE, ToType(map), name); PropertyAccessInfo info(this, STORE, ToType(map), name);
if (info.CanAccessMonomorphic()) { if (info.CanAccessMonomorphic()) {
HValue* checked_literal = BuildCheckMap(literal, map); HValue* checked_literal = Add<HCheckMaps>(literal, map);
ASSERT(!info.lookup()->IsPropertyCallbacks()); ASSERT(!info.lookup()->IsPropertyCallbacks());
store = BuildMonomorphicAccess( store = BuildMonomorphicAccess(
&info, literal, checked_literal, value, &info, literal, checked_literal, value,
@ -5263,7 +5258,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
// De-opt if elements kind changed from boilerplate_elements_kind. // De-opt if elements kind changed from boilerplate_elements_kind.
Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate()); Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate());
literal = Add<HCheckMaps>(literal, map, top_info()); literal = Add<HCheckMaps>(literal, map);
} }
// The array is expected in the bailout environment during computation // The array is expected in the bailout environment during computation
@ -5316,7 +5311,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object,
Handle<Map> map) { Handle<Map> map) {
BuildCheckHeapObject(object); BuildCheckHeapObject(object);
return Add<HCheckMaps>(object, map, top_info()); return Add<HCheckMaps>(object, map);
} }
@ -5399,12 +5394,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
if (!info->field_maps()->is_empty()) { if (!info->field_maps()->is_empty()) {
ASSERT(field_access.representation().IsHeapObject()); ASSERT(field_access.representation().IsHeapObject());
BuildCheckHeapObject(value); BuildCheckHeapObject(value);
if (info->field_maps()->length() == 1) { value = Add<HCheckMaps>(value, info->field_maps());
// TODO(bmeurer): Also apply stable maps optimization to the else case!
value = BuildCheckMap(value, info->field_maps()->first());
} else {
value = Add<HCheckMaps>(value, info->field_maps());
}
// TODO(bmeurer): This is a dirty hack to avoid repeating the smi check // TODO(bmeurer): This is a dirty hack to avoid repeating the smi check
// that was already performed by the HCheckHeapObject above in the // that was already performed by the HCheckHeapObject above in the
@ -6358,8 +6348,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
Handle<Map> map, Handle<Map> map,
PropertyAccessType access_type, PropertyAccessType access_type,
KeyedAccessStoreMode store_mode) { KeyedAccessStoreMode store_mode) {
HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(), HCheckMaps* checked_object = Add<HCheckMaps>(object, map, dependency);
dependency);
if (dependency) { if (dependency) {
checked_object->ClearDependsOnFlag(kElementsKind); checked_object->ClearDependsOnFlag(kElementsKind);
} }
@ -6838,19 +6827,9 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
} }
HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant, HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant) {
CompilationInfo* info) { HCheckMaps* check = Add<HCheckMaps>(
HConstant* constant_value = New<HConstant>(constant); Add<HConstant>(constant), handle(constant->map()));
Handle<Map> map(constant->map(), info->isolate());
if (constant->map()->CanOmitMapChecks()) {
Map::AddDependentCompilationInfo(
map, DependentCode::kPrototypeCheckGroup, info);
return constant_value;
}
AddInstruction(constant_value);
HCheckMaps* check = Add<HCheckMaps>(constant_value, map, info);
check->ClearDependsOnFlag(kElementsKind); check->ClearDependsOnFlag(kElementsKind);
return check; return check;
} }
@ -6859,16 +6838,13 @@ HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant,
HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
Handle<JSObject> holder) { Handle<JSObject> holder) {
while (holder.is_null() || !prototype.is_identical_to(holder)) { while (holder.is_null() || !prototype.is_identical_to(holder)) {
BuildConstantMapCheck(prototype, top_info()); BuildConstantMapCheck(prototype);
Object* next_prototype = prototype->GetPrototype(); Object* next_prototype = prototype->GetPrototype();
if (next_prototype->IsNull()) return NULL; if (next_prototype->IsNull()) return NULL;
CHECK(next_prototype->IsJSObject()); CHECK(next_prototype->IsJSObject());
prototype = handle(JSObject::cast(next_prototype)); prototype = handle(JSObject::cast(next_prototype));
} }
return BuildConstantMapCheck(prototype);
HInstruction* checked_object = BuildConstantMapCheck(prototype, top_info());
if (!checked_object->IsLinked()) AddInstruction(checked_object);
return checked_object;
} }

View File

@ -1298,7 +1298,6 @@ class HGraphBuilder {
HBasicBlock* CreateLoopHeaderBlock(); HBasicBlock* CreateLoopHeaderBlock();
HValue* BuildCheckHeapObject(HValue* object); HValue* BuildCheckHeapObject(HValue* object);
HValue* BuildCheckMap(HValue* obj, Handle<Map> map);
HValue* BuildCheckString(HValue* string); HValue* BuildCheckString(HValue* string);
HValue* BuildWrapReceiver(HValue* object, HValue* function); HValue* BuildWrapReceiver(HValue* object, HValue* function);
@ -1781,8 +1780,7 @@ class HGraphBuilder {
HValue* previous_object_size, HValue* previous_object_size,
HValue* payload); HValue* payload);
HInstruction* BuildConstantMapCheck(Handle<JSObject> constant, HInstruction* BuildConstantMapCheck(Handle<JSObject> constant);
CompilationInfo* info);
HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype, HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype,
Handle<JSObject> holder); Handle<JSObject> holder);

View File

@ -5594,14 +5594,20 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
Register object_; Register object_;
}; };
if (instr->hydrogen()->CanOmitMapChecks()) return; if (instr->hydrogen()->IsStabilityCheck()) {
const UniqueSet<Map>* maps = instr->hydrogen()->maps();
for (int i = 0; i < maps->size(); ++i) {
AddStabilityDependency(maps->at(i).handle());
}
return;
}
LOperand* input = instr->value(); LOperand* input = instr->value();
ASSERT(input->IsRegister()); ASSERT(input->IsRegister());
Register reg = ToRegister(input); Register reg = ToRegister(input);
DeferredCheckMaps* deferred = NULL; DeferredCheckMaps* deferred = NULL;
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
deferred = new(zone()) DeferredCheckMaps(this, instr, reg, x87_stack_); deferred = new(zone()) DeferredCheckMaps(this, instr, reg, x87_stack_);
__ bind(deferred->check_maps()); __ bind(deferred->check_maps());
} }
@ -5616,7 +5622,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
Handle<Map> map = maps->at(maps->size() - 1).handle(); Handle<Map> map = maps->at(maps->size() - 1).handle();
__ CompareMap(reg, map); __ CompareMap(reg, map);
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
__ j(not_equal, deferred->entry()); __ j(not_equal, deferred->entry());
} else { } else {
DeoptimizeIf(not_equal, instr->environment()); DeoptimizeIf(not_equal, instr->environment());

View File

@ -2027,15 +2027,12 @@ LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
LOperand* value = NULL; if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
if (!instr->CanOmitMapChecks()) { LOperand* value = UseRegisterAtStart(instr->value());
value = UseRegisterAtStart(instr->value()); LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); if (instr->HasMigrationTarget()) {
} info()->MarkAsDeferredCalling();
LInstruction* result = new(zone()) LCheckMaps(value); result = AssignPointerMap(result);
if (!instr->CanOmitMapChecks()) {
result = AssignEnvironment(result);
if (instr->has_migration_target()) result = AssignPointerMap(result);
} }
return result; return result;
} }

View File

@ -2399,7 +2399,7 @@ class LCheckInstanceType V8_FINAL : public LTemplateInstruction<0, 1, 1> {
class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 0> { class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 0> {
public: public:
explicit LCheckMaps(LOperand* value) { explicit LCheckMaps(LOperand* value = NULL) {
inputs_[0] = value; inputs_[0] = value;
} }

View File

@ -221,4 +221,10 @@ void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) {
chunk_->AddDeprecationDependency(map); chunk_->AddDeprecationDependency(map);
} }
void LCodeGenBase::AddStabilityDependency(Handle<Map> map) {
if (!map->is_stable()) return Abort(kMapBecameUnstable);
chunk_->AddStabilityDependency(map);
}
} } // namespace v8::internal } } // namespace v8::internal

View File

@ -77,6 +77,7 @@ class LCodeGenBase BASE_EMBEDDED {
// Methods for code dependencies. // Methods for code dependencies.
void AddDeprecationDependency(Handle<Map> map); void AddDeprecationDependency(Handle<Map> map);
void AddStabilityDependency(Handle<Map> map);
}; };

View File

@ -234,7 +234,8 @@ LChunk::LChunk(CompilationInfo* info, HGraph* graph)
instructions_(32, graph->zone()), instructions_(32, graph->zone()),
pointer_maps_(8, graph->zone()), pointer_maps_(8, graph->zone()),
inlined_closures_(1, graph->zone()), inlined_closures_(1, graph->zone()),
deprecation_dependencies_(MapLess(), MapAllocator(graph->zone())) { deprecation_dependencies_(MapLess(), MapAllocator(graph->zone())),
stability_dependencies_(MapLess(), MapAllocator(graph->zone())) {
} }
@ -382,6 +383,14 @@ void LChunk::CommitDependencies(Handle<Code> code) const {
Map::AddDependentCode(map, DependentCode::kTransitionGroup, code); Map::AddDependentCode(map, DependentCode::kTransitionGroup, code);
} }
for (MapSet::const_iterator it = stability_dependencies_.begin(),
iend = stability_dependencies_.end(); it != iend; ++it) {
Handle<Map> map = *it;
ASSERT(map->is_stable());
ASSERT(map->CanTransition());
Map::AddDependentCode(map, DependentCode::kPrototypeCheckGroup, code);
}
info_->CommitDependencies(code); info_->CommitDependencies(code);
} }

View File

@ -652,6 +652,13 @@ class LChunk : public ZoneObject {
deprecation_dependencies_.insert(map); deprecation_dependencies_.insert(map);
} }
void AddStabilityDependency(Handle<Map> map) {
ASSERT(map->is_stable());
if (!map->CanTransition()) return;
ASSERT(!info_->IsStub());
stability_dependencies_.insert(map);
}
Zone* zone() const { return info_->zone(); } Zone* zone() const { return info_->zone(); }
Handle<Code> Codegen(); Handle<Code> Codegen();
@ -680,6 +687,7 @@ class LChunk : public ZoneObject {
ZoneList<LPointerMap*> pointer_maps_; ZoneList<LPointerMap*> pointer_maps_;
ZoneList<Handle<JSFunction> > inlined_closures_; ZoneList<Handle<JSFunction> > inlined_closures_;
MapSet deprecation_dependencies_; MapSet deprecation_dependencies_;
MapSet stability_dependencies_;
}; };

View File

@ -5164,7 +5164,14 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
Register object_; Register object_;
}; };
if (instr->hydrogen()->CanOmitMapChecks()) return; if (instr->hydrogen()->IsStabilityCheck()) {
const UniqueSet<Map>* maps = instr->hydrogen()->maps();
for (int i = 0; i < maps->size(); ++i) {
AddStabilityDependency(maps->at(i).handle());
}
return;
}
Register map_reg = scratch0(); Register map_reg = scratch0();
LOperand* input = instr->value(); LOperand* input = instr->value();
ASSERT(input->IsRegister()); ASSERT(input->IsRegister());
@ -5172,7 +5179,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
__ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
DeferredCheckMaps* deferred = NULL; DeferredCheckMaps* deferred = NULL;
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
deferred = new(zone()) DeferredCheckMaps(this, instr, reg); deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
__ bind(deferred->check_maps()); __ bind(deferred->check_maps());
} }
@ -5185,7 +5192,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
} }
Handle<Map> map = maps->at(maps->size() - 1).handle(); Handle<Map> map = maps->at(maps->size() - 1).handle();
// Do the CompareMap() directly within the Branch() and DeoptimizeIf(). // Do the CompareMap() directly within the Branch() and DeoptimizeIf().
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
__ Branch(deferred->entry(), ne, map_reg, Operand(map)); __ Branch(deferred->entry(), ne, map_reg, Operand(map));
} else { } else {
DeoptimizeIf(ne, instr->environment(), map_reg, Operand(map)); DeoptimizeIf(ne, instr->environment(), map_reg, Operand(map));

View File

@ -1926,15 +1926,12 @@ LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
LOperand* value = NULL; if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
if (!instr->CanOmitMapChecks()) { LOperand* value = UseRegisterAtStart(instr->value());
value = UseRegisterAtStart(instr->value()); LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); if (instr->HasMigrationTarget()) {
} info()->MarkAsDeferredCalling();
LInstruction* result = new(zone()) LCheckMaps(value); result = AssignPointerMap(result);
if (!instr->CanOmitMapChecks()) {
result = AssignEnvironment(result);
if (instr->has_migration_target()) result = AssignPointerMap(result);
} }
return result; return result;
} }

View File

@ -2330,7 +2330,7 @@ class LCheckInstanceType V8_FINAL : public LTemplateInstruction<0, 1, 0> {
class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 0> { class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 0> {
public: public:
explicit LCheckMaps(LOperand* value) { explicit LCheckMaps(LOperand* value = NULL) {
inputs_[0] = value; inputs_[0] = value;
} }

View File

@ -1157,6 +1157,7 @@ template <class C> inline bool Is(Object* obj);
V(kLookupVariableInCountOperation, \ V(kLookupVariableInCountOperation, \
"Lookup variable in count operation") \ "Lookup variable in count operation") \
V(kMapBecameDeprecated, "Map became deprecated") \ V(kMapBecameDeprecated, "Map became deprecated") \
V(kMapBecameUnstable, "Map became unstable") \
V(kMapIsNoLongerInEax, "Map is no longer in eax") \ V(kMapIsNoLongerInEax, "Map is no longer in eax") \
V(kModuleDeclaration, "Module declaration") \ V(kModuleDeclaration, "Module declaration") \
V(kModuleLiteral, "Module literal") \ V(kModuleLiteral, "Module literal") \

View File

@ -5013,14 +5013,20 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
Register object_; Register object_;
}; };
if (instr->hydrogen()->CanOmitMapChecks()) return; if (instr->hydrogen()->IsStabilityCheck()) {
const UniqueSet<Map>* maps = instr->hydrogen()->maps();
for (int i = 0; i < maps->size(); ++i) {
AddStabilityDependency(maps->at(i).handle());
}
return;
}
LOperand* input = instr->value(); LOperand* input = instr->value();
ASSERT(input->IsRegister()); ASSERT(input->IsRegister());
Register reg = ToRegister(input); Register reg = ToRegister(input);
DeferredCheckMaps* deferred = NULL; DeferredCheckMaps* deferred = NULL;
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
deferred = new(zone()) DeferredCheckMaps(this, instr, reg); deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
__ bind(deferred->check_maps()); __ bind(deferred->check_maps());
} }
@ -5035,7 +5041,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
Handle<Map> map = maps->at(maps->size() - 1).handle(); Handle<Map> map = maps->at(maps->size() - 1).handle();
__ CompareMap(reg, map); __ CompareMap(reg, map);
if (instr->hydrogen()->has_migration_target()) { if (instr->hydrogen()->HasMigrationTarget()) {
__ j(not_equal, deferred->entry()); __ j(not_equal, deferred->entry());
} else { } else {
DeoptimizeIf(not_equal, instr->environment()); DeoptimizeIf(not_equal, instr->environment());

View File

@ -1935,15 +1935,12 @@ LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
LOperand* value = NULL; if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
if (!instr->CanOmitMapChecks()) { LOperand* value = UseRegisterAtStart(instr->value());
value = UseRegisterAtStart(instr->value()); LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); if (instr->HasMigrationTarget()) {
} info()->MarkAsDeferredCalling();
LInstruction* result = new(zone()) LCheckMaps(value); result = AssignPointerMap(result);
if (!instr->CanOmitMapChecks()) {
result = AssignEnvironment(result);
if (instr->has_migration_target()) result = AssignPointerMap(result);
} }
return result; return result;
} }

View File

@ -2338,7 +2338,7 @@ class LCheckInstanceType V8_FINAL : public LTemplateInstruction<0, 1, 0> {
class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 0> { class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 0> {
public: public:
explicit LCheckMaps(LOperand* value) { explicit LCheckMaps(LOperand* value = NULL) {
inputs_[0] = value; inputs_[0] = value;
} }