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:
verwaest@chromium.org 2013-07-23 09:18:42 +00:00
parent b8d7bee4a3
commit babce318d1
14 changed files with 151 additions and 39 deletions

View File

@ -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);
} }

View File

@ -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,14 +5315,12 @@ 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());
} }
} }
}
void LCodeGen::DoAllocate(LAllocate* instr) { void LCodeGen::DoAllocate(LAllocate* instr) {

View File

@ -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()));

View File

@ -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")

View File

@ -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();

View File

@ -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) ||

View File

@ -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(),

View File

@ -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,13 +6001,11 @@ 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);
} }
} }
}
void LCodeGen::DoAllocate(LAllocate* instr) { void LCodeGen::DoAllocate(LAllocate* instr) {

View File

@ -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);
} }

View File

@ -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();

View File

@ -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);

View File

@ -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,13 +5030,11 @@ 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);
} }
} }
}
void LCodeGen::DoAllocate(LAllocate* instr) { void LCodeGen::DoAllocate(LAllocate* instr) {

View File

@ -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);
} }

View 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());