Beispiel #1
0
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);
}
Beispiel #2
0
// 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;
}
Beispiel #3
0
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);
    }
}
Beispiel #4
0
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;
    }
}
Beispiel #5
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
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());
}
Beispiel #9
0
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);
    }
}
Beispiel #10
0
	// 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);
	}
Beispiel #11
0
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());
}
Beispiel #12
0
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);
    }
}
Beispiel #13
0
 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;
 }
Beispiel #14
0
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;
}
Beispiel #15
0
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;
}
Beispiel #16
0
/*
 * 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;
}
Beispiel #17
0
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);
    }
}
Beispiel #18
0
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;
}
Beispiel #19
0
/*
 * 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;
}
Beispiel #20
0
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;
}
Beispiel #21
0
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;
}
Beispiel #22
0
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);
    }
}