예제 #1
0
JSBool
js_GetClassPrototype(JSContext *cx, JSClass *clasp, JSObject **protop)
{
    JSBool ok;
    JSObject *ctor;
    jsval pval;
    JSProperty *prop;

    *protop = NULL;
    JS_LOCK(cx);
    ok = FindConstructor(cx, clasp, &pval);
    if (!ok || !JSVAL_IS_FUNCTION(pval))
	goto out;
    ctor = JSVAL_TO_OBJECT(pval);
    if (!js_LookupProperty(cx, ctor,
			   (jsval)cx->runtime->atomState.classPrototypeAtom,
			   NULL, &prop)) {
	ok = JS_FALSE;
	goto out;
    }
    if (prop) {
	pval = prop->object->slots[prop->slot];
	if (JSVAL_IS_OBJECT(pval))
	    *protop = JSVAL_TO_OBJECT(pval);
    }
out:
    JS_UNLOCK(cx);
    return ok;
}
예제 #2
0
파일: jsexn.c 프로젝트: artcom/y60
static JSBool
InitExceptionObject(JSContext *cx, JSObject *obj, JSString *message,
                    JSString *filename, uintN lineno)
{
    JSCheckAccessOp checkAccess;
    JSErrorReporter older;
    JSExceptionState *state;
    jschar *stackbuf;
    size_t stacklen, stackmax;
    JSStackFrame *fp;
    jsval callerid, v;
    JSBool ok;
    JSString *argsrc, *stack;
    uintN i, ulineno;
    const char *cp;
    char ulnbuf[11];

    if (!JS_DefineProperty(cx, obj, js_message_str, STRING_TO_JSVAL(message),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return JS_FALSE;
    }

    if (!JS_DefineProperty(cx, obj, js_filename_str,
                           STRING_TO_JSVAL(filename),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return JS_FALSE;
    }

    if (!JS_DefineProperty(cx, obj, js_lineno_str,
                           INT_TO_JSVAL(lineno),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return JS_FALSE;
    }

    /*
     * Set the 'stack' property.
     *
     * First, set aside any error reporter for cx and save its exception state
     * so we can suppress any checkAccess failures.  Such failures should stop
     * the backtrace procedure, not result in a failure of this constructor.
     */
    checkAccess = cx->runtime->checkObjectAccess;
    if (checkAccess) {
        older = JS_SetErrorReporter(cx, NULL);
        state = JS_SaveExceptionState(cx);
    }
#ifdef __GNUC__         /* suppress bogus gcc warnings */
    else {
        older = NULL;
        state = NULL;
    }
#endif
    callerid = ATOM_KEY(cx->runtime->atomState.callerAtom);

    /*
     * Prepare to allocate a jschar buffer at stackbuf, where stacklen indexes
     * the next free jschar slot, and with room for at most stackmax non-null
     * jschars.  If stackbuf is non-null, it always contains an extra slot for
     * the null terminator we'll store at the end, as a backstop.
     *
     * All early returns must goto done after this point, till the after-loop
     * cleanup code has run!
     */
    stackbuf = NULL;
    stacklen = stackmax = 0;
    ok = JS_TRUE;

#define APPEND_CHAR_TO_STACK(c)                                               \
    JS_BEGIN_MACRO                                                            \
        if (stacklen == stackmax) {                                           \
            void *ptr_;                                                       \
            stackmax = stackmax ? 2 * stackmax : 64;                          \
            ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar));   \
            if (!ptr_) {                                                      \
                ok = JS_FALSE;                                                \
                goto done;                                                    \
            }                                                                 \
            stackbuf = ptr_;                                                  \
        }                                                                     \
        stackbuf[stacklen++] = (c);                                           \
    JS_END_MACRO

#define APPEND_STRING_TO_STACK(str)                                           \
    JS_BEGIN_MACRO                                                            \
        JSString *str_ = str;                                                 \
        size_t length_ = JSSTRING_LENGTH(str_);                               \
        if (stacklen + length_ > stackmax) {                                  \
            void *ptr_;                                                       \
            stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_));            \
            ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar));   \
            if (!ptr_) {                                                      \
                ok = JS_FALSE;                                                \
                goto done;                                                    \
            }                                                                 \
            stackbuf = ptr_;                                                  \
        }                                                                     \
        js_strncpy(stackbuf + stacklen, JSSTRING_CHARS(str_), length_);       \
        stacklen += length_;                                                  \
    JS_END_MACRO

    for (fp = cx->fp; fp; fp = fp->down) {
        if (checkAccess) {
            v = (fp->fun && fp->argv) ? fp->argv[-2] : JSVAL_NULL;
            if (!JSVAL_IS_PRIMITIVE(v)) {
                ok = checkAccess(cx, fp->fun->object, callerid, JSACC_READ, &v);
                if (!ok) {
                    ok = JS_TRUE;
                    break;
                }
            }
        }

        if (fp->fun) {
            if (fp->fun->atom)
                APPEND_STRING_TO_STACK(ATOM_TO_STRING(fp->fun->atom));

            APPEND_CHAR_TO_STACK('(');
            for (i = 0; i < fp->argc; i++) {
                /* Avoid toSource bloat and fallibility for object types. */
                v = fp->argv[i];
                if (JSVAL_IS_PRIMITIVE(v)) {
                    argsrc = js_ValueToSource(cx, v);
                } else if (JSVAL_IS_FUNCTION(cx, v)) {
                    /* XXX Avoid function decompilation bloat for now. */
                    argsrc = JS_GetFunctionId(JS_ValueToFunction(cx, v));
                    if (!argsrc)
                        argsrc = js_ValueToSource(cx, v);
                } else {
                    /* XXX Avoid toString on objects, it takes too long and
                           uses too much memory, for too many classes (see
                           Mozilla bug 166743). */
                    char buf[100];
                    JS_snprintf(buf, sizeof buf, "[object %s]",
                                OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v))->name);
                    argsrc = JS_NewStringCopyZ(cx, buf);
                }
                if (!argsrc) {
                    ok = JS_FALSE;
                    goto done;
                }
                if (i > 0)
                    APPEND_CHAR_TO_STACK(',');
                APPEND_STRING_TO_STACK(argsrc);
            }
            APPEND_CHAR_TO_STACK(')');
        }

        APPEND_CHAR_TO_STACK('@');
        if (fp->script && fp->script->filename) {
            for (cp = fp->script->filename; *cp; cp++)
                APPEND_CHAR_TO_STACK(*cp);
        }
        APPEND_CHAR_TO_STACK(':');
        if (fp->script && fp->pc) {
            ulineno = js_PCToLineNumber(fp->script, fp->pc);
            JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", ulineno);
            for (cp = ulnbuf; *cp; cp++)
                APPEND_CHAR_TO_STACK(*cp);
        } else {
            APPEND_CHAR_TO_STACK('0');
        }
        APPEND_CHAR_TO_STACK('\n');
    }

#undef APPEND_CHAR_TO_STACK
#undef APPEND_STRING_TO_STACK

done:
    if (checkAccess) {
        if (ok)
            JS_RestoreExceptionState(cx, state);
        else
            JS_DropExceptionState(cx, state);
        JS_SetErrorReporter(cx, older);
    }
    if (!ok) {
        JS_free(cx, stackbuf);
        return JS_FALSE;
    }

    if (!stackbuf) {
        stack = cx->runtime->emptyString;
    } else {
        /* NB: if stackbuf was allocated, it has room for the terminator. */
        JS_ASSERT(stacklen <= stackmax);
        if (stacklen < stackmax) {
            /*
             * Realloc can fail when shrinking on some FreeBSD versions, so
             * don't use JS_realloc here; simply let the oversized allocation
             * be owned by the string in that rare case.
             */
            void *shrunk = realloc(stackbuf, (stacklen+1) * sizeof(jschar));
            if (shrunk)
                stackbuf = shrunk;
        }
        stackbuf[stacklen] = 0;
        stack = js_NewString(cx, stackbuf, stacklen, 0);
        if (!stack) {
            JS_free(cx, stackbuf);
            return JS_FALSE;
        }
    }
    return JS_DefineProperty(cx, obj, js_stack_str,
                             STRING_TO_JSVAL(stack),
                             NULL, NULL, JSPROP_ENUMERATE);
}
예제 #3
0
JSProperty *
js_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
    JSRuntime *rt;
    JSScope *scope, *protoScope;
    JSProperty *prop, *protoProp;
    PRHashNumber hash;
    JSSymbol *sym, *protoSym;
    JSObject *proto, *assignobj;
    jsval pval, aval, rval;
    jsint slot;
    JSErrorReporter older;
    JSString *str;

    rt = cx->runtime;
    PR_ASSERT(JS_IS_RUNTIME_LOCKED(rt));

#ifdef SCOPE_TABLE_NOTYET
    /* XXX hash recompute */
    /* XXX protoProp->getter, protoProp->setter, protoProp->flags */
    scope = js_MutateScope(cx, obj, id, getter, setter, flags, &prop);
