Beispiel #1
0
JSBool
js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp)
{
    JSErrNum errorNumber;
    JSExnType exn;
    JSBool ok;
    JSObject *errProto, *errObject;
    JSString *messageStr, *filenameStr;
    uintN lineno;
    JSExnPrivate *privateData;
    const JSErrorFormatString *errorString;

    /*
     * Tell our caller to report immediately if cx has no active frames, or if
     * this report is just a warning.
     */
    JS_ASSERT(reportp);
    if (!cx->fp || JSREPORT_IS_WARNING(reportp->flags))
        return JS_FALSE;

    /* Find the exception index associated with this error. */
    errorNumber = (JSErrNum) reportp->errorNumber;
    errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber);
    exn = errorString ? errorString->exnType : JSEXN_NONE;
    JS_ASSERT(exn < JSEXN_LIMIT);

#if defined( DEBUG_mccabe ) && defined ( PRINTNAMES )
    /* Print the error name and the associated exception name to stderr */
    fprintf(stderr, "%s\t%s\n",
            errortoexnname[errorNumber].name,
            errortoexnname[errorNumber].exception);
#endif

    /*
     * Return false (no exception raised) if no exception is associated
     * with the given error number.
     */
    if (exn == JSEXN_NONE)
        return JS_FALSE;

    /*
     * Prevent runaway recursion, just as the Exception native constructor
     * must do, via cx->creatingException.  If an out-of-memory error occurs,
     * no exception object will be created, but we don't assume that OOM is
     * the only kind of error that subroutines of this function called below
     * might raise.
     */
    if (cx->creatingException)
        return JS_FALSE;
    cx->creatingException = JS_TRUE;

    /* Protect the newly-created strings below from nesting GCs. */
    ok = js_EnterLocalRootScope(cx);
    if (!ok)
        goto out;

    /*
     * Try to get an appropriate prototype by looking up the corresponding
     * exception constructor name in the scope chain of the current context's
     * top stack frame, or in the global object if no frame is active.
     */
    ok = js_GetClassPrototype(cx, exceptions[exn].name, &errProto);
    if (!ok)
        goto out;

    errObject = js_NewObject(cx, &ExceptionClass, errProto, NULL);
    if (!errObject) {
        ok = JS_FALSE;
        goto out;
    }

    /*
     * Set the generated Exception object early, so it won't be GC'd by a last
     * ditch attempt to collect garbage, or a GC that otherwise nests or races
     * under any of the following calls.  If one of the following calls fails,
     * it will overwrite this exception object with one of its own (except in
     * case of OOM errors, of course).
     */
    JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject));

    messageStr = JS_NewStringCopyZ(cx, message);
    if (!messageStr) {
        ok = JS_FALSE;
        goto out;
    }

    if (reportp) {
        filenameStr = JS_NewStringCopyZ(cx, reportp->filename);
        if (!filenameStr) {
            ok = JS_FALSE;
            goto out;
        }
        lineno = reportp->lineno;
    } else {
        filenameStr = cx->runtime->emptyString;
        lineno = 0;
    }
    ok = InitExceptionObject(cx, errObject, messageStr, filenameStr, lineno);
    if (!ok)
        goto out;

    /*
     * Construct a new copy of the error report struct, and store it in the
     * exception object's private data.  We can't use the error report struct
     * that was passed in, because it's stack-allocated, and also because it
     * may point to transient data in the JSTokenStream.
     */
    privateData = exn_newPrivate(cx, reportp);
    if (!privateData) {
        ok = JS_FALSE;
        goto out;
    }
    OBJ_SET_SLOT(cx, errObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(privateData));

    /* Flag the error report passed in to indicate an exception was raised. */
    reportp->flags |= JSREPORT_EXCEPTION;

