diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index be36c624120..6eb14fa82c3 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -5432,7 +5432,7 @@ js_GetWrappedObject(JSContext *cx, JSObject *obj) return obj; } -#if DEBUG +#ifdef DEBUG /* * Routines to print out values during debugging. These are FRIEND_API to help @@ -5602,8 +5602,12 @@ js_DumpObject(JSObject *obj) sharesScope = (scope->object != obj); if (sharesScope) { - fprintf(stderr, "no own properties - see proto (%s at %p)\n", - STOBJ_GET_CLASS(proto)->name, proto); + if (proto) { + fprintf(stderr, "no own properties - see proto (%s at %p)\n", + STOBJ_GET_CLASS(proto)->name, proto); + } else { + fprintf(stderr, "no own properties - null proto\n"); + } } else { fprintf(stderr, "properties:\n"); for (JSScopeProperty *sprop = SCOPE_LAST_PROP(scope); sprop; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 4231c1d28e8..2940dc7e1e1 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -3189,6 +3189,16 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, Fragment* outer) return true; } +static inline bool isSlotUndemotable(JSContext* cx, TreeInfo* ti, unsigned slot) +{ + if (slot < ti->stackSlots) + return oracle.isStackSlotUndemotable(cx, slot); + + JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); + uint16* gslots = tm->globalSlots->data(); + return oracle.isGlobalSlotUndemotable(cx, gslots[slot - ti->stackSlots]); +} + JS_REQUIRES_STACK static bool js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, Fragment* outer) { @@ -3212,8 +3222,11 @@ js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, Fragment* outer) /* If this exit does not have enough globals, there might exist a peer with more globals that we * can join to. */ - TreeInfo* ti; + uint8* m2; Fragment* f; + TreeInfo* ti; + bool matched; + bool undemote; bool bound = false; unsigned int checkSlots; for (f = from->first; f != NULL; f = f->peer) { @@ -3223,7 +3236,33 @@ js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, Fragment* outer) JS_ASSERT(exit->numStackSlots == ti->stackSlots); /* Check the minimum number of slots that need to be compared. */ checkSlots = JS_MIN(exit->numStackSlots + exit->numGlobalSlots, ti->typeMap.length()); - if (memcmp(getFullTypeMap(exit), ti->typeMap.data(), checkSlots) == 0) { + m = getFullTypeMap(exit); + m2 = ti->typeMap.data(); + /* Analyze the exit typemap against the peer typemap. + * Two conditions are important: + * 1) Typemaps are identical: these peers can be attached. + * 2) Typemaps do not match, but only contain I->D mismatches. + * In this case, the original tree must be trashed because it + * will never connect to any peer. + */ + matched = true; + undemote = false; + for (uint32 i = 0; i < checkSlots; i++) { + /* If the types are equal we're okay. */ + if (m[i] == m2[i]) + continue; + matched = false; + /* If there's an I->D that cannot be resolved, flag it. + * Otherwise, break and go to the next peer. + */ + if (m[i] == JSVAL_INT && m2[i] == JSVAL_DOUBLE && isSlotUndemotable(cx, ti, i)) { + undemote = true; + } else { + undemote = false; + break; + } + } + if (matched) { /* Capture missing globals on both trees and link the fragments together. */ if (from != f) { ti->dependentTrees.addUnique(from); @@ -3247,6 +3286,11 @@ js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, Fragment* outer) JS_ASSERT(bound); debug_only_v(js_DumpPeerStability(tm->fragmento, f->ip);) break; + } else if (undemote) { + /* The original tree is unconnectable, so trash it. */ + js_TrashTree(cx, f); + /* We shouldn't attempt to record now, since we'll hit a duplicate. */ + return false; } } if (bound)