DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps)
- Handle<JSObject> prototype() const { return hydrogen()->prototype(); }
- Handle<JSObject> holder() const { return hydrogen()->holder(); }
+ ZoneList<Handle<JSObject> >* prototypes() const {
+ return hydrogen()->prototypes();
+ }
+ ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); }
};
Register prototype_reg = ToRegister(instr->temp());
Register map_reg = ToRegister(instr->temp2());
- Handle<JSObject> holder = instr->holder();
- Handle<JSObject> current_prototype = instr->prototype();
+ ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
+ ZoneList<Handle<Map> >* maps = instr->maps();
- // Load prototype object.
- __ LoadHeapObject(prototype_reg, current_prototype);
+ ASSERT(prototypes->length() == maps->length());
- // Check prototype maps up to the holder.
- while (!current_prototype.is_identical_to(holder)) {
+ for (int i = 0; i < prototypes->length(); i++) {
+ __ LoadHeapObject(prototype_reg, prototypes->at(i));
__ ldr(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
DoCheckMapCommon(map_reg,
- Handle<Map>(current_prototype->map()),
- ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
- current_prototype =
- 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());
+ maps->at(i),
+ ALLOW_ELEMENT_TRANSITION_MAPS,
+ instr->environment());
+ }
}
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());
}
class HCheckPrototypeMaps: public HTemplateInstruction<0> {
public:
- HCheckPrototypeMaps(Handle<JSObject> prototype, Handle<JSObject> holder)
- : prototype_(prototype), holder_(holder) {
+ HCheckPrototypeMaps(Handle<JSObject> prototype,
+ Handle<JSObject> holder,
+ Zone* zone) : prototypes_(2, zone), maps_(2, zone) {
SetFlag(kUseGVN);
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_; }
- Handle<JSObject> holder() const { return holder_; }
+ ZoneList<Handle<JSObject> >* prototypes() { return &prototypes_; }
+
+ ZoneList<Handle<Map> >* maps() { return &maps_; }
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps)
virtual intptr_t Hashcode() {
ASSERT_ALLOCATION_DISABLED;
- intptr_t hash = reinterpret_cast<intptr_t>(*prototype());
- hash = 17 * hash + reinterpret_cast<intptr_t>(*holder());
+ intptr_t hash = 0;
+ 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;
}
protected:
virtual bool DataEquals(HValue* other) {
HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other);
- return prototype_.is_identical_to(b->prototype()) &&
- holder_.is_identical_to(b->holder());
+#ifdef DEBUG
+ 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:
- Handle<JSObject> prototype_;
- Handle<JSObject> holder_;
+ ZoneList<Handle<JSObject> > prototypes_;
+ ZoneList<Handle<Map> > maps_;
};
virtual HValue* Canonicalize();
static HInstruction* NewHSub(Zone* zone,
- HValue* context,
- HValue* left,
- HValue* right);
+ HValue* context,
+ HValue* left,
+ HValue* right);
DECLARE_CONCRETE_INSTRUCTION(Sub)
ASSERT(proto->IsJSObject());
AddInstruction(new(zone()) HCheckPrototypeMaps(
Handle<JSObject>(JSObject::cast(map->prototype())),
- Handle<JSObject>(JSObject::cast(proto))));
+ Handle<JSObject>(JSObject::cast(proto)),
+ zone()));
}
int index = ComputeLoadStoreFieldIndex(map, name, lookup);
Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map());
AddCheckMapsWithTransitions(object, map);
- HInstruction* holder_value =
- AddInstruction(new(zone()) HCheckPrototypeMaps(prototype, holder));
+ HInstruction* holder_value = AddInstruction(
+ new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
return BuildLoadNamedField(holder_value, holder_map, &lookup);
}
void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
Handle<Map> receiver_map) {
if (!holder.is_null()) {
- AddInstruction(new(zone()) HCheckPrototypeMaps(
- Handle<JSObject>(JSObject::cast(receiver_map->prototype())), holder));
+ Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
+ AddInstruction(
+ new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
}
}
ASSERT(!expr->holder().is_null());
AddInstruction(new(zone()) HCheckPrototypeMaps(
oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
- expr->holder()));
+ expr->holder(),
+ zone()));
HStringCharCodeAt* char_code =
BuildStringCharCodeAt(context, string, index);
if (id == kStringCharCodeAt) {
ASSERT(instr->temp()->Equals(instr->result()));
Register reg = ToRegister(instr->temp());
- Handle<JSObject> holder = instr->holder();
- Handle<JSObject> current_prototype = instr->prototype();
+ ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
+ ZoneList<Handle<Map> >* maps = instr->maps();
- // Load prototype object.
- __ LoadHeapObject(reg, current_prototype);
+ ASSERT(prototypes->length() == maps->length());
- // Check prototype maps up to the holder.
- while (!current_prototype.is_identical_to(holder)) {
- DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
- ALLOW_ELEMENT_TRANSITION_MAPS, instr);
-
- current_prototype =
- Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
- // Load next prototype object.
- __ LoadHeapObject(reg, current_prototype);
+ for (int i = 0; i < prototypes->length(); i++) {
+ __ LoadHeapObject(reg, prototypes->at(i));
+ DoCheckMapCommon(reg, maps->at(i), ALLOW_ELEMENT_TRANSITION_MAPS, instr);
}
-
- // Check the holder map.
- DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
- ALLOW_ELEMENT_TRANSITION_MAPS, instr);
}
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps)
- Handle<JSObject> prototype() const { return hydrogen()->prototype(); }
- Handle<JSObject> holder() const { return hydrogen()->holder(); }
+ ZoneList<Handle<JSObject> >* prototypes() const {
+ return hydrogen()->prototypes();
+ }
+ ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); }
};
ASSERT(instr->temp()->Equals(instr->result()));
Register reg = ToRegister(instr->temp());
- Handle<JSObject> holder = instr->holder();
- Handle<JSObject> current_prototype = instr->prototype();
+ ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
+ ZoneList<Handle<Map> >* maps = instr->maps();
- // Load prototype object.
- __ LoadHeapObject(reg, current_prototype);
+ ASSERT(prototypes->length() == maps->length());
- // Check prototype maps up to the holder.
- while (!current_prototype.is_identical_to(holder)) {
- DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
- ALLOW_ELEMENT_TRANSITION_MAPS, instr);
- current_prototype =
- Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
- // Load next prototype object.
- __ LoadHeapObject(reg, current_prototype);
+ for (int i = 0; i < prototypes->length(); i++) {
+ __ LoadHeapObject(reg, prototypes->at(i));
+ DoCheckMapCommon(reg, maps->at(i), ALLOW_ELEMENT_TRANSITION_MAPS, instr);
}
-
- // Check the holder map.
- DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
- ALLOW_ELEMENT_TRANSITION_MAPS, instr);
}
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps)
- Handle<JSObject> prototype() const { return hydrogen()->prototype(); }
- Handle<JSObject> holder() const { return hydrogen()->holder(); }
+ ZoneList<Handle<JSObject> >* prototypes() const {
+ return hydrogen()->prototypes();
+ }
+ ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); }
};
--- /dev/null
+// 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));