Commit 7f331f62 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Make HCheckPrototypeMaps compatible with parallel recompilation.

HCheckPrototypeMaps currently records the prototype and the holder of the
prototype chain (both ends of the chain) and assumes that the chain elements
and their maps did not change in during the entirety of Crankshaft. The actual
traversal of the prototype chain happens in Lithium at code generation.
With parallel compilation, this assumption is not longer correct.

R=mstarzinger@chromium.org
BUG=

Review URL: https://chromiumcodereview.appspot.com/11864013

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13454 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c3d45451
...@@ -2166,8 +2166,10 @@ class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 2> { ...@@ -2166,8 +2166,10 @@ class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 2> {
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps)
Handle<JSObject> prototype() const { return hydrogen()->prototype(); } ZoneList<Handle<JSObject> >* prototypes() const {
Handle<JSObject> holder() const { return hydrogen()->holder(); } return hydrogen()->prototypes();
}
ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); }
}; };
......
...@@ -5318,29 +5318,19 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { ...@@ -5318,29 +5318,19 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
Register prototype_reg = ToRegister(instr->temp()); Register prototype_reg = ToRegister(instr->temp());
Register map_reg = ToRegister(instr->temp2()); Register map_reg = ToRegister(instr->temp2());
Handle<JSObject> holder = instr->holder(); ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
Handle<JSObject> current_prototype = instr->prototype(); ZoneList<Handle<Map> >* maps = instr->maps();
// Load prototype object. ASSERT(prototypes->length() == maps->length());
__ LoadHeapObject(prototype_reg, current_prototype);
// Check prototype maps up to the holder. for (int i = 0; i < prototypes->length(); i++) {
while (!current_prototype.is_identical_to(holder)) { __ 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, DoCheckMapCommon(map_reg,
Handle<Map>(current_prototype->map()), maps->at(i),
ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment()); ALLOW_ELEMENT_TRANSITION_MAPS,
current_prototype = instr->environment());
Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype())); }
// Load next prototype object.
__ LoadHeapObject(prototype_reg, current_prototype);
}
// Check the holder map.
__ ldr(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
DoCheckMapCommon(map_reg,
Handle<Map>(current_prototype->map()),
ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
} }
......
...@@ -1205,7 +1205,8 @@ void HCheckInstanceType::PrintDataTo(StringStream* stream) { ...@@ -1205,7 +1205,8 @@ void HCheckInstanceType::PrintDataTo(StringStream* stream) {
void HCheckPrototypeMaps::PrintDataTo(StringStream* stream) { void HCheckPrototypeMaps::PrintDataTo(StringStream* stream) {
stream->Add("[receiver_prototype=%p,holder=%p]", *prototype(), *holder()); stream->Add("[receiver_prototype=%p,holder=%p]",
*prototypes_.first(), *prototypes_.last());
} }
......
...@@ -2446,14 +2446,24 @@ class HCheckNonSmi: public HUnaryOperation { ...@@ -2446,14 +2446,24 @@ class HCheckNonSmi: public HUnaryOperation {
class HCheckPrototypeMaps: public HTemplateInstruction<0> { class HCheckPrototypeMaps: public HTemplateInstruction<0> {
public: public:
HCheckPrototypeMaps(Handle<JSObject> prototype, Handle<JSObject> holder) HCheckPrototypeMaps(Handle<JSObject> prototype,
: prototype_(prototype), holder_(holder) { Handle<JSObject> holder,
Zone* zone) : prototypes_(2, zone), maps_(2, zone) {
SetFlag(kUseGVN); SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps); SetGVNFlag(kDependsOnMaps);
// Keep a list of all objects on the prototype chain up to the holder
// and the expected maps.
while (true) {
prototypes_.Add(prototype, zone);
maps_.Add(Handle<Map>(prototype->map()), zone);
if (prototype.is_identical_to(holder)) break;
prototype = Handle<JSObject>(JSObject::cast(prototype->GetPrototype()));
}
} }
Handle<JSObject> prototype() const { return prototype_; } ZoneList<Handle<JSObject> >* prototypes() { return &prototypes_; }
Handle<JSObject> holder() const { return holder_; }
ZoneList<Handle<Map> >* maps() { return &maps_; }
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps) DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps)
...@@ -2465,21 +2475,33 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { ...@@ -2465,21 +2475,33 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
virtual intptr_t Hashcode() { virtual intptr_t Hashcode() {
ASSERT_ALLOCATION_DISABLED; ASSERT_ALLOCATION_DISABLED;
intptr_t hash = reinterpret_cast<intptr_t>(*prototype()); intptr_t hash = 0;
hash = 17 * hash + reinterpret_cast<intptr_t>(*holder()); for (int i = 0; i < prototypes_.length(); i++) {
hash = 17 * hash + reinterpret_cast<intptr_t>(*prototypes_[i]);
hash = 17 * hash + reinterpret_cast<intptr_t>(*maps_[i]);
}
return hash; return hash;
} }
protected: protected:
virtual bool DataEquals(HValue* other) { virtual bool DataEquals(HValue* other) {
HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other); HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other);
return prototype_.is_identical_to(b->prototype()) && #ifdef DEBUG
holder_.is_identical_to(b->holder()); if (prototypes_.length() != b->prototypes()->length()) return false;
for (int i = 0; i < prototypes_.length(); i++) {
if (!prototypes_[i].is_identical_to(b->prototypes()->at(i))) return false;
if (!maps_[i].is_identical_to(b->maps()->at(i))) return false;
}
return true;
#else
return prototypes_.first().is_identical_to(b->prototypes()->first()) &&
prototypes_.last().is_identical_to(b->prototypes()->last());
#endif // DEBUG
} }
private: private:
Handle<JSObject> prototype_; ZoneList<Handle<JSObject> > prototypes_;
Handle<JSObject> holder_; ZoneList<Handle<Map> > maps_;
}; };
...@@ -3614,9 +3636,9 @@ class HSub: public HArithmeticBinaryOperation { ...@@ -3614,9 +3636,9 @@ class HSub: public HArithmeticBinaryOperation {
virtual HValue* Canonicalize(); virtual HValue* Canonicalize();
static HInstruction* NewHSub(Zone* zone, static HInstruction* NewHSub(Zone* zone,
HValue* context, HValue* context,
HValue* left, HValue* left,
HValue* right); HValue* right);
DECLARE_CONCRETE_INSTRUCTION(Sub) DECLARE_CONCRETE_INSTRUCTION(Sub)
......
...@@ -5561,7 +5561,8 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( ...@@ -5561,7 +5561,8 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
ASSERT(proto->IsJSObject()); ASSERT(proto->IsJSObject());
AddInstruction(new(zone()) HCheckPrototypeMaps( AddInstruction(new(zone()) HCheckPrototypeMaps(
Handle<JSObject>(JSObject::cast(map->prototype())), Handle<JSObject>(JSObject::cast(map->prototype())),
Handle<JSObject>(JSObject::cast(proto)))); Handle<JSObject>(JSObject::cast(proto)),
zone()));
} }
int index = ComputeLoadStoreFieldIndex(map, name, lookup); int index = ComputeLoadStoreFieldIndex(map, name, lookup);
...@@ -6296,8 +6297,8 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( ...@@ -6296,8 +6297,8 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
Handle<JSObject> holder(lookup.holder()); Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map()); Handle<Map> holder_map(holder->map());
AddCheckMapsWithTransitions(object, map); AddCheckMapsWithTransitions(object, map);
HInstruction* holder_value = HInstruction* holder_value = AddInstruction(
AddInstruction(new(zone()) HCheckPrototypeMaps(prototype, holder)); new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
return BuildLoadNamedField(holder_value, holder_map, &lookup); return BuildLoadNamedField(holder_value, holder_map, &lookup);
} }
...@@ -6836,8 +6837,9 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { ...@@ -6836,8 +6837,9 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
Handle<Map> receiver_map) { Handle<Map> receiver_map) {
if (!holder.is_null()) { if (!holder.is_null()) {
AddInstruction(new(zone()) HCheckPrototypeMaps( Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
Handle<JSObject>(JSObject::cast(receiver_map->prototype())), holder)); AddInstruction(
new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
} }
} }
...@@ -7469,7 +7471,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( ...@@ -7469,7 +7471,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
ASSERT(!expr->holder().is_null()); ASSERT(!expr->holder().is_null());
AddInstruction(new(zone()) HCheckPrototypeMaps( AddInstruction(new(zone()) HCheckPrototypeMaps(
oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
expr->holder())); expr->holder(),
zone()));
HStringCharCodeAt* char_code = HStringCharCodeAt* char_code =
BuildStringCharCodeAt(context, string, index); BuildStringCharCodeAt(context, string, index);
if (id == kStringCharCodeAt) { if (id == kStringCharCodeAt) {
......
...@@ -5169,26 +5169,15 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { ...@@ -5169,26 +5169,15 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
ASSERT(instr->temp()->Equals(instr->result())); ASSERT(instr->temp()->Equals(instr->result()));
Register reg = ToRegister(instr->temp()); Register reg = ToRegister(instr->temp());
Handle<JSObject> holder = instr->holder(); ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
Handle<JSObject> current_prototype = instr->prototype(); ZoneList<Handle<Map> >* maps = instr->maps();
// Load prototype object. ASSERT(prototypes->length() == maps->length());
__ LoadHeapObject(reg, current_prototype);
// Check prototype maps up to the holder. for (int i = 0; i < prototypes->length(); i++) {
while (!current_prototype.is_identical_to(holder)) { __ LoadHeapObject(reg, prototypes->at(i));
DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()), DoCheckMapCommon(reg, maps->at(i), ALLOW_ELEMENT_TRANSITION_MAPS, instr);
ALLOW_ELEMENT_TRANSITION_MAPS, instr);
current_prototype =
Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
// Load next prototype object.
__ LoadHeapObject(reg, current_prototype);
} }
// Check the holder map.
DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
ALLOW_ELEMENT_TRANSITION_MAPS, instr);
} }
......
...@@ -2231,8 +2231,10 @@ class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> { ...@@ -2231,8 +2231,10 @@ class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> {
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps)
Handle<JSObject> prototype() const { return hydrogen()->prototype(); } ZoneList<Handle<JSObject> >* prototypes() const {
Handle<JSObject> holder() const { return hydrogen()->holder(); } return hydrogen()->prototypes();
}
ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); }
}; };
......
...@@ -4778,25 +4778,15 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { ...@@ -4778,25 +4778,15 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
ASSERT(instr->temp()->Equals(instr->result())); ASSERT(instr->temp()->Equals(instr->result()));
Register reg = ToRegister(instr->temp()); Register reg = ToRegister(instr->temp());
Handle<JSObject> holder = instr->holder(); ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
Handle<JSObject> current_prototype = instr->prototype(); ZoneList<Handle<Map> >* maps = instr->maps();
// Load prototype object. ASSERT(prototypes->length() == maps->length());
__ LoadHeapObject(reg, current_prototype);
// Check prototype maps up to the holder. for (int i = 0; i < prototypes->length(); i++) {
while (!current_prototype.is_identical_to(holder)) { __ LoadHeapObject(reg, prototypes->at(i));
DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()), DoCheckMapCommon(reg, maps->at(i), ALLOW_ELEMENT_TRANSITION_MAPS, instr);
ALLOW_ELEMENT_TRANSITION_MAPS, instr);
current_prototype =
Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
// Load next prototype object.
__ LoadHeapObject(reg, current_prototype);
} }
// Check the holder map.
DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
ALLOW_ELEMENT_TRANSITION_MAPS, instr);
} }
......
...@@ -2102,8 +2102,10 @@ class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> { ...@@ -2102,8 +2102,10 @@ class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> {
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps)
Handle<JSObject> prototype() const { return hydrogen()->prototype(); } ZoneList<Handle<JSObject> >* prototypes() const {
Handle<JSObject> holder() const { return hydrogen()->holder(); } return hydrogen()->prototypes();
}
ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); }
}; };
......
// 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
// Flags: --parallel-recompilation --manual-parallel-recompilation
function f(foo) { return foo.bar(); }
var o = {};
o.__proto__ = { __proto__: { bar: function() { return 1; } } };
assertEquals(1, f(o));
assertEquals(1, f(o));
%ForceParallelRecompile(f);
// Change the prototype chain during optimization.
o.__proto__.__proto__ = { bar: function() { return 2; } };
%InstallRecompiledCode(f);
assertEquals(2, f(o));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment