Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix function prototype cache bug

Close #91
  • Loading branch information...
commit 8362c2d2782bcb4cfe3d663ce5d3b264f1a13a1c 1 parent fd7644a
@Constellation authored
View
61 iv/lv5/railgun/operation.h
@@ -255,39 +255,44 @@ class Operation {
void StoreProp(JSVal base,
Instruction* instr,
OP::Type generic,
- Symbol s, JSVal stored, bool strict, Error* e) {
+ Symbol name, JSVal src, bool strict, Error* e) {
// opcode | (base | src | index) | nop | nop
base.CheckObjectCoercible(CHECK);
if (base.IsPrimitive()) {
- StorePropPrimitive(base, s, stored, strict, e);
- } else {
- // cache patten
- JSObject* obj = base.object();
- if (instr[2].map == obj->map()) {
- // map is cached, so use previous index code
- obj->Direct(instr[3].u32[0]) = stored;
- return;
- } else {
- Slot slot;
- if (obj->GetOwnPropertySlot(ctx_, s, &slot)) {
- // only data property
- if (slot.IsStoreCacheable() && !symbol::IsArrayIndexSymbol(s)) {
- instr[2].map = obj->map();
- instr[3].u32[0] = slot.offset();
- obj->Direct(slot.offset()) = stored;
- } else {
- // dispatch generic path
- obj->Put(ctx_, s, stored, strict, e);
- instr[0] = Instruction::GetOPInstruction(generic);
- }
- return;
- } else {
- instr[2].map = NULL;
- obj->Put(ctx_, s, stored, strict, e);
- return;
- }
+ StorePropPrimitive(base, name, src, strict, e);
+ return;
+ }
+
+ // cache patten
+ JSObject* obj = base.object();
+ if (instr[2].map == obj->map()) {
+ // map is cached, so use previous index code
+ obj->Direct(instr[3].u32[0]) = src;
+ return;
+ }
+
+ Map* previous = obj->map();
+ Slot slot;
+ obj->PutSlot(ctx(), name, src, &slot, strict, CHECK);
+ const Slot::PutResultType put_result_type = slot.put_result_type();
+ const bool unique = previous->IsUnique() || obj->map()->IsUnique();
+
+ // uncacheable pattern
+ if (!slot.IsPutCacheable() || !symbol::IsArrayIndexSymbol(name)) {
+ return;
+ }
+
+ assert(put_result_type != Slot::PUT_NONE);
+
+ // TODO(Constellation) VM only store replace pattern.
+ if (put_result_type == Slot::PUT_REPLACE) {
+ if (previous == obj->map()) {
+ instr[2].map = obj->map();
+ instr[3].u32[0] = slot.offset();
}
}
+
+ return;
}
void StorePropImpl(JSVal base, Symbol s,
View
11 iv/lv5/slot.h
@@ -20,6 +20,7 @@ class Slot : public StoredSlot {
static const uint32_t FLAG_USED = 1;
static const uint32_t FLAG_CACHEABLE = 2;
static const uint32_t FLAG_PUT_CACHEABLE = 4;
+ static const uint32_t FLAG_FORCE_PUT_UNCACHEABLE = 8;
static const uint32_t FLAG_INIT = FLAG_CACHEABLE;
class PutUnCacheable : private core::Noncopyable<PutUnCacheable> {
@@ -90,14 +91,16 @@ class Slot : public StoredSlot {
inline void MakeUnCacheable() {
flags_ &= (~FLAG_CACHEABLE);
+ assert(!IsCacheable());
}
inline void MakePutUnCacheable() {
- flags_ &= (~FLAG_PUT_CACHEABLE);
+ flags_ |= FLAG_FORCE_PUT_UNCACHEABLE;
+ assert(!IsPutCacheable());
}
bool IsPutCacheable() const {
- return flags_ & FLAG_PUT_CACHEABLE;
+ return flags_ & FLAG_PUT_CACHEABLE && !IsPutForceUnCacheable();
}
inline void MakeUsed() {
@@ -131,6 +134,10 @@ class Slot : public StoredSlot {
return flags_ & FLAG_CACHEABLE;
}
+ bool IsPutForceUnCacheable() const {
+ return flags_ & FLAG_FORCE_PUT_UNCACHEABLE;
+ }
+
void set_put_result_type(PutResultType type) {
flags_ &= (~(PUT_MASK << PUT_SHIFT));
flags_ |= (type << PUT_SHIFT);
View
1  test/lv5/suite/spec.list
@@ -50,3 +50,4 @@ spec/global-registers/global-registers-writable.js
spec/function/function-type-error.js
spec/to-string.js
spec/regress/object-indexed-initializer.js
+spec/function-prototype-cache.js
View
22 test/lv5/suite/spec/function-prototype-cache.js
@@ -0,0 +1,22 @@
+describe("Function", function() {
+ it("prototype cache #91", function() {
+ function Dummy() { }
+
+ function inherit(a, b) {
+ Dummy.prototype = b.prototype;
+ a.prototype = new Dummy();
+ a.prototype.constructor = a;
+ }
+
+ function A() { }
+ function B() { }
+ function C() { }
+ function D() { }
+
+ inherit(C, A);
+ inherit(D, B);
+
+ expect(Object.getPrototypeOf(C.prototype)).toBe(A.prototype);
+ expect(Object.getPrototypeOf(D.prototype)).toBe(B.prototype);
+ });
+});
Please sign in to comment.
Something went wrong with that request. Please try again.