#endif
    scope = js_GetMutableScope(cx, obj);
    if (!scope)
	return NULL;

    /* Handle old bug that treated empty string as zero index. */
    CHECK_FOR_FUNNY_INDEX(id);

    hash = js_HashValue(id);
    sym = scope->ops->lookup(cx, scope, id, hash);
    if (sym) {
	prop = sym_property(sym);
#if JS_HAS_OBJ_WATCHPOINT
	if (!prop) {
	    /*
	     * Deleted property place-holder, could have a watchpoint that
	     * holds the deleted-but-watched property.
	     */
	    prop = js_FindWatchPoint(rt, obj, js_IdToValue(id));
	}
#endif
    } else {
	prop = NULL;
    }

    if (!prop) {
	/* Find a prototype property with the same id. */
	proto = OBJ_GET_PROTO(obj);
	protoProp = NULL;
	while (proto) {
	    protoScope = (JSScope *)proto->map;
	    protoSym = protoScope->ops->lookup(cx, protoScope, id, hash);
	    if (protoSym) {
		protoProp = sym_property(protoSym);
		if (protoProp)
		    break;
	    }
	    proto = OBJ_GET_PROTO(proto);
	}

	/* Make a new property descriptor with the right heritage. */
	if (protoProp) {
	    prop = js_NewProperty(cx, scope, id,
				  protoProp->getter, protoProp->setter,
				  protoProp->flags | JSPROP_ENUMERATE);
	    prop->id = protoProp->id;
	} else {
	    prop = js_NewProperty(cx, scope, id,
				  scope->map.clasp->getProperty,
				  scope->map.clasp->setProperty,
				  JSPROP_ENUMERATE);
	}
	if (!prop)
	    return NULL;

	if (!obj->map->clasp->addProperty(cx, obj, prop->id, vp)) {
	    js_DestroyProperty(cx, prop);
	    return NULL;
	}

	/* Initialize new properties to undefined. */
	obj->slots[prop->slot] = JSVAL_VOID;

	if (sym) {
	    /* Null-valued symbol left behind from a delete operation. */
	    sym->entry.value = js_HoldProperty(cx, prop);
	}
    }

    if (!sym) {
	/* Need a new symbol as well as a new property. */
	sym = scope->ops->add(cx, scope, id, prop);
	if (!sym)
	    return NULL;
#if JS_BUG_AUTO_INDEX_PROPS
	{
	    jsval id2 = INT_TO_JSVAL(prop->slot - JSSLOT_START);
	    if (!scope->ops->add(cx, scope, id2, prop)) {
		scope->ops->remove(cx, scope, id);
		return NULL;
	    }
	    PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id2, prop);
	}
#endif
	PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id, prop);
    }

    /* Get the current property value from its slot. */
    PR_ASSERT(prop->slot < obj->map->freeslot);
    slot = prop->slot;
    pval = obj->slots[slot];

    /* Evil overloaded operator assign() hack. */
    if (JSVAL_IS_OBJECT(pval)) {
	assignobj = JSVAL_TO_OBJECT(pval);
	if (assignobj) {
	    older = JS_SetErrorReporter(cx, NULL);
	    if (js_GetProperty(cx, assignobj, (jsval)rt->atomState.assignAtom,
			       &aval) &&
		JSVAL_IS_FUNCTION(aval) &&
		js_Call(cx, assignobj, aval, 1, vp, &rval)) {
		*vp = rval;
		JS_SetErrorReporter(cx, older);
		prop->flags |= JSPROP_ASSIGNHACK;
		return prop;
	    }
	    JS_SetErrorReporter(cx, older);
	}
    }

    /* Check for readonly *after* the assign() hack. */
    if (prop->flags & JSPROP_READONLY) {
	if (!JSVERSION_IS_ECMA(cx->version)) {
	    str = js_ValueToSource(cx, js_IdToValue(id));
	    if (str) {
		JS_ReportError(cx, "%s is read-only",
			       JS_GetStringBytes(str));
	    }
	}
	return NULL;
    }

    /* Let the setter modify vp before copying from it to obj->slots[slot]. */
    if (!prop->setter(cx, obj, prop->id, vp))
	return NULL;
    GC_POKE(cx, pval);
    obj->slots[slot] = *vp;

    /* Setting a property makes it enumerable. */
    prop->flags |= JSPROP_ENUMERATE;
    return prop;
}