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:
parent
5883de41cc
commit
785bdf7c1e
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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") \
|
||||||
|
@ -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());
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user