[JAEGER] Merge from tracemonkey.

This commit is contained in:
David Mandelin 2010-08-23 11:35:14 -07:00
commit e2bcf55aa2
13 changed files with 129 additions and 41 deletions

View File

@ -64,7 +64,7 @@ static void printf_stderr_common(const char* format, ...)
static void printCallSite(const char* file, int line, const char* function)
{
#if WTF_PLATFORM_WIN && !WTF_PLATFORM_WINCE && defined _DEBUG
#if WTF_COMPILER_MSVC && !WTF_PLATFORM_WINCE && defined _DEBUG
_CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
#else
printf_stderr_common("(%s:%d %s)\n", file, line, function);

View File

@ -68,6 +68,8 @@ BEGIN_TEST(testContexts_bug561444)
JS_BeginRequest(cx);
{
jsvalRoot v(cx);
JSAutoCrossCompartmentCall crossCall;
crossCall.enter(cx, d->obj);
if (!JS_EvaluateScript(cx, d->obj, d->code, strlen(d->code), __FILE__, __LINE__, v.addr()))
return;
}

View File

@ -4414,6 +4414,10 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *prin
uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
chars, length, NULL, filename, lineno);
if (script && !js_NewScriptObject(cx, script)) {
js_DestroyScript(cx, script);
script = NULL;
}
LAST_FRAME_CHECKS(cx, script);
return script;
}
@ -4509,11 +4513,15 @@ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
}
}
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
script = Compiler::compileScript(cx, obj, NULL, NULL, tcflags,
NULL, 0, fp, filename, 1);
if (fp != stdin)
fclose(fp);
if (script && !js_NewScriptObject(cx, script)) {
js_DestroyScript(cx, script);
script = NULL;
}
LAST_FRAME_CHECKS(cx, script);
return script;
}
@ -4527,9 +4535,13 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *file
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, principals);
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
NULL, 0, file, filename, 1);
if (script && !js_NewScriptObject(cx, script)) {
js_DestroyScript(cx, script);
script = NULL;
}
LAST_FRAME_CHECKS(cx, script);
return script;
}
@ -4543,34 +4555,29 @@ JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *f
JS_PUBLIC_API(JSObject *)
JS_NewScriptObject(JSContext *cx, JSScript *script)
{
JSObject *obj;
CHECK_REQUEST(cx);
assertSameCompartment(cx, script);
if (!script)
return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
JS_ASSERT(!script->u.object);
{
AutoScriptRooter root(cx, script);
obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
if (obj) {
obj->setPrivate(script);
script->u.object = obj;
#ifdef CHECK_SCRIPT_OWNER
script->owner = NULL;
#endif
}
}
return obj;
/*
* This function should only ever be applied to JSScripts that had
* script objects allocated for them when they were created, as
* described in the comment for JSScript::u.object.
*/
JS_ASSERT(script->u.object);
return script->u.object;
}
JS_PUBLIC_API(JSObject *)
JS_GetScriptObject(JSScript *script)
{
/*
* This function should only ever be applied to JSScripts that had
* script objects allocated for them when they were created, as
* described in the comment for JSScript::u.object.
*/
JS_ASSERT(script->u.object);
return script->u.object;
}
@ -4578,8 +4585,17 @@ JS_PUBLIC_API(void)
JS_DestroyScript(JSContext *cx, JSScript *script)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, script);
js_DestroyScript(cx, script);
/*
* Originally, JSScript lifetimes were managed explicitly, and this function
* was used to free a JSScript. Now, this function does nothing, and the
* garbage collector manages JSScripts; you must root the JSScript's script
* object (obtained via JS_GetScriptObject) to keep it alive.
*
* However, since the script objects have taken over this responsibility, it
* follows that every script passed here must have a script object.
*/
JS_ASSERT(script->u.object);
}
JS_PUBLIC_API(JSFunction *)
@ -4741,6 +4757,8 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, script);
/* This should receive only scripts handed out via the JSAPI. */
JS_ASSERT(script == JSScript::emptyScript() || script->u.object);
ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
LAST_FRAME_CHECKS(cx, ok);
return ok;
@ -4768,7 +4786,7 @@ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
}
ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
LAST_FRAME_CHECKS(cx, ok);
JS_DestroyScript(cx, script);
js_DestroyScript(cx, script);
return ok;
}

View File

