Eliminate map checks of constant values.
R=ulan@chromium.org Review URL: https://chromiumcodereview.appspot.com/19954005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15819 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
b8d7bee4a3
commit
babce318d1
@ -2035,9 +2035,14 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
||||||
LUnallocated* temp1 = TempRegister();
|
LUnallocated* temp1 = NULL;
|
||||||
LOperand* temp2 = TempRegister();
|
LOperand* temp2 = NULL;
|
||||||
|
if (!instr->CanOmitPrototypeChecks()) {
|
||||||
|
temp1 = TempRegister();
|
||||||
|
temp2 = TempRegister();
|
||||||
|
}
|
||||||
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2);
|
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2);
|
||||||
|
if (instr->CanOmitPrototypeChecks()) return result;
|
||||||
return AssignEnvironment(result);
|
return AssignEnvironment(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2049,8 +2054,10 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
|
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
|
||||||
LOperand* value = UseRegisterAtStart(instr->value());
|
LOperand* value = NULL;
|
||||||
|
if (!instr->CanOmitMapChecks()) value = UseRegisterAtStart(instr->value());
|
||||||
LInstruction* result = new(zone()) LCheckMaps(value);
|
LInstruction* result = new(zone()) LCheckMaps(value);
|
||||||
|
if (instr->CanOmitMapChecks()) return result;
|
||||||
return AssignEnvironment(result);
|
return AssignEnvironment(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5232,6 +5232,7 @@ void LCodeGen::DoCheckMapCommon(Register map_reg,
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
|
void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
|
||||||
|
if (instr->hydrogen()->CanOmitMapChecks()) return;
|
||||||
Register map_reg = scratch0();
|
Register map_reg = scratch0();
|
||||||
LOperand* input = instr->value();
|
LOperand* input = instr->value();
|
||||||
ASSERT(input->IsRegister());
|
ASSERT(input->IsRegister());
|
||||||
@ -5304,6 +5305,8 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
||||||
|
if (instr->hydrogen()->CanOmitPrototypeChecks()) return;
|
||||||
|
|
||||||
Register prototype_reg = ToRegister(instr->temp());
|
Register prototype_reg = ToRegister(instr->temp());
|
||||||
Register map_reg = ToRegister(instr->temp2());
|
Register map_reg = ToRegister(instr->temp2());
|
||||||
|
|
||||||
@ -5312,12 +5315,10 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
|||||||
|
|
||||||
ASSERT(prototypes->length() == maps->length());
|
ASSERT(prototypes->length() == maps->length());
|
||||||
|
|
||||||
if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
|
for (int i = 0; i < prototypes->length(); i++) {
|
||||||
for (int i = 0; i < prototypes->length(); i++) {
|
__ LoadHeapObject(prototype_reg, prototypes->at(i));
|
||||||
__ LoadHeapObject(prototype_reg, prototypes->at(i));
|
__ ldr(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
|
||||||
__ ldr(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
|
DoCheckMapCommon(map_reg, maps->at(i), instr->environment());
|
||||||
DoCheckMapCommon(map_reg, maps->at(i), instr->environment());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,7 +884,8 @@ HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
|
|||||||
// Check that the map of the global has not changed: use a placeholder map
|
// Check that the map of the global has not changed: use a placeholder map
|
||||||
// that will be replaced later with the global object's map.
|
// that will be replaced later with the global object's map.
|
||||||
Handle<Map> placeholder_map = isolate()->factory()->meta_map();
|
Handle<Map> placeholder_map = isolate()->factory()->meta_map();
|
||||||
AddInstruction(HCheckMaps::New(receiver, placeholder_map, zone()));
|
AddInstruction(HCheckMaps::New(
|
||||||
|
receiver, placeholder_map, zone(), top_info()));
|
||||||
|
|
||||||
HValue* cell = Add<HConstant>(placeholder_cell, Representation::Tagged());
|
HValue* cell = Add<HConstant>(placeholder_cell, Representation::Tagged());
|
||||||
HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
|
HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
|
||||||
|
@ -307,6 +307,9 @@ DEFINE_int(parallel_recompilation_delay, 0,
|
|||||||
DEFINE_bool(omit_prototype_checks_for_leaf_maps, true,
|
DEFINE_bool(omit_prototype_checks_for_leaf_maps, true,
|
||||||
"do not emit prototype checks if all prototypes have leaf maps, "
|
"do not emit prototype checks if all prototypes have leaf maps, "
|
||||||
"deoptimize the optimized code if the layout of the maps changes.")
|
"deoptimize the optimized code if the layout of the maps changes.")
|
||||||
|
DEFINE_bool(omit_map_checks_for_leaf_maps, true,
|
||||||
|
"do not emit check maps for constant values that have a leaf map, "
|
||||||
|
"deoptimize the optimized code if the layout of the maps changes.")
|
||||||
|
|
||||||
// Experimental profiler changes.
|
// Experimental profiler changes.
|
||||||
DEFINE_bool(experimental_profiler, true, "enable all profiler experiments")
|
DEFINE_bool(experimental_profiler, true, "enable all profiler experiments")
|
||||||
|
@ -1680,7 +1680,7 @@ void HCheckMaps::PrintDataTo(StringStream* stream) {
|
|||||||
for (int i = 1; i < map_set()->length(); ++i) {
|
for (int i = 1; i < map_set()->length(); ++i) {
|
||||||
stream->Add(",%p", *map_set()->at(i));
|
stream->Add(",%p", *map_set()->at(i));
|
||||||
}
|
}
|
||||||
stream->Add("]");
|
stream->Add("]%s", CanOmitMapChecks() ? "(omitted)" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2775,6 +2775,22 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HCheckMaps* HCheckMaps::New(HValue* value,
|
||||||
|
Handle<Map> map,
|
||||||
|
Zone* zone,
|
||||||
|
CompilationInfo* info,
|
||||||
|
HValue* typecheck) {
|
||||||
|
HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
|
||||||
|
check_map->map_set_.Add(map, zone);
|
||||||
|
if (map->CanOmitMapChecks() &&
|
||||||
|
value->IsConstant() &&
|
||||||
|
HConstant::cast(value)->InstanceOf(map)) {
|
||||||
|
check_map->omit(info);
|
||||||
|
}
|
||||||
|
return check_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HCheckMaps::FinalizeUniqueValueId() {
|
void HCheckMaps::FinalizeUniqueValueId() {
|
||||||
if (!map_unique_ids_.is_empty()) return;
|
if (!map_unique_ids_.is_empty()) return;
|
||||||
Zone* zone = block()->zone();
|
Zone* zone = block()->zone();
|
||||||
|
@ -2738,12 +2738,7 @@ class HLoadExternalArrayPointer: public HUnaryOperation {
|
|||||||
class HCheckMaps: public HTemplateInstruction<2> {
|
class HCheckMaps: public HTemplateInstruction<2> {
|
||||||
public:
|
public:
|
||||||
static HCheckMaps* New(HValue* value, Handle<Map> map, Zone* zone,
|
static HCheckMaps* New(HValue* value, Handle<Map> map, Zone* zone,
|
||||||
HValue *typecheck = NULL) {
|
CompilationInfo* info, HValue *typecheck = NULL);
|
||||||
HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
|
|
||||||
check_map->map_set_.Add(map, zone);
|
|
||||||
return check_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HCheckMaps* New(HValue* value, SmallMapList* maps, Zone* zone,
|
static HCheckMaps* New(HValue* value, SmallMapList* maps, Zone* zone,
|
||||||
HValue *typecheck = NULL) {
|
HValue *typecheck = NULL) {
|
||||||
HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
|
HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
|
||||||
@ -2777,6 +2772,8 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
|||||||
return check_map;
|
return check_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CanOmitMapChecks() { return omit_; }
|
||||||
|
|
||||||
virtual bool HasEscapingOperandAt(int index) { return false; }
|
virtual bool HasEscapingOperandAt(int index) { return false; }
|
||||||
virtual Representation RequiredInputRepresentation(int index) {
|
virtual Representation RequiredInputRepresentation(int index) {
|
||||||
return Representation::Tagged();
|
return Representation::Tagged();
|
||||||
@ -2812,7 +2809,7 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
|||||||
private:
|
private:
|
||||||
// Clients should use one of the static New* methods above.
|
// Clients should use one of the static New* methods above.
|
||||||
HCheckMaps(HValue* value, Zone *zone, HValue* typecheck)
|
HCheckMaps(HValue* value, Zone *zone, HValue* typecheck)
|
||||||
: map_unique_ids_(0, zone) {
|
: omit_(false), map_unique_ids_(0, zone) {
|
||||||
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.
|
||||||
// TODO(titzer): do GVN flags already express this dependency?
|
// TODO(titzer): do GVN flags already express this dependency?
|
||||||
@ -2824,6 +2821,16 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
|||||||
SetGVNFlag(kDependsOnElementsKind);
|
SetGVNFlag(kDependsOnElementsKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void omit(CompilationInfo* info) {
|
||||||
|
omit_ = true;
|
||||||
|
for (int i = 0; i < map_set_.length(); i++) {
|
||||||
|
Handle<Map> map = map_set_.at(i);
|
||||||
|
map->AddDependentCompilationInfo(DependentCode::kPrototypeCheckGroup,
|
||||||
|
info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool omit_;
|
||||||
SmallMapList map_set_;
|
SmallMapList map_set_;
|
||||||
ZoneList<UniqueValueId> map_unique_ids_;
|
ZoneList<UniqueValueId> map_unique_ids_;
|
||||||
};
|
};
|
||||||
@ -3302,6 +3309,11 @@ class HConstant: public HTemplateInstruction<0> {
|
|||||||
return handle_;
|
return handle_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InstanceOf(Handle<Map> map) {
|
||||||
|
return handle_->IsJSObject() &&
|
||||||
|
Handle<JSObject>::cast(handle_)->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) ||
|
||||||
|
@ -1045,7 +1045,7 @@ HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
|
|||||||
|
|
||||||
HValue* HGraphBuilder::BuildCheckMap(HValue* obj,
|
HValue* HGraphBuilder::BuildCheckMap(HValue* obj,
|
||||||
Handle<Map> map) {
|
Handle<Map> map) {
|
||||||
HCheckMaps* check = HCheckMaps::New(obj, map, zone());
|
HCheckMaps* check = HCheckMaps::New(obj, map, zone(), top_info());
|
||||||
AddInstruction(check);
|
AddInstruction(check);
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
@ -1208,7 +1208,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
|
|||||||
if (is_store && (fast_elements || fast_smi_only_elements) &&
|
if (is_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 = HCheckMaps::New(
|
HCheckMaps* check_cow_map = HCheckMaps::New(
|
||||||
elements, isolate()->factory()->fixed_array_map(), zone);
|
elements, isolate()->factory()->fixed_array_map(), zone, top_info());
|
||||||
check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
|
check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
|
||||||
AddInstruction(check_cow_map);
|
AddInstruction(check_cow_map);
|
||||||
}
|
}
|
||||||
@ -1276,7 +1276,8 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
|
|||||||
length);
|
length);
|
||||||
} else {
|
} else {
|
||||||
HCheckMaps* check_cow_map = HCheckMaps::New(
|
HCheckMaps* check_cow_map = HCheckMaps::New(
|
||||||
elements, isolate()->factory()->fixed_array_map(), zone);
|
elements, isolate()->factory()->fixed_array_map(),
|
||||||
|
zone, top_info());
|
||||||
check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
|
check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
|
||||||
AddInstruction(check_cow_map);
|
AddInstruction(check_cow_map);
|
||||||
}
|
}
|
||||||
@ -4450,7 +4451,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>(original_boilerplate_object->map(),
|
Handle<Map> map = Handle<Map>(original_boilerplate_object->map(),
|
||||||
isolate());
|
isolate());
|
||||||
AddInstruction(HCheckMaps::New(literal, map, zone()));
|
AddInstruction(HCheckMaps::New(literal, map, zone(), top_info()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The array is expected in the bailout environment during computation
|
// The array is expected in the bailout environment during computation
|
||||||
@ -4541,7 +4542,7 @@ static Representation ComputeLoadStoreRepresentation(Handle<Map> type,
|
|||||||
|
|
||||||
void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) {
|
void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) {
|
||||||
BuildCheckHeapObject(object);
|
BuildCheckHeapObject(object);
|
||||||
AddInstruction(HCheckMaps::New(object, map, zone()));
|
AddInstruction(HCheckMaps::New(object, map, zone(), top_info()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -5506,7 +5507,8 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
|
|||||||
Handle<Map> map,
|
Handle<Map> map,
|
||||||
bool is_store,
|
bool is_store,
|
||||||
KeyedAccessStoreMode store_mode) {
|
KeyedAccessStoreMode store_mode) {
|
||||||
HCheckMaps* mapcheck = HCheckMaps::New(object, map, zone(), dependency);
|
HCheckMaps* mapcheck = HCheckMaps::New(
|
||||||
|
object, map, zone(), top_info(), dependency);
|
||||||
AddInstruction(mapcheck);
|
AddInstruction(mapcheck);
|
||||||
if (dependency) {
|
if (dependency) {
|
||||||
mapcheck->ClearGVNFlag(kDependsOnElementsKind);
|
mapcheck->ClearGVNFlag(kDependsOnElementsKind);
|
||||||
@ -5690,7 +5692,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
|||||||
if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
|
if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
|
||||||
AddInstruction(HCheckMaps::New(
|
AddInstruction(HCheckMaps::New(
|
||||||
elements, isolate()->factory()->fixed_array_map(),
|
elements, isolate()->factory()->fixed_array_map(),
|
||||||
zone(), mapcompare));
|
zone(), top_info(), mapcompare));
|
||||||
}
|
}
|
||||||
if (map->IsJSArray()) {
|
if (map->IsJSArray()) {
|
||||||
HInstruction* length = AddLoad(object, HObjectAccess::ForArrayLength(),
|
HInstruction* length = AddLoad(object, HObjectAccess::ForArrayLength(),
|
||||||
|
@ -5802,6 +5802,7 @@ void LCodeGen::DoCheckMapCommon(Register reg,
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
|
void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
|
||||||
|
if (instr->hydrogen()->CanOmitMapChecks()) return;
|
||||||
LOperand* input = instr->value();
|
LOperand* input = instr->value();
|
||||||
ASSERT(input->IsRegister());
|
ASSERT(input->IsRegister());
|
||||||
Register reg = ToRegister(input);
|
Register reg = ToRegister(input);
|
||||||
@ -5992,6 +5993,7 @@ void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
||||||
|
if (instr->hydrogen()->CanOmitPrototypeChecks()) return;
|
||||||
Register reg = ToRegister(instr->temp());
|
Register reg = ToRegister(instr->temp());
|
||||||
|
|
||||||
ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
|
ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
|
||||||
@ -5999,11 +6001,9 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
|||||||
|
|
||||||
ASSERT(prototypes->length() == maps->length());
|
ASSERT(prototypes->length() == maps->length());
|
||||||
|
|
||||||
if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
|
for (int i = 0; i < prototypes->length(); i++) {
|
||||||
for (int i = 0; i < prototypes->length(); i++) {
|
__ LoadHeapObject(reg, prototypes->at(i));
|
||||||
__ LoadHeapObject(reg, prototypes->at(i));
|
DoCheckMapCommon(reg, maps->at(i), instr);
|
||||||
DoCheckMapCommon(reg, maps->at(i), instr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2063,8 +2063,10 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
||||||
LUnallocated* temp = TempRegister();
|
LUnallocated* temp = NULL;
|
||||||
|
if (!instr->CanOmitPrototypeChecks()) temp = TempRegister();
|
||||||
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
|
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
|
||||||
|
if (instr->CanOmitPrototypeChecks()) return result;
|
||||||
return AssignEnvironment(result);
|
return AssignEnvironment(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2081,8 +2083,10 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
|
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
|
||||||
LOperand* value = UseRegisterAtStart(instr->value());
|
LOperand* value = NULL;
|
||||||
|
if (!instr->CanOmitMapChecks()) value = UseRegisterAtStart(instr->value());
|
||||||
LCheckMaps* result = new(zone()) LCheckMaps(value);
|
LCheckMaps* result = new(zone()) LCheckMaps(value);
|
||||||
|
if (instr->CanOmitMapChecks()) return result;
|
||||||
return AssignEnvironment(result);
|
return AssignEnvironment(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3669,6 +3669,12 @@ bool Map::CanOmitPrototypeChecks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Map::CanOmitMapChecks() {
|
||||||
|
return !HasTransitionArray() && !is_dictionary_map() &&
|
||||||
|
FLAG_omit_map_checks_for_leaf_maps;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int DependentCode::number_of_entries(DependencyGroup group) {
|
int DependentCode::number_of_entries(DependencyGroup group) {
|
||||||
if (length() == 0) return 0;
|
if (length() == 0) return 0;
|
||||||
return Smi::cast(get(group))->value();
|
return Smi::cast(get(group))->value();
|
||||||
|
@ -5626,6 +5626,7 @@ class Map: public HeapObject {
|
|||||||
inline void NotifyLeafMapLayoutChange();
|
inline void NotifyLeafMapLayoutChange();
|
||||||
|
|
||||||
inline bool CanOmitPrototypeChecks();
|
inline bool CanOmitPrototypeChecks();
|
||||||
|
inline bool CanOmitMapChecks();
|
||||||
|
|
||||||
void AddDependentCompilationInfo(DependentCode::DependencyGroup group,
|
void AddDependentCompilationInfo(DependentCode::DependencyGroup group,
|
||||||
CompilationInfo* info);
|
CompilationInfo* info);
|
||||||
|
@ -4954,6 +4954,7 @@ void LCodeGen::DoCheckMapCommon(Register reg,
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
|
void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
|
||||||
|
if (instr->hydrogen()->CanOmitMapChecks()) return;
|
||||||
LOperand* input = instr->value();
|
LOperand* input = instr->value();
|
||||||
ASSERT(input->IsRegister());
|
ASSERT(input->IsRegister());
|
||||||
Register reg = ToRegister(input);
|
Register reg = ToRegister(input);
|
||||||
@ -5021,6 +5022,7 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
||||||
|
if (instr->hydrogen()->CanOmitPrototypeChecks()) return;
|
||||||
Register reg = ToRegister(instr->temp());
|
Register reg = ToRegister(instr->temp());
|
||||||
|
|
||||||
ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
|
ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
|
||||||
@ -5028,11 +5030,9 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
|||||||
|
|
||||||
ASSERT(prototypes->length() == maps->length());
|
ASSERT(prototypes->length() == maps->length());
|
||||||
|
|
||||||
if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
|
for (int i = 0; i < prototypes->length(); i++) {
|
||||||
for (int i = 0; i < prototypes->length(); i++) {
|
__ LoadHeapObject(reg, prototypes->at(i));
|
||||||
__ LoadHeapObject(reg, prototypes->at(i));
|
DoCheckMapCommon(reg, maps->at(i), instr);
|
||||||
DoCheckMapCommon(reg, maps->at(i), instr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1949,8 +1949,10 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
||||||
LUnallocated* temp = TempRegister();
|
LUnallocated* temp = NULL;
|
||||||
|
if (!instr->CanOmitPrototypeChecks()) temp = TempRegister();
|
||||||
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
|
LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
|
||||||
|
if (instr->CanOmitPrototypeChecks()) return result;
|
||||||
return AssignEnvironment(result);
|
return AssignEnvironment(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1962,8 +1964,10 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
|
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
|
||||||
LOperand* value = UseRegisterAtStart(instr->value());
|
LOperand* value = NULL;
|
||||||
|
if (!instr->CanOmitMapChecks()) value = UseRegisterAtStart(instr->value());
|
||||||
LCheckMaps* result = new(zone()) LCheckMaps(value);
|
LCheckMaps* result = new(zone()) LCheckMaps(value);
|
||||||
|
if (instr->CanOmitMapChecks()) return result;
|
||||||
return AssignEnvironment(result);
|
return AssignEnvironment(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
55
test/mjsunit/omit-constant-mapcheck.js
Normal file
55
test/mjsunit/omit-constant-mapcheck.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// 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:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax
|
||||||
|
|
||||||
|
var g1 = { a:1 }
|
||||||
|
|
||||||
|
function load() {
|
||||||
|
return g1.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(1, load());
|
||||||
|
assertEquals(1, load());
|
||||||
|
%OptimizeFunctionOnNextCall(load);
|
||||||
|
assertEquals(1, load());
|
||||||
|
delete g1.a;
|
||||||
|
assertEquals(undefined, load());
|
||||||
|
|
||||||
|
var g2 = { a:2 }
|
||||||
|
|
||||||
|
function load2() {
|
||||||
|
return g2.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(2, load2());
|
||||||
|
assertEquals(2, load2());
|
||||||
|
%OptimizeFunctionOnNextCall(load2);
|
||||||
|
assertEquals(2, load2());
|
||||||
|
g2.b = 10;
|
||||||
|
g2.a = 5;
|
||||||
|
assertEquals(5, load2());
|
Loading…
Reference in New Issue
Block a user