diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index 8de5e339b671..e1da5a8b2b72 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -1022,27 +1022,8 @@ JSScope::reportReadOnlyScope(JSContext *cx) void JSScope::generateOwnShape(JSContext *cx) { -#ifdef JS_TRACER - if (object) { - js_LeaveTraceIfGlobalObject(cx, object); - - /* - * The JIT must have arranged to re-guard after any unpredictable shape - * change, so if we are on trace here, we should already be prepared to - * bail off trace. - */ - JS_ASSERT_IF(JS_ON_TRACE(cx), cx->bailExit); - - /* - * If we are recording, here is where we forget already-guarded shapes. - * Any subsequent property operation upon object on the trace currently - * being recorded will re-guard (and re-memoize). - */ - JSTraceMonitor *tm = &JS_TRACE_MONITOR(cx); - if (TraceRecorder *tr = tm->recorder) - tr->forgetGuardedShapesForObject(object); - } -#endif + if (object) + js_LeaveTraceIfGlobalObject(cx, object); shape = js_GenerateShape(cx, false); setOwnShape(); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 6e39171d488c..d634a72df8e2 100755 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -2181,8 +2181,6 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* _anchor, Fragment* _frag this->newobj_ins = NULL; this->loopLabel = NULL; - guardedShapeTable.ops = NULL; - #ifdef JS_JIT_SPEW debug_only_print0(LC_TMMinimal, "\n"); debug_only_printf(LC_TMMinimal, "Recording starting from %s:%u@%u (FragID=%06u)\n", @@ -2244,7 +2242,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* _anchor, Fragment* _frag fragment->loopLabel = entryLabel; }) - lirbuf->sp = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, sp)), "sp"); + lirbuf->sp = addName(lir->insLoad(LIR_ldp, lirbuf->state, (int)offsetof(InterpState, sp)), "sp"); lirbuf->rp = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, rp)), "rp"); cx_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, cx)), "cx"); eos_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eos)), "eos"); @@ -2291,7 +2289,6 @@ TraceRecorder::~TraceRecorder() /* Purge the tempAlloc used during recording. */ tempAlloc.reset(); traceMonitor->lirbuf->clear(); - forgetGuardedShapes(); } bool @@ -8589,136 +8586,20 @@ TraceRecorder::binary(LOpcode op) return JSRS_STOP; } -struct GuardedShapeEntry : public JSDHashEntryStub -{ - JSObject* obj; -}; - -#ifdef DEBUG -#include - -static FILE* shapefp = NULL; - -static void -DumpShape(JSObject* obj, const char* prefix) -{ - JSScope* scope = OBJ_SCOPE(obj); - - if (!shapefp) { - shapefp = fopen("/tmp/shapes.dump", "w"); - if (!shapefp) - return; - } - - fprintf(shapefp, "\n%s: shape %u flags %x\n", prefix, scope->shape, scope->flags); - for (JSScopeProperty* sprop = scope->lastProp; sprop; sprop = sprop->parent) { - if (JSID_IS_ATOM(sprop->id)) { - fprintf(shapefp, " %s", JS_GetStringBytes(JSVAL_TO_STRING(ID_TO_VALUE(sprop->id)))); - } else { - JS_ASSERT(!JSID_IS_OBJECT(sprop->id)); - fprintf(shapefp, " %d", JSID_TO_INT(sprop->id)); - } - fprintf(shapefp, " %u %p %p %x %x %d\n", - sprop->slot, sprop->getter, sprop->setter, sprop->attrs, sprop->flags, - sprop->shortid); - } - fflush(shapefp); -} - -static JSDHashOperator -DumpShapeEnumerator(JSDHashTable* table, JSDHashEntryHdr* hdr, uint32 number, void* arg) -{ - GuardedShapeEntry* entry = (GuardedShapeEntry*) hdr; - const char* prefix = (const char*) arg; - - DumpShape(entry->obj, prefix); - return JS_DHASH_NEXT; -} - void -TraceRecorder::dumpGuardedShapes(const char* prefix) -{ - if (guardedShapeTable.ops) - JS_DHashTableEnumerate(&guardedShapeTable, DumpShapeEnumerator, (void*) prefix); -} -#endif /* DEBUG */ - -JS_REQUIRES_STACK JSRecordingStatus TraceRecorder::guardShape(LIns* obj_ins, JSObject* obj, uint32 shape, const char* guardName, LIns* map_ins, VMSideExit* exit) { - if (!guardedShapeTable.ops) { - JS_DHashTableInit(&guardedShapeTable, JS_DHashGetStubOps(), NULL, - sizeof(GuardedShapeEntry), JS_DHASH_MIN_SIZE); - } - - // Test (with add if missing) for a remembered guard for (obj_ins, obj). - GuardedShapeEntry* entry = (GuardedShapeEntry*) - JS_DHashTableOperate(&guardedShapeTable, obj_ins, JS_DHASH_ADD); - if (!entry) { - JS_ReportOutOfMemory(cx); - return JSRS_ERROR; - } - - // If already guarded, emit an assertion that the shape matches. - if (entry->key) { - JS_ASSERT(entry->key == obj_ins); - JS_ASSERT(entry->obj == obj); - debug_only_stmt( - lir->insAssert(lir->ins2i(LIR_eq, - lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), - shape)); - ) - return JSRS_CONTINUE; - } - - // Not yet guarded. Remember obj_ins along with obj (for invalidation). - entry->key = obj_ins; - entry->obj = obj; - - debug_only_stmt(DumpShape(obj, "guard");) - debug_only_stmt(fprintf(shapefp, "for obj_ins %p\n", obj_ins);) - - // Finally, emit the shape guard. LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), "shape"); guard(true, addName(lir->ins2i(LIR_eq, shape_ins, shape), guardName), exit); - return JSRS_CONTINUE; -} - -static JSDHashOperator -ForgetGuardedShapesForObject(JSDHashTable* table, JSDHashEntryHdr* hdr, uint32 number, void* arg) -{ - GuardedShapeEntry* entry = (GuardedShapeEntry*) hdr; - if (entry->obj == arg) { - debug_only_stmt(DumpShape(entry->obj, "forget");) - return JS_DHASH_REMOVE; - } - return JS_DHASH_NEXT; -} - -void -TraceRecorder::forgetGuardedShapesForObject(JSObject* obj) -{ - if (guardedShapeTable.ops) - JS_DHashTableEnumerate(&guardedShapeTable, ForgetGuardedShapesForObject, obj); -} - -void -TraceRecorder::forgetGuardedShapes() -{ - if (guardedShapeTable.ops) { - debug_only_stmt(dumpGuardedShapes("forget-all");) - JS_DHashTableFinish(&guardedShapeTable); - guardedShapeTable.ops = NULL; - } } JS_STATIC_ASSERT(offsetof(JSObjectOps, objectMap) == 0); inline LIns* -TraceRecorder::map(LIns* obj_ins) +TraceRecorder::map(LIns *obj_ins) { return addName(lir->insLoad(LIR_ldp, obj_ins, (int) offsetof(JSObject, map)), "map"); } @@ -8898,7 +8779,7 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, // Otherwise guard on key object exact match. if (PCVCAP_TAG(entry->vcap) <= 1) { if (aobj != globalObj) - CHECK_STATUS(guardShape(obj_ins, aobj, entry->kshape, "guard_kshape", map_ins, exit)); + guardShape(obj_ins, aobj, entry->kshape, "guard_kshape", map_ins, exit); if (entry->adding()) { if (aobj == globalObj) @@ -8947,7 +8828,7 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, } else { obj2_ins = INS_CONSTOBJ(obj2); } - CHECK_STATUS(guardShape(obj2_ins, obj2, vshape, "guard_vshape", map(obj2_ins), exit)); + guardShape(obj2_ins, obj2, vshape, "guard_vshape", map(obj2_ins), exit); } pcval = entry->vword; @@ -9236,7 +9117,7 @@ TraceRecorder::guardPrototypeHasNoIndexedProperties(JSObject* obj, LIns* obj_ins return JSRS_STOP; while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit)) - CHECK_STATUS(guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", map(obj_ins), exit)); + guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", map(obj_ins), exit); return JSRS_CONTINUE; } @@ -10711,11 +10592,9 @@ TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop if (obj == globalObj) ABORT_TRACE("can't trace function-valued property set in branded global scope"); - enterDeepBailCall(); LIns* args[] = { v_ins, INS_CONSTSPROP(sprop), obj_ins, cx_ins }; LIns* ok_ins = lir->insCall(&MethodWriteBarrier_ci, args); guard(false, lir->ins_eq0(ok_ins), OOM_EXIT); - leaveDeepBailCall(); } // Find obj2. If entry->adding(), the TAG bits are all 0. @@ -10824,9 +10703,6 @@ TraceRecorder::enterDeepBailCall() // Tell nanojit not to discard or defer stack writes before this call. GuardRecord* guardRec = createGuardRecord(exit); lir->insGuard(LIR_xbarrier, NULL, guardRec); - - // Forget about guarded shapes, since deep bailers can reshape the world. - forgetGuardedShapes(); return exit; } @@ -11980,8 +11856,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, LIns* map_ins = map(obj_ins); LIns* ops_ins; if (map_is_native(obj->map, map_ins, ops_ins)) { - CHECK_STATUS(guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", map_ins, - exit)); + guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", map_ins, exit); } else if (!guardDenseArray(obj, obj_ins, exit)) { ABORT_TRACE("non-native object involved in undefined property access"); } @@ -12060,10 +11935,8 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, * leaked to the calling script. */ if (isMethod && !cx->fp->imacpc) { - enterDeepBailCall(); LIns* args[] = { v_ins, INS_CONSTSPROP(sprop), obj_ins, cx_ins }; v_ins = lir->insCall(&MethodReadBarrier_ci, args); - leaveDeepBailCall(); } if (slotp) { @@ -12808,7 +12681,7 @@ TraceRecorder::record_JSOP_INSTANCEOF() stack(-2, lir->insCall(&HasInstance_ci, args)); LIns* status_ins = lir->insLoad(LIR_ld, lirbuf->state, - offsetof(InterpState, builtinStatus)); + (int) offsetof(InterpState, builtinStatus)); pendingGuardCondition = lir->ins_eq0(status_ins); leaveDeepBailCall(); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index c4c7cdfde9ad..3c1db3535d05 100755 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -47,7 +47,6 @@ #include "jstypes.h" #include "jsbuiltins.h" #include "jscntxt.h" -#include "jsdhash.h" #include "jsinterp.h" #include "jslock.h" #include "jsnum.h" @@ -838,17 +837,9 @@ class TraceRecorder { JS_REQUIRES_STACK JSRecordingStatus unary(nanojit::LOpcode op); JS_REQUIRES_STACK JSRecordingStatus binary(nanojit::LOpcode op); - JS_REQUIRES_STACK JSRecordingStatus guardShape(nanojit::LIns* obj_ins, JSObject* obj, - uint32 shape, const char* name, - nanojit::LIns* map_ins, VMSideExit* exit); - - JSDHashTable guardedShapeTable; - -#ifdef DEBUG - void dumpGuardedShapes(const char* prefix); -#endif - - void forgetGuardedShapes(); + JS_REQUIRES_STACK void guardShape(nanojit::LIns* obj_ins, JSObject* obj, + uint32 shape, const char* guardName, + nanojit::LIns* map_ins, VMSideExit* exit); inline nanojit::LIns* map(nanojit::LIns *obj_ins); JS_REQUIRES_STACK bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins, @@ -1056,7 +1047,7 @@ public: JS_REQUIRES_STACK JSRecordingStatus record_DefLocalFunSetSlot(uint32 slot, JSObject* obj); JS_REQUIRES_STACK JSRecordingStatus record_NativeCallComplete(); - void forgetGuardedShapesForObject(JSObject* obj); + TreeInfo* getTreeInfo() { return treeInfo; } #ifdef DEBUG void tprint(const char *format, int count, nanojit::LIns *insa[]); diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index 9e0fdd371040..fb10292af9d9 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -1067,13 +1067,6 @@ namespace nanojit virtual LInsp insSkip(size_t size) { return out->insSkip(size); } - void insAssert(LIns* expr) { - #if defined DEBUG - LIns* branch = insBranch(LIR_jt, expr, NULL); - ins0(LIR_dbreak); - branch->setTarget(ins0(LIR_label)); - #endif - } // convenience functions diff --git a/js/src/nanojit/LIRopcode.tbl b/js/src/nanojit/LIRopcode.tbl index a2c0f42806bf..177ad5b46904 100644 --- a/js/src/nanojit/LIRopcode.tbl +++ b/js/src/nanojit/LIRopcode.tbl @@ -74,7 +74,7 @@ OPDEF(start, 0, 0, Op0) // start of a fragment OPDEF(regfence, 1, 0, Op0) // register fence, no register allocation is allowed across this meta instruction OPDEF(skip, 2, 1, Sk) // holds blobs ("payloads") of data; also links pages -OPDEF(dbreak, 3, 0, Op0) +OPDEF(unused3, 3,-1, None) OPDEF(unused4, 4,-1, None) OPDEF(unused5, 5,-1, None) OPDEF(unused6, 6,-1, None)