@ -384,8 +384,10 @@ JS_REQUIRES_STACK inline
FrameRegsIter::FrameRegsIter(JSContext *cx)
{
curseg = cx->getCurrentSegment();
if (JS_UNLIKELY(!curseg || !curseg->isActive()))
if (JS_UNLIKELY(!curseg || !curseg->isActive())) {
initSlow();
return;
}
JS_ASSERT(cx->fp);
curfp = cx->fp;
cursp = cx->regs->sp;

View File

@ -293,7 +293,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
stackDepth = 0;
valueCount = 0;
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
if (fp->hasFunction() && fp->argv) {
if (fp->hasFunction() && fp->argv && !fp->isEvalFrame()) {
Value v = NullValue();
if (checkAccess &&
!checkAccess(cx, fp->callee(), callerid, JSACC_READ, &v)) {
@ -334,7 +334,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
values = GetStackTraceValueBuffer(priv);
elem = priv->stackElems;
for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->down) {
if (!fp->hasFunction()) {
if (!fp->hasFunction() || fp->isEvalFrame()) {
elem->funName = NULL;
elem->argc = 0;
} else {

View File

@ -874,12 +874,13 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
JSObject *initialVarObj;
if (down) {
/* Propagate arg state for eval and the debugger API. */
JS_ASSERT_IF(down->hasFunction(), down->hasCallObj());
fp->setCallObj(down->maybeCallObj());
fp->setArgsObj(NULL);
fp->setFunction((script->staticLevel > 0) ? down->maybeFunction() : NULL);
fp->setThisValue(down->getThisValue());
fp->flags = flags;
fp->setNumActualArgs(down->numActualArgs());
fp->setNumActualArgs(0);
fp->argv = down->argv;
fp->setAnnotation(down->maybeAnnotation());
fp->setScopeChain(chain);

View File

@ -185,6 +185,7 @@ struct JSStackFrame
JSObject* getArgsObj() const {
JS_ASSERT(hasArgsObj());
JS_ASSERT(!isEvalFrame());
return argsobj;
}
@ -409,6 +410,7 @@ struct JSStackFrame
}
size_t numFormalArgs() const {
JS_ASSERT(!isEvalFrame());
return getFunction()->nargs;
}
@ -455,6 +457,7 @@ struct JSStackFrame
/* Argument count accessors */
size_t numActualArgs() const {
JS_ASSERT(!isEvalFrame());
return argc;
}
@ -528,6 +531,7 @@ struct JSStackFrame
}
bool isDummyFrame() const { return !!(flags & JSFRAME_DUMMY); }
bool isEvalFrame() const { return !!(flags & JSFRAME_EVAL); }
private:
JSObject *computeThisObject(JSContext *cx);

View File

@ -6082,8 +6082,11 @@ JSObject::getCompartment(JSContext *cx)
return cx->runtime->defaultCompartment;
}
// Compile-time Function, Block, and RegExp objects are not parented.
if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass) {
/*
* Script objects and compile-time Function, Block, RegExp objects
* are not parented.
*/
if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass || clasp == &js_ScriptClass) {
// This is a bogus answer, but it'll do for now.
return cx->runtime->defaultCompartment;
}

View File

@ -1322,6 +1322,33 @@ js_TraceScript(JSTracer *trc, JSScript *script)
js_MarkScriptFilename(script->filename);
}
JSBool
js_NewScriptObject(JSContext *cx, JSScript *script)
{
AutoScriptRooter root(cx, script);
JS_ASSERT(!script->u.object);
JS_ASSERT(script != JSScript::emptyScript());
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
if (!obj)
return JS_FALSE;
obj->setPrivate(script);
script->u.object = obj;
/*
* Clear the object's proto, to avoid entraining stuff. Once we no longer use the parent
* for security checks, then we can clear the parent, too.
*/
obj->clearProto();
#ifdef CHECK_SCRIPT_OWNER
script->owner = NULL;
#endif
return JS_TRUE;
}
typedef struct GSNCacheEntry {
JSDHashEntryHdr hdr;
jsbytecode *pc;

View File

@ -227,7 +227,23 @@ struct JSScript {
uint16 staticLevel;/* static level for display maintenance */
JSPrincipals *principals;/* principals for this script */
union {
JSObject *object; /* optional Script-class object wrapper */
/*
* A script object of class js_ScriptClass, to ensure the script is GC'd.
* - All scripts returned by JSAPI functions (JS_CompileScript,
* JS_CompileFile, etc.) have these objects.
* - Function scripts never have script objects; such scripts are owned
* by their function objects.
* - Temporary scripts created by obj_eval, JS_EvaluateScript, and
* similar functions never have these objects; such scripts are
* explicitly destroyed by the code that created them.
* Debugging API functions (JSDebugHooks::newScriptHook;
* JS_GetFunctionScript) may reveal sans-script-object Function and
* temporary scripts to clients, but clients must never call
* JS_NewScriptObject on such scripts: doing so would double-free them,
* once from the explicit call to js_DestroyScript, and once when the
* script object is garbage collected.
*/
JSObject *object;
JSScript *nextToGC; /* next to GC in rt->scriptsToGC list */
} u;
#ifdef CHECK_SCRIPT_OWNER
@ -479,6 +495,9 @@ js_DestroyScript(JSContext *cx, JSScript *script);
extern void
js_TraceScript(JSTracer *trc, JSScript *script);
extern JSBool
js_NewScriptObject(JSContext *cx, JSScript *script);
/*
* To perturb as little code as possible, we introduce a js_GetSrcNote lookup
* cache without adding an explicit cx parameter. Thus js_GetSrcNote becomes

View File

@ -1095,7 +1095,13 @@ Tracker::set(const void* v, LIns* i)
static inline jsuint
argSlots(JSStackFrame* fp)
{
return JS_MAX(fp->numActualArgs(), fp->numFormalArgs());
return fp->isEvalFrame() ? 0 : JS_MAX(fp->numActualArgs(), fp->numFormalArgs());
}
static inline jsuint
numEntryFrameArgs(JSStackFrame* fp)
{
return fp->isEvalFrame() ? 0 : fp->numActualArgs();
}
static inline bool
@ -6104,7 +6110,7 @@ AttemptToExtendTree(JSContext* cx, VMSideExit* anchor, VMSideExit* exitedFrom, j
}
JS_ASSERT(ngslots >= anchor->numGlobalSlots);
bool rv = TraceRecorder::startRecorder(cx, anchor, c, stackSlots, ngslots, typeMap,
exitedFrom, outer, cx->fp->numActualArgs(),
exitedFrom, outer, numEntryFrameArgs(cx->fp),
Record_Branch, hits < maxHits);
#ifdef MOZ_TRACEVIS
if (!rv && tvso)
@ -6153,7 +6159,7 @@ TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCall
JS_ASSERT(r->fragment && !r->fragment->lastIns);
TreeFragment* root = r->fragment->root;
TreeFragment* first = LookupOrAddLoop(tm, cx->regs->pc, root->globalObj,
root->globalShape, cx->fp->numActualArgs());
root->globalShape, numEntryFrameArgs(cx->fp));
/*
* Make sure the shape of the global object still matches (this might flush
@ -6181,7 +6187,7 @@ TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCall
TreeFragment* outerFragment = root;
jsbytecode* outer = (jsbytecode*) outerFragment->ip;
uint32 outerArgc = outerFragment->argc;
JS_ASSERT(cx->fp->numActualArgs() == first->argc);
JS_ASSERT(numEntryFrameArgs(cx->fp) == first->argc);
AbortRecording(cx, "No compatible inner tree");
return RecordingIfTrue(RecordTree(cx, first, outer, outerArgc, globalSlots, Record_Branch));
@ -7205,7 +7211,7 @@ MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, RecordReason reason)
}
jsbytecode* pc = cx->regs->pc;
uint32 argc = cx->fp->numActualArgs();
uint32 argc = numEntryFrameArgs(cx->fp);
TreeFragment* f = LookupOrAddLoop(tm, pc, globalObj, globalShape, argc);
@ -8247,19 +8253,16 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, Value*& vp,
uintN slot = uint16(sprop->shortid);
vp = NULL;
uintN upvar_slot = SPROP_INVALID_SLOT;
JSStackFrame* cfp = (JSStackFrame*) obj->getPrivate();
if (cfp) {
if (sprop->getterOp() == js_GetCallArg) {
JS_ASSERT(slot < cfp->numFormalArgs());
vp = &cfp->argv[slot];
upvar_slot = slot;
nr.v = *vp;
} else if (sprop->getterOp() == js_GetCallVar ||
sprop->getterOp() == js_GetCallVarChecked) {
JS_ASSERT(slot < cfp->getSlotCount());
vp = &cfp->slots()[slot];
upvar_slot = cx->fp->numFormalArgs() + slot;
nr.v = *vp;
} else {
RETURN_STOP("dynamic property of Call object");

View File

@ -671,8 +671,17 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
{
if (!js_XDRScript(xdr, scriptp, true, NULL))
return JS_FALSE;
if (xdr->mode == JSXDR_DECODE)
if (xdr->mode == JSXDR_DECODE) {
js_CallNewScriptHook(xdr->cx, *scriptp, NULL);
if (*scriptp != JSScript::emptyScript() &&
!js_NewScriptObject(xdr->cx, *scriptp)) {
js_DestroyScript(xdr->cx, *scriptp);
*scriptp = NULL;
return JS_FALSE;
}
}
return JS_TRUE;
}

View File

@ -49,7 +49,7 @@ skip script regress-335700.js # bug xxx - reftest hang, BigO
skip-if(!xulRuntime.shell) script regress-336409-1.js # no results reported.
skip-if(!xulRuntime.shell&&xulRuntime.XPCOMABI.match(/x86_64/)) script regress-336409-2.js # fails on 64 bit systems for some reason
skip-if(!xulRuntime.shell) script regress-336410-1.js # slow
skip-if(!xulRuntime.shell&&xulRuntime.XPCOMABI.match(/x86_64/)) script regress-336410-2.js # fails on 64 bit systems for some reason
skip-if(!xulRuntime.shell&&(xulRuntime.XPCOMABI.match(/x86_64/)||xulRuntime.OS=="WINNT")) script regress-336410-2.js # fails in browser on 64 bit systems or Windows.
script regress-338804-01.js
script regress-338804-02.js
script regress-338804-03.js