void js_TraceLocalRoots(JSTracer *trc, JSLocalRootStack *lrs) { uint32 n, m, mark; JSLocalRootChunk *lrc; jsval v; n = lrs->rootCount; if (n == 0) return; mark = lrs->scopeMark; lrc = lrs->topChunk; do { while (--n > mark) { m = n & JSLRS_CHUNK_MASK; v = lrc->roots[m]; JS_ASSERT(JSVAL_IS_GCTHING(v) && v != JSVAL_NULL); JS_SET_TRACING_INDEX(trc, "local_root", n); js_CallValueTracerIfGCThing(trc, v); if (m == 0) lrc = lrc->down; } m = n & JSLRS_CHUNK_MASK; mark = JSVAL_TO_INT(lrc->roots[m]); if (m == 0) lrc = lrc->down; } while (n != 0); JS_ASSERT(!lrc); }
// static XPCVariant* XPCVariant::newVariant(XPCCallContext& ccx, jsval aJSVal) { XPCVariant* variant = new XPCVariant(); if(!variant) return nsnull; NS_ADDREF(variant); variant->mJSVal = aJSVal; if(JSVAL_IS_GCTHING(variant->mJSVal)) { JSRuntime* rt; if(NS_FAILED(ccx.GetRuntime()->GetJSRuntimeService()->GetRuntime(&rt))|| !JS_AddNamedRootRT(rt, &variant->mJSVal, "XPCVariant::mJSVal")) { NS_RELEASE(variant); // Also sets variant to nsnull. } } if(variant && !variant->InitializeData(ccx)) NS_RELEASE(variant); // Also sets variant to nsnull. return variant; }
void jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval) { JSCrossCompartmentCall *call = NULL; JS_ASSERT(jsdval->nref > 0); if(0 == --jsdval->nref) { jsd_RefreshValue(jsdc, jsdval); if(JSVAL_IS_GCTHING(jsdval->val)) { JS_BeginRequest(jsdc->dumbContext); call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob); if(!call) { JS_EndRequest(jsdc->dumbContext); return; } JS_RemoveValueRoot(jsdc->dumbContext, &jsdval->val); JS_LeaveCrossCompartmentCall(call); JS_EndRequest(jsdc->dumbContext); } free(jsdval); } }
void js_MarkLocalRoots(JSContext *cx, JSLocalRootStack *lrs) { unsigned n, m, mark; JSLocalRootChunk *lrc; n = lrs->rootCount; if (n == 0) return; mark = lrs->scopeMark; lrc = lrs->topChunk; while (--n > mark) { #ifdef GC_MARK_DEBUG char name[22]; JS_snprintf(name, sizeof name, "<local root %u>", n); #else const char *name = NULL; #endif m = n & JSLRS_CHUNK_MASK; JS_ASSERT(JSVAL_IS_GCTHING(lrc->roots[m])); JS_MarkGCThing(cx, JSVAL_TO_GCTHING(lrc->roots[m]), name, NULL); if (m == 0) lrc = lrc->down; } }
void js_MarkLocalRoots(JSContext *cx, JSLocalRootStack *lrs) { uint32 n, m, mark; JSLocalRootChunk *lrc; n = lrs->rootCount; if (n == 0) return; mark = lrs->scopeMark; lrc = lrs->topChunk; do { while (--n > mark) { #ifdef GC_MARK_DEBUG char name[22]; JS_snprintf(name, sizeof name, "<local root %u>", n); #endif m = n & JSLRS_CHUNK_MASK; JS_ASSERT(JSVAL_IS_GCTHING(lrc->roots[m])); GC_MARK(cx, JSVAL_TO_GCTHING(lrc->roots[m]), name); if (m == 0) lrc = lrc->down; } m = n & JSLRS_CHUNK_MASK; mark = JSVAL_TO_INT(lrc->roots[m]); if (m == 0) lrc = lrc->down; } while (n != 0); JS_ASSERT(!lrc); }
JS_NEVER_INLINE bool cls_testIsAboutToBeFinalized_bug528645::createAndTestRooted() { jsvalRoot root(cx); /* * Check various types of GC things against JS_IsAboutToBeFinalized. * Make sure to include unit and numeric strings to the set. */ EVAL("var x = 1.1; " "[''+x, 'a', '123456789', 'something'.substring(1), " "{}, [], new Function('return 10;'), <xml/>];", root.addr()); JSObject *array = JSVAL_TO_OBJECT(root.value()); JS_ASSERT(JS_IsArrayObject(cx, array)); JSBool ok = JS_GetArrayLength(cx, array, &checkPointersLength); CHECK(ok); checkPointers = (void **) malloc(sizeof(void *) * checkPointersLength); CHECK(checkPointers); checkPointersStaticStrings = 0; for (jsuint i = 0; i != checkPointersLength; ++i) { jsval v; ok = JS_GetElement(cx, array, i, &v); CHECK(ok); JS_ASSERT(JSVAL_IS_GCTHING(v)); JS_ASSERT(!JSVAL_IS_NULL(v)); checkPointers[i] = JSVAL_TO_GCTHING(v); if (JSString::isStatic(checkPointers[i])) ++checkPointersStaticStrings; } oldGCCallback = JS_SetGCCallback(cx, TestAboutToBeFinalizedCallback); JS_GC(cx); /* * All GC things are rooted via the root holding the array containing them * and TestAboutToBeFinalizedCallback must keep them as is. */ for (jsuint i = 0; i != checkPointersLength; ++i) CHECK(checkPointers[i]); /* * Overwrite the registers and stack with new GC things to avoid false * positives with the finalization test. */ EVAL("[]", root.addr()); array = JSVAL_TO_OBJECT(root.value()); JS_ASSERT(JS_IsArrayObject(cx, array)); jsuint tmp; CHECK(JS_GetArrayLength(cx, array, &tmp)); CHECK(ok); return true; }
JSDValue* jsd_NewValue(JSDContext* jsdc, jsval val) { JSDValue* jsdval; if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue)))) return NULL; if(JSVAL_IS_GCTHING(val)) { JSBool ok = JS_FALSE; JS_BeginRequest(jsdc->dumbContext); ok = JS_AddNamedRoot(jsdc->dumbContext, &jsdval->val, "JSDValue"); JS_EndRequest(jsdc->dumbContext); if(!ok) { free(jsdval); return NULL; } } jsdval->val = val; jsdval->nref = 1; JS_INIT_CLIST(&jsdval->props); return jsdval; }
XPCTraceableVariant::~XPCTraceableVariant() { NS_ASSERTION(JSVAL_IS_GCTHING(mJSVal), "Must be traceable or unlinked"); // If mJSVal is JSVAL_STRING, we don't need to clean anything up; // simply removing the string from the root set is good. if(!JSVAL_IS_STRING(mJSVal)) nsVariant::Cleanup(&mData); if (!JSVAL_IS_NULL(mJSVal)) RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetJSRuntime()); }
XPCVariant::~XPCVariant() { nsVariant::Cleanup(&mData); if(JSVAL_IS_GCTHING(mJSVal)) { JSRuntime* rt; nsIJSRuntimeService* rtsrvc = nsXPConnect::GetJSRuntimeService(); if(rtsrvc && NS_SUCCEEDED(rtsrvc->GetRuntime(&rt))) JS_RemoveRootRT(rt, &mJSVal); } }
// Return the cloned object (or an already-computed object if we've cloned val before) jsval GetOrClone(jsval val) { if (!JSVAL_IS_GCTHING(val) || JSVAL_IS_NULL(val)) return val; std::map<void*, jsval>::iterator it = m_Mapping.find(JSVAL_TO_GCTHING(val)); if (it != m_Mapping.end()) return it->second; m_RooterFrom.Push(val); // root it so our mapping doesn't get invalidated return Clone(val); }
XPCTraceableVariant::~XPCTraceableVariant() { jsval val = GetJSValPreserveColor(); NS_ASSERTION(JSVAL_IS_GCTHING(val), "Must be traceable or unlinked"); // If val is JSVAL_STRING, we don't need to clean anything up; simply // removing the string from the root set is good. if (!JSVAL_IS_STRING(val)) nsVariant::Cleanup(&mData); if (!JSVAL_IS_NULL(val)) RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock()); }
void jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval) { JS_ASSERT(jsdval->nref > 0); if(0 == --jsdval->nref) { jsd_RefreshValue(jsdc, jsdval); if(JSVAL_IS_GCTHING(jsdval->val)) { JS_BeginRequest(jsdc->dumbContext); JS_RemoveRoot(jsdc->dumbContext, &jsdval->val); JS_EndRequest(jsdc->dumbContext); } free(jsdval); } }
JSBool PersistentGCReference::GCCallback(JSContext *cx, JSGCStatus status) { if (status == JSGC_MARK_END) { PersistentGCReference *ref = weakPtrs; while (ref != NULL) { jsval v = ref->native(); ref->isNearDeath = JSVAL_IS_GCTHING(v) == JS_TRUE && JS_IsAboutToBeFinalized(cx, JSVAL_TO_GCTHING(v)) == JS_TRUE; if (ref->isNearDeath && ref->callback) { Persistent<Value> h(reinterpret_cast<Value*>(ref)); ref->callback(h, ref->context); } ref = ref->next; } } // TODO: what do I do here? return JS_FALSE; }
static bool JSOBJECT_CHECK_TYPE(jsval jsObj) { bool isType; isType = JSVAL_IS_BOOLEAN(jsObj); isType = JSVAL_IS_DOUBLE(jsObj); isType = JSVAL_IS_GCTHING(jsObj); isType = JSVAL_IS_INT(jsObj); isType = JSVAL_IS_NULL(jsObj); isType = JSVAL_IS_NUMBER(jsObj); isType = JSVAL_IS_OBJECT(jsObj); isType = JSVAL_IS_PRIMITIVE(jsObj); isType = JSVAL_IS_STRING(jsObj); isType = JSVAL_IS_VOID(jsObj); return true; }
js_atom_marker(JSHashEntry *he, intN i, void *arg) { JSAtom *atom; MarkArgs *args; jsval key; atom = (JSAtom *)he; args = (MarkArgs *)arg; if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) || (args->gcflags & GC_KEEP_ATOMS)) { atom->flags |= ATOM_MARK; key = ATOM_KEY(atom); if (JSVAL_IS_GCTHING(key)) args->mark(JSVAL_TO_GCTHING(key), args->data); } return HT_ENUMERATE_NEXT; }
/* * Create a new JSD value referring to a jsval. Copy string values into the * JSD compartment. Leave all other GCTHINGs in their native compartments * and access them through cross-compartment calls. */ JSDValue* jsd_NewValue(JSDContext* jsdc, jsval val) { JSDValue* jsdval; JSCrossCompartmentCall *call = NULL; if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue)))) return NULL; if(JSVAL_IS_GCTHING(val)) { JSBool ok; JS_BeginRequest(jsdc->dumbContext); call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob); if(!call) { JS_EndRequest(jsdc->dumbContext); free(jsdval); return NULL; } ok = JS_AddNamedValueRoot(jsdc->dumbContext, &jsdval->val, "JSDValue"); if(ok && JSVAL_IS_STRING(val)) { if(!JS_WrapValue(jsdc->dumbContext, &val)) { ok = JS_FALSE; } } JS_LeaveCrossCompartmentCall(call); JS_EndRequest(jsdc->dumbContext); if(!ok) { free(jsdval); return NULL; } } jsdval->val = val; jsdval->nref = 1; JS_INIT_CLIST(&jsdval->props); return jsdval; }
void jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval) { JSCompartment* oldCompartment = NULL; JS_ASSERT(jsdval->nref > 0); if(0 == --jsdval->nref) { jsd_RefreshValue(jsdc, jsdval); if(JSVAL_IS_GCTHING(jsdval->val)) { JS_BeginRequest(jsdc->dumbContext); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, jsdc->glob); JS_RemoveValueRoot(jsdc->dumbContext, &jsdval->val); JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); JS_EndRequest(jsdc->dumbContext); } free(jsdval); } }
js_atom_key_marker(PRHashEntry *he, intN i, void *arg) { JSAtom *atom; jsval key; MarkAtomArgs *args; atom = (JSAtom *)he; if (atom->nrefs == 0) { /* * Unreferenced atom, probably from the scanner atomizing a name, * number, or string that the parser did not save in an atom map * (because it was a syntax error, e.g.). */ return HT_ENUMERATE_REMOVE; } key = ATOM_KEY(atom); if (JSVAL_IS_GCTHING(key)) { args = arg; args->mark(args->runtime, JSVAL_TO_GCTHING(key)); } return HT_ENUMERATE_NEXT; }
/* * Create a new JSD value referring to a jsval. Copy string values into the * JSD compartment. Leave all other GCTHINGs in their native compartments * and access them through cross-compartment calls. */ JSDValue* jsd_NewValue(JSDContext* jsdc, jsval value) { JS::RootedValue val(jsdc->dumbContext, value); JSDValue* jsdval; JSCompartment* oldCompartment = NULL; if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue)))) return NULL; if(JSVAL_IS_GCTHING(val)) { JSBool ok; JS_BeginRequest(jsdc->dumbContext); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, jsdc->glob); ok = JS_AddNamedValueRoot(jsdc->dumbContext, &jsdval->val, "JSDValue"); if(ok && JSVAL_IS_STRING(val)) { if(!JS_WrapValue(jsdc->dumbContext, val.address())) { ok = JS_FALSE; } } JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); JS_EndRequest(jsdc->dumbContext); if(!ok) { free(jsdval); return NULL; } } jsdval->val = val; jsdval->nref = 1; JS_INIT_CLIST(&jsdval->props); return jsdval; }
JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, JSPropertyDesc *pd) { JSPropertyOp getter; JSScope *scope; JSScopeProperty *aprop; jsval lastException; JSBool wasThrowing; pd->id = ID_TO_VALUE(sprop->id); wasThrowing = cx->throwing; if (wasThrowing) { lastException = cx->exception; if (JSVAL_IS_GCTHING(lastException) && !js_AddRoot(cx, &lastException, "lastException")) { return JS_FALSE; } cx->throwing = JS_FALSE; } if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) { if (!cx->throwing) { pd->flags = JSPD_ERROR; pd->value = JSVAL_VOID; } else { pd->flags = JSPD_EXCEPTION; pd->value = cx->exception; } } else { pd->flags = 0; } cx->throwing = wasThrowing; if (wasThrowing) { cx->exception = lastException; if (JSVAL_IS_GCTHING(lastException)) js_RemoveRoot(cx->runtime, &lastException); } getter = sprop->getter; pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0) | ((sprop->attrs & JSPROP_READONLY) ? JSPD_READONLY : 0) | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0) #if JS_HAS_CALL_OBJECT | ((getter == js_GetCallVariable) ? JSPD_VARIABLE : 0) #endif /* JS_HAS_CALL_OBJECT */ | ((getter == js_GetArgument) ? JSPD_ARGUMENT : 0) | ((getter == js_GetLocalVariable) ? JSPD_VARIABLE : 0); #if JS_HAS_CALL_OBJECT /* for Call Object 'real' getter isn't passed in to us */ if (OBJ_GET_CLASS(cx, obj) == &js_CallClass && getter == js_CallClass.getProperty) { /* * Property of a heavyweight function's variable object having the * class-default getter. It's either an argument if permanent, or a * nested function if impermanent. Local variables have a special * getter (js_GetCallVariable, tested above) and setter, and not the * class default. */ pd->flags |= (sprop->attrs & JSPROP_PERMANENT) ? JSPD_ARGUMENT : JSPD_VARIABLE; } #endif /* JS_HAS_CALL_OBJECT */ pd->spare = 0; pd->slot = (pd->flags & (JSPD_ARGUMENT | JSPD_VARIABLE)) ? sprop->shortid : 0; pd->alias = JSVAL_VOID; scope = OBJ_SCOPE(obj); if (SPROP_HAS_VALID_SLOT(sprop, scope)) { for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) { if (aprop != sprop && aprop->slot == sprop->slot) { pd->alias = ID_TO_VALUE(aprop->id); break; } } } return JS_TRUE; }
nsresult IDBRequest::SetDone(AsyncConnectionHelper* aHelper) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!"); NS_ASSERTION(!mResultValRooted, "Already rooted?!"); NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!"); // See if our window is still valid. If not then we're going to pretend that // we never completed. if (NS_FAILED(CheckInnerWindowCorrectness())) { return NS_OK; } mHaveResultOrErrorCode = true; nsresult rv = aHelper->GetResultCode(); // If the request failed then set the error code and return. if (NS_FAILED(rv)) { mErrorCode = NS_ERROR_GET_CODE(rv); return NS_OK; } // Otherwise we need to get the result from the helper. JSContext* cx = static_cast<JSContext*>(mScriptContext->GetNativeContext()); NS_ASSERTION(cx, "Failed to get a context!"); JSObject* global = static_cast<JSObject*>(mScriptContext->GetNativeGlobal()); NS_ASSERTION(global, "Failed to get global object!"); JSAutoRequest ar(cx); JSAutoEnterCompartment ac; if (!ac.enter(cx, global)) { rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } else { RootResultVal(); rv = aHelper->GetSuccessResult(cx, &mResultVal); if (NS_SUCCEEDED(rv)) { // Unroot if we don't really need to be rooted. if (!JSVAL_IS_GCTHING(mResultVal)) { UnrootResultVal(); } } else { NS_WARNING("GetSuccessResult failed!"); } } if (NS_SUCCEEDED(rv)) { mErrorCode = 0; } else { mErrorCode = NS_ERROR_GET_CODE(rv); mResultVal = JSVAL_VOID; } return rv; }
void js_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval) { JSLocalRootStack *lrs; uint32 mark, m, n; JSLocalRootChunk *lrc; /* Defend against buggy native callers. */ lrs = cx->localRootStack; JS_ASSERT(lrs && lrs->rootCount != 0); if (!lrs || lrs->rootCount == 0) return; mark = lrs->scopeMark; JS_ASSERT(mark != JSLRS_NULL_MARK); if (mark == JSLRS_NULL_MARK) return; /* Free any chunks being popped by this leave operation. */ m = mark >> JSLRS_CHUNK_SHIFT; n = (lrs->rootCount - 1) >> JSLRS_CHUNK_SHIFT; while (n > m) { lrc = lrs->topChunk; JS_ASSERT(lrc != &lrs->firstChunk); lrs->topChunk = lrc->down; JS_free(cx, lrc); --n; } /* * Pop the scope, restoring lrs->scopeMark. If rval is a GC-thing, push * it on the caller's scope, or store it in lastInternalResult if we are * leaving the outermost scope. We don't need to allocate a new lrc * because we can overwrite the old mark's slot with rval. */ lrc = lrs->topChunk; m = mark & JSLRS_CHUNK_MASK; lrs->scopeMark = (uint32) JSVAL_TO_INT(lrc->roots[m]); if (JSVAL_IS_GCTHING(rval) && !JSVAL_IS_NULL(rval)) { if (mark == 0) { cx->weakRoots.lastInternalResult = rval; } else { /* * Increment m to avoid the "else if (m == 0)" case below. If * rval is not a GC-thing, that case would take care of freeing * any chunk that contained only the old mark. Since rval *is* * a GC-thing here, we want to reuse that old mark's slot. */ lrc->roots[m++] = rval; ++mark; } } lrs->rootCount = (uint32) mark; /* * Free the stack eagerly, risking malloc churn. The alternative would * require an lrs->entryCount member, maintained by Enter and Leave, and * tested by the GC in addition to the cx->localRootStack non-null test. * * That approach would risk hoarding 264 bytes (net) per context. Right * now it seems better to give fresh (dirty in CPU write-back cache, and * the data is no longer needed) memory back to the malloc heap. */ if (mark == 0) { cx->localRootStack = NULL; JS_free(cx, lrs); } else if (m == 0) { lrs->topChunk = lrc->down; JS_free(cx, lrc); } }