out:
    js_LeaveLocalRootScope(cx);
    cx->creatingException = JS_FALSE;
    return ok;
}
Beispiel #2
0
JSObject *
js_InitExceptionClasses(JSContext *cx, JSObject *obj)
{
    JSObject *obj_proto, *protos[JSEXN_LIMIT];
    int i;

    /*
     * If lazy class initialization occurs for any Error subclass, then all
     * classes are initialized, starting with Error.  To avoid reentry and
     * redundant initialization, we must not pass a null proto parameter to
     * js_NewObject below, when called for the Error superclass.  We need to
     * ensure that Object.prototype is the proto of Error.prototype.
     *
     * See the equivalent code to ensure that parent_proto is non-null when
     * JS_InitClass calls js_NewObject, in jsapi.c.
     */
    if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
                              &obj_proto)) {
        return NULL;
    }

    if (!js_EnterLocalRootScope(cx))
        return NULL;

    /* Initialize the prototypes first. */
    for (i = 0; exceptions[i].name != 0; i++) {
        JSAtom *atom;
        JSFunction *fun;
        JSString *nameString;
        int protoIndex = exceptions[i].protoIndex;

        /* Make the prototype for the current constructor name. */
        protos[i] = js_NewObject(cx, &js_ErrorClass,
                                 (protoIndex != JSEXN_NONE)
                                 ? protos[protoIndex]
                                 : obj_proto,
                                 obj, 0);
        if (!protos[i])
            break;

        /* So exn_finalize knows whether to destroy private data. */
        STOBJ_SET_SLOT(protos[i], JSSLOT_PRIVATE, JSVAL_VOID);

        /* Make a constructor function for the current name. */
        atom = cx->runtime->atomState.classAtoms[exceptions[i].key];
        fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0);
        if (!fun)
            break;

        /* Make this constructor make objects of class Exception. */
        fun->u.n.clasp = &js_ErrorClass;

        /* Make the prototype and constructor links. */
        if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), protos[i],
                                  JSPROP_READONLY | JSPROP_PERMANENT)) {
            break;
        }

        /* proto bootstrap bit from JS_InitClass omitted. */
        nameString = JS_NewStringCopyZ(cx, exceptions[i].name);
        if (!nameString)
            break;

        /* Add the name property to the prototype. */
        if (!JS_DefineProperty(cx, protos[i], js_name_str,
                               STRING_TO_JSVAL(nameString),
                               NULL, NULL,
                               JSPROP_ENUMERATE)) {
            break;
        }

        /* Finally, stash the constructor for later uses. */
        if (!js_SetClassObject(cx, obj, exceptions[i].key, FUN_OBJECT(fun)))
            break;
    }

    js_LeaveLocalRootScope(cx);
    if (exceptions[i].name)
        return NULL;

    /*
     * Add an empty message property.  (To Exception.prototype only,
     * because this property will be the same for all the exception
     * protos.)
     */
    if (!JS_DefineProperty(cx, protos[0], js_message_str,
                           STRING_TO_JSVAL(cx->runtime->emptyString),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return NULL;
    }
    if (!JS_DefineProperty(cx, protos[0], js_fileName_str,
                           STRING_TO_JSVAL(cx->runtime->emptyString),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return NULL;
    }
    if (!JS_DefineProperty(cx, protos[0], js_lineNumber_str,
                           INT_TO_JSVAL(0),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return NULL;
    }

    /*
     * Add methods only to Exception.prototype, because ostensibly all
     * exception types delegate to that.
     */
    if (!JS_DefineFunctions(cx, protos[0], exception_methods))
        return NULL;

    return protos[0];
}
Beispiel #3
0
JSObject *
js_InitExceptionClasses(JSContext *cx, JSObject *obj)
{
    int i;
    JSObject *protos[JSEXN_LIMIT];

    if (!js_EnterLocalRootScope(cx))
        return NULL;

    /* Initialize the prototypes first. */
    for (i = 0; exceptions[i].name != 0; i++) {
        JSAtom *atom;
        JSFunction *fun;
        JSString *nameString;
        int protoIndex = exceptions[i].protoIndex;

        /* Make the prototype for the current constructor name. */
        protos[i] = js_NewObject(cx, &ExceptionClass,
                                 (protoIndex != JSEXN_NONE)
                                 ? protos[protoIndex]
                                 : NULL,
                                 obj);
        if (!protos[i])
            break;

        /* So exn_finalize knows whether to destroy private data. */
        OBJ_SET_SLOT(cx, protos[i], JSSLOT_PRIVATE, JSVAL_VOID);

        atom = js_Atomize(cx, exceptions[i].name, strlen(exceptions[i].name), 0);
        if (!atom)
            break;

        /* Make a constructor function for the current name. */
        fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0);
        if (!fun)
            break;

        /* Make this constructor make objects of class Exception. */
        fun->clasp = &ExceptionClass;

        /* Make the prototype and constructor links. */
        if (!js_SetClassPrototype(cx, fun->object, protos[i],
                                  JSPROP_READONLY | JSPROP_PERMANENT)) {
            break;
        }

        /* proto bootstrap bit from JS_InitClass omitted. */
        nameString = JS_NewStringCopyZ(cx, exceptions[i].name);
        if (!nameString)
            break;

        /* Add the name property to the prototype. */
        if (!JS_DefineProperty(cx, protos[i], js_name_str,
                               STRING_TO_JSVAL(nameString),
                               NULL, NULL,
                               JSPROP_ENUMERATE)) {
            break;
        }
    }

    js_LeaveLocalRootScope(cx);
    if (exceptions[i].name)
        return NULL;

    /*
     * Add an empty message property.  (To Exception.prototype only,
     * because this property will be the same for all the exception
     * protos.)
     */
    if (!JS_DefineProperty(cx, protos[0], js_message_str,
                           STRING_TO_JSVAL(cx->runtime->emptyString),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return NULL;
    }
    if (!JS_DefineProperty(cx, protos[0], js_filename_str,
                           STRING_TO_JSVAL(cx->runtime->emptyString),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return NULL;
    }
    if (!JS_DefineProperty(cx, protos[0], js_lineno_str,
                           INT_TO_JSVAL(0),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return NULL;
    }

    /*
     * Add methods only to Exception.prototype, because ostensibly all
     * exception types delegate to that.
     */
    if (!JS_DefineFunctions(cx, protos[0], exception_methods))
        return NULL;

    return protos[0];
}