author | Jeff Walden <jwalden@mit.edu> |
Thu, 21 Oct 2010 14:31:29 -0700 | |
changeset 56775 | 6abb9e45a79a26fd39418bd68f2cb31991aa4d47 |
parent 56774 | 5c77882891f7f2c00a201a8ae9fd6794f8d35029 |
child 56777 | 48515da9356a94dabb7e541a82a5c3f9ea7bf37c |
push id | 16665 |
push user | rsayre@mozilla.com |
push date | Sun, 31 Oct 2010 10:52:31 +0000 |
treeherder | mozilla-central@504a46e82712 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jorendorff, dvander |
bugs | 604504 |
milestone | 2.0b8pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1323,16 +1323,37 @@ InvokeConstructorWithGivenThis(JSContext ok = Invoke(cx, args, JSINVOKE_CONSTRUCT); } *rval = args.rval(); return ok; } bool +DirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp) +{ + JS_ASSERT(vp == cx->regs->sp - argc - 2); + JS_ASSERT(vp[0].isObject()); + JS_ASSERT(vp[0].toObject().isFunction()); + JS_ASSERT(vp[0].toObject().getFunctionPrivate() == evalfun); + JS_ASSERT(IsBuiltinEvalFunction(evalfun)); + + AutoFunctionCallProbe callProbe(cx, evalfun); + + JSStackFrame *caller = cx->fp(); + JS_ASSERT(caller->isScriptFrame()); + JSObject *scopeChain = + GetScopeChainFast(cx, caller, JSOP_EVAL, JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH); + if (!scopeChain || !EvalKernel(cx, argc, vp, DIRECT_EVAL, caller, scopeChain)) + return false; + cx->regs->sp = vp + 1; + return true; +} + +bool ValueToId(JSContext *cx, const Value &v, jsid *idp) { int32_t i; if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) { *idp = INT_TO_JSID(i); return true; } @@ -4627,21 +4648,17 @@ BEGIN_CASE(JSOP_EVAL) if (!IsFunctionObject(*vp, &callee)) goto call_using_invoke; newfun = callee->getFunctionPrivate(); if (!IsBuiltinEvalFunction(newfun)) goto not_direct_eval; - Probes::enterJSFun(cx, newfun); - JSBool ok = CallJSNative(cx, newfun->u.n.native, argc, vp); - Probes::exitJSFun(cx, newfun); - regs.sp = vp + 1; - if (!ok) + if (!DirectEval(cx, newfun, argc, vp)) goto error; } END_CASE(JSOP_EVAL) BEGIN_CASE(JSOP_CALL) BEGIN_CASE(JSOP_APPLY) { argc = GET_ARGC(regs.pc);
--- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -969,16 +969,26 @@ ExternalGetOrSet(JSContext *cx, JSObject extern JS_REQUIRES_STACK bool InvokeConstructor(JSContext *cx, const CallArgs &args); extern JS_REQUIRES_STACK bool InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval, uintN argc, Value *argv, Value *rval); /* + * Performs a direct eval for the given arguments, which must correspond to the + * currently-executing stack frame, which must be a script frame. evalfun must + * be the built-in eval function and must correspond to the callee in vp[0]. + * When this function succeeds it returns the result in *vp, adjusts the JS + * stack pointer, and returns true. + */ +extern JS_REQUIRES_STACK bool +DirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp); + +/* * Executes a script with the given scope chain in the context of the given * frame. */ extern JS_FORCES_STACK bool Execute(JSContext *cx, JSObject *chain, JSScript *script, JSStackFrame *prev, uintN flags, Value *result); /*
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -926,43 +926,37 @@ js_CheckPrincipalsAccess(JSContext *cx, JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_INDIRECT_CALL, callerstr); return JS_FALSE; } } return JS_TRUE; } -static JSObject * -CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller) -{ - JSObject *inner; - - if (!scopeobj) - goto bad; - - OBJ_TO_INNER_OBJECT(cx, scopeobj); - if (!scopeobj) - return NULL; +static bool +CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj) +{ + JSObject *inner = scopeobj; + OBJ_TO_INNER_OBJECT(cx, inner); + if (!inner) + return false; + JS_ASSERT(inner == scopeobj); /* XXX This is an awful gross hack. */ - inner = scopeobj; while (scopeobj) { JSObjectOp op = scopeobj->getClass()->ext.innerObject; - if (op && op(cx, scopeobj) != scopeobj) - goto bad; + if (op && op(cx, scopeobj) != scopeobj) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_INDIRECT_CALL, + js_eval_str); + return false; + } scopeobj = scopeobj->getParent(); } - return inner; - -bad: - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_INDIRECT_CALL, caller); - return NULL; + return true; } const char * js_ComputeFilename(JSContext *cx, JSStackFrame *caller, JSPrincipals *principals, uintN *linenop) { uint32 flags; #ifdef DEBUG @@ -1088,151 +1082,161 @@ EvalCacheLookup(JSContext *cx, JSString } return NULL; } /* ES5 15.1.2.1. */ static JSBool eval(JSContext *cx, uintN argc, Value *vp) { - if (argc < 1) { - vp->setUndefined(); - return true; - } + /* + * NB: This method handles only indirect eval: direct eval is handled by + * JSOP_EVAL. + */ JSStackFrame *caller = js_GetScriptedCaller(cx, NULL); + + /* FIXME Bug 602994: This really should be perfectly cromulent. */ if (!caller) { /* Eval code needs to inherit principals from the caller. */ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_INDIRECT_CALL, js_eval_str); return false; } - jsbytecode *callerPC = caller->pc(cx); - bool directCall = (callerPC && js_GetOpcode(cx, caller->script(), callerPC) == JSOP_EVAL); - - /* - * If the callee was originally a cross-compartment wrapper, this is an - * indirect call. - */ - if (directCall && caller->scopeChain().compartment() != vp[0].toObject().compartment()) - directCall = false; - + return EvalKernel(cx, argc, vp, INDIRECT_EVAL, caller, vp[0].toObject().getGlobal()); +} + +namespace js { + +bool +EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame *caller, + JSObject *scopeobj) +{ /* - * Direct calls to eval are supposed to see the caller's |this|. If we - * haven't wrapped that yet, do so now, before we make a copy of it for - * the eval code to use. + * FIXME Bug 602994: Calls with no scripted caller should be permitted and + * should be implemented as indirect calls. */ - if (!caller->computeThis(cx)) - return false; - - Value *argv = JS_ARGV(cx, vp); - if (!argv[0].isString()) { - *vp = argv[0]; - return true; - } + JS_ASSERT(caller); + JS_ASSERT(scopeobj); /* * We once supported a second argument to eval to use as the scope chain * when evaluating the code string. Warn when such uses are seen so that * authors will know that support for eval(s, o) has been removed. */ - if (argc > 1 && !caller->script()->warnedAboutTwoArgumentEval) { + JSScript *callerScript = caller->script(); + if (argc > 1 && !callerScript->warnedAboutTwoArgumentEval) { static const char TWO_ARGUMENT_WARNING[] = "Support for eval(code, scopeObject) has been removed. " "Use |with (scopeObject) eval(code);| instead."; if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING)) return false; - caller->script()->warnedAboutTwoArgumentEval = true; - } - - /* - * Per ES5, if we see an indirect call, then run in the global scope. - * (eval is specified this way so that the compiler can make assumptions - * about what bindings may or may not exist in the current frame if it - * doesn't see 'eval'.) - */ - uintN staticLevel; - JSObject *scopeobj; - if (directCall) { - /* Compile using the caller's current scope object. */ - staticLevel = caller->script()->staticLevel + 1; - scopeobj = GetScopeChainFast(cx, caller, JSOP_EVAL, - JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH); - if (!scopeobj) - return false; - - JS_ASSERT_IF(caller->isFunctionFrame(), caller->hasCallObj()); - } else { - /* Pretend that we're top level. */ - staticLevel = 0; - scopeobj = vp[0].toObject().getGlobal(); - } - - /* Ensure we compile this eval with the right object in the scope chain. */ - JSObject *result = CheckScopeChainValidity(cx, scopeobj, js_eval_str); - if (!result) - return false; - JS_ASSERT(result == scopeobj); + callerScript->warnedAboutTwoArgumentEval = true; + } /* * CSP check: Is eval() allowed at all? * Report errors via CSP is done in the script security mgr. */ if (!js_CheckContentSecurityPolicy(cx)) { JS_ReportError(cx, "call to eval() blocked by CSP"); return false; } - JSObject *callee = &vp[0].toObject(); + /* ES5 15.1.2.1 step 1. */ + if (argc < 1) { + vp->setUndefined(); + return true; + } + if (!vp[2].isString()) { + *vp = vp[2]; + return true; + } + JSString *str = vp[2].toString(); + + /* ES5 15.1.2.1 steps 2-8. */ + JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, Jsvalify(vp))); + JS_ASSERT(IsBuiltinEvalFunction(callee->getFunctionPrivate())); JSPrincipals *principals = js_EvalFramePrincipals(cx, callee, caller); - uintN line; - const char *file = js_ComputeFilename(cx, caller, principals, &line); - - JSString *str = argv[0].toString(); - JSScript *script = NULL; + + /* + * Per ES5, indirect eval runs in the global scope. (eval is specified this + * way so that the compiler can make assumptions about what bindings may or + * may not exist in the current frame if it doesn't see 'eval'.) + */ + uintN staticLevel; + if (evalType == DIRECT_EVAL) { + staticLevel = caller->script()->staticLevel + 1; + +#ifdef DEBUG + jsbytecode *callerPC = caller->pc(cx); + JS_ASSERT_IF(caller->isFunctionFrame(), caller->hasCallObj()); + JS_ASSERT(callerPC && js_GetOpcode(cx, caller->script(), callerPC) == JSOP_EVAL); +#endif + } else { + /* Pretend that we're top level. */ + staticLevel = 0; + + JS_ASSERT(scopeobj == scopeobj->getGlobal()); + JS_ASSERT(scopeobj->isGlobal()); + } + + /* Ensure we compile this eval with the right object in the scope chain. */ + if (!CheckScopeChainValidity(cx, scopeobj)) + return false; const jschar *chars; size_t length; str->getCharsAndLength(chars, length); /* * If the eval string starts with '(' and ends with ')', it may be JSON. * Try the JSON parser first because it's much faster. If the eval string * isn't JSON, JSON parsing will probably fail quickly, so little time * will be lost. */ - if (length > 2 && chars[0] == '(' && chars[length-1] == ')') { + if (length > 2 && chars[0] == '(' && chars[length - 1] == ')') { JSONParser *jp = js_BeginJSONParse(cx, vp, /* suppressErrors = */true); - JSBool ok = jp != NULL; - if (ok) { + if (jp != NULL) { /* Run JSON-parser on string inside ( and ). */ - ok = js_ConsumeJSONText(cx, jp, chars+1, length-2); + JSBool ok = js_ConsumeJSONText(cx, jp, chars + 1, length - 2); ok &= js_FinishJSONParse(cx, jp, NullValue()); if (ok) return true; } } + /* + * Direct calls to eval are supposed to see the caller's |this|. If we + * haven't wrapped that yet, do so now, before we make a copy of it for + * the eval code to use. + */ + if (evalType == DIRECT_EVAL && !caller->computeThis(cx)) + return false; + + JSScript *script = NULL; JSScript **bucket = EvalCacheHash(cx, str); - if (directCall && caller->isFunctionFrame()) + if (evalType == DIRECT_EVAL && caller->isFunctionFrame()) script = EvalCacheLookup(cx, str, caller, staticLevel, principals, scopeobj, bucket); /* - * We can't have a callerFrame (down in js_Execute's terms) if we're in - * global code. This includes indirect eval and direct eval called with a - * scope object parameter. + * We can't have a callerFrame (down in js::Execute's terms) if we're in + * global code (or if we're an indirect eval). */ JSStackFrame *callerFrame = (staticLevel != 0) ? caller : NULL; if (!script) { + uintN lineno; + const char *filename = js_ComputeFilename(cx, caller, principals, &lineno); + uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL; script = Compiler::compileScript(cx, scopeobj, callerFrame, principals, tcflags, chars, length, - NULL, file, line, str, staticLevel); + NULL, filename, lineno, str, staticLevel); if (!script) return false; } assertSameCompartment(cx, scopeobj, script); /* * Belt-and-braces: check that the lesser of eval's principals and the @@ -1246,18 +1250,16 @@ eval(JSContext *cx, uintN argc, Value *v *bucket = script; #ifdef CHECK_SCRIPT_OWNER script->owner = NULL; #endif return ok; } -namespace js { - bool IsBuiltinEvalFunction(JSFunction *fun) { return fun->maybeNative() == eval; } }
--- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1712,13 +1712,29 @@ js_Object(JSContext *cx, uintN argc, js: namespace js { extern bool SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles); extern JSString * obj_toStringHelper(JSContext *cx, JSObject *obj); +enum EvalType { INDIRECT_EVAL, DIRECT_EVAL }; + +/* + * Common code implementing direct and indirect eval. + * + * Evaluate vp[2], if it is a string, in the context of the given calling + * frame, with the provided scope chain, with the semantics of either a direct + * or indirect eval (see ES5 10.4.2). If this is an indirect eval, scopeobj + * must be a global object. + * + * On success, store the completion value in *vp and return true. + */ +extern bool +EvalKernel(JSContext *cx, uintN argc, js::Value *vp, EvalType evalType, JSStackFrame *caller, + JSObject *scopeobj); + extern bool IsBuiltinEvalFunction(JSFunction *fun); } #endif /* jsobj_h___ */
--- a/js/src/jsprobes.h +++ b/js/src/jsprobes.h @@ -211,11 +211,30 @@ inline void Probes::GCEnd(JSCompartment inline void Probes::GCStartMarkPhase(JSCompartment *compartment) {} inline void Probes::GCEndMarkPhase(JSCompartment *compartment) {} inline void Probes::GCStartSweepPhase(JSCompartment *compartment) {} inline void Probes::GCEndSweepPhase(JSCompartment *compartment) {} inline JSBool Probes::CustomMark(JSString *string) { return JS_TRUE; } inline JSBool Probes::CustomMark(const char *string) { return JS_TRUE; } inline JSBool Probes::CustomMark(int marker) { return JS_TRUE; } +struct AutoFunctionCallProbe { + JSContext * const cx; + JSFunction *fun; + js::Value *lval; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + AutoFunctionCallProbe(JSContext *cx, JSFunction *fun, js::Value *lval = NULL + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : cx(cx), fun(fun), lval(lval) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + Probes::enterJSFun(cx, fun, lval); + } + + ~AutoFunctionCallProbe() { + Probes::exitJSFun(cx, fun, lval); + } +}; + } /* namespace js */ #endif /* _JSPROBES_H */
--- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -1206,17 +1206,21 @@ mjit::Compiler::generateMethod() prepareStubCall(Uses(0)); masm.move(Imm32(fullAtomIndex(PC)), Registers::ArgReg1); stubCall(stubs::CallName); frame.pushSynced(); frame.pushSynced(); END_CASE(JSOP_CALLNAME) BEGIN_CASE(JSOP_EVAL) - jsop_eval(); + { + JaegerSpew(JSpew_Insns, " --- EVAL --- \n"); + emitEval(GET_ARGC(PC)); + JaegerSpew(JSpew_Insns, " --- END EVAL --- \n"); + } END_CASE(JSOP_EVAL) BEGIN_CASE(JSOP_CALL) BEGIN_CASE(JSOP_APPLY) { JaegerSpew(JSpew_Insns, " --- SCRIPTED CALL --- \n"); inlineCallHelper(GET_ARGC(PC), false); JaegerSpew(JSpew_Insns, " --- END SCRIPTED CALL --- \n"); @@ -4323,21 +4327,27 @@ mjit::Compiler::jsop_instanceof() if (firstSlow.isSet()) firstSlow.getJump().linkTo(stubcc.masm.label(), &stubcc.masm); stubcc.rejoin(Changes(1)); return true; } void -mjit::Compiler::jsop_eval() +mjit::Compiler::emitEval(uint32 argc) { - JaegerSpew(JSpew_Insns, " --- SCRIPTED CALL --- \n"); - inlineCallHelper(GET_ARGC(PC), false); - JaegerSpew(JSpew_Insns, " --- END SCRIPTED CALL --- \n"); + /* Check for interrupts on function call */ + interruptCheckHelper(); + + frame.syncAndKill(Registers(Registers::AvailRegs), Uses(argc + 2)); + prepareStubCall(Uses(argc + 2)); + masm.move(Imm32(argc), Registers::ArgReg1); + stubCall(stubs::Eval); + frame.popn(argc + 2); + frame.pushSynced(); } /* * Note: This function emits tracer hooks into the OOL path. This means if * it is used in the middle of an in-progress slow path, the stream will be * hopelessly corrupted. Take care to only call this before linkExits() and * after rejoin()s. */
--- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -363,17 +363,17 @@ class Compiler : public BaseCompiler bool jsop_callprop_obj(JSAtom *atom); bool jsop_callprop_str(JSAtom *atom); bool jsop_callprop_generic(JSAtom *atom); bool jsop_instanceof(); void jsop_name(JSAtom *atom); bool jsop_xname(JSAtom *atom); void enterBlock(JSObject *obj); void leaveBlock(); - void jsop_eval(); + void emitEval(uint32 argc); /* Fast arithmetic. */ void jsop_binary(JSOp op, VoidStub stub); void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub); void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub); void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub); void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg);
--- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -437,16 +437,40 @@ stubs::UncachedNewHelper(VMFrame &f, uin void * JS_FASTCALL stubs::UncachedCall(VMFrame &f, uint32 argc) { UncachedCallResult ucr; UncachedCallHelper(f, argc, &ucr); return ucr.codeAddr; } +void JS_FASTCALL +stubs::Eval(VMFrame &f, uint32 argc) +{ + Value *vp = f.regs.sp - (argc + 2); + + JSObject *callee; + JSFunction *fun; + + if (!IsFunctionObject(*vp, &callee) || + !IsBuiltinEvalFunction((fun = callee->getFunctionPrivate()))) + { + if (!ComputeThisFromVpInPlace(f.cx, vp) || + !Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0)) + { + THROW(); + } + return; + } + + JS_ASSERT(f.regs.fp == f.cx->fp()); + if (!DirectEval(f.cx, fun, argc, vp)) + THROW(); +} + void stubs::UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr) { ucr->init(); JSContext *cx = f.cx; Value *vp = f.regs.sp - (argc + 2);
--- a/js/src/methodjit/StubCalls.h +++ b/js/src/methodjit/StubCalls.h @@ -60,16 +60,17 @@ void JS_FASTCALL InitMethod(VMFrame &f, void JS_FASTCALL HitStackQuota(VMFrame &f); void * JS_FASTCALL FixupArity(VMFrame &f, uint32 argc); void * JS_FASTCALL CompileFunction(VMFrame &f, uint32 argc); void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc); void JS_FASTCALL SlowCall(VMFrame &f, uint32 argc); void * JS_FASTCALL UncachedNew(VMFrame &f, uint32 argc); void * JS_FASTCALL UncachedCall(VMFrame &f, uint32 argc); +void JS_FASTCALL Eval(VMFrame &f, uint32 argc); void JS_FASTCALL EnterScript(VMFrame &f); void JS_FASTCALL LeaveScript(VMFrame &f); /* * Result struct for UncachedXHelper. * * These functions can have one of two results: *
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_5/Global/eval-native-callback-is-indirect.js @@ -0,0 +1,32 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 604504; +var summary = "eval called from a native function is indirect"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var originalEval = eval; + +var global = this; +var directCheckCode = "this === global"; + +function testBound() +{ + var global = "psych!"; + var eval = originalEval.bind(undefined, directCheckCode); + assertEq(eval(), true); +} +testBound(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!");
--- a/js/src/tests/ecma_5/Global/jstests.list +++ b/js/src/tests/ecma_5/Global/jstests.list @@ -1,6 +1,7 @@ url-prefix ../../jsreftest.html?test=ecma_5/Global/ script parseInt-01.js script eval-01.js script eval-02.js script eval-inside-with-is-direct.js script parenthesized-eval-is-direct.js +script eval-native-callback-is-indirect.js
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/eval-native-callback-is-indirect.js @@ -0,0 +1,43 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 604504; +var summary = "eval called from a native function is indirect"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var originalEval = eval; + +var global = this; +var directCheckCode = "this === global"; + +function testArrayGeneric() +{ + var global = "psych!"; + var eval = Array.map; + + var mapped = eval([directCheckCode], originalEval); + assertEq(mapped[0], true); +} + +function testStringGeneric() +{ + var global = "psych!"; + var eval = String.replace; + + var newString = eval(directCheckCode, directCheckCode, originalEval); + assertEq(newString, "true"); +} +testStringGeneric(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!");
--- a/js/src/tests/ecma_5/extensions/jstests.list +++ b/js/src/tests/ecma_5/extensions/jstests.list @@ -2,9 +2,10 @@ url-prefix ../../jsreftest.html?test=ecm script 15.4.4.11.js script 8.12.5-01.js script Boolean-toSource.js script Number-toSource.js script String-toSource.js script proxy-strict.js script regress-bug567606.js script string-literal-getter-setter-decompilation.js +script eval-native-callback-is-indirect.js script regress-bug607284.js