author | Luke Wagner <luke@mozilla.com> |
Fri, 09 Nov 2012 11:39:52 -0800 | |
changeset 112868 | 843a3db9c0457acbdf91e257a927ac97ea4a7dc5 |
parent 112867 | 7dbb863bed7ca9906af2df81569f0d42f15d2808 |
child 112869 | 5fd176fb2acaec963539d0a9ce513aec76b22169 |
push id | 23839 |
push user | ryanvm@gmail.com |
push date | Sat, 10 Nov 2012 01:34:49 +0000 |
treeherder | autoland@a47525b93528 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jimb |
bugs | 807845 |
milestone | 19.0a1 |
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/jsapi-tests/Makefile.in +++ b/js/src/jsapi-tests/Makefile.in @@ -60,16 +60,17 @@ CPPSRCS = \ testStringBuffer.cpp \ testTrap.cpp \ testTypedArrays.cpp \ testVersion.cpp \ testXDR.cpp \ testProfileStrings.cpp \ testJSEvaluateScript.cpp \ testErrorCopying.cpp \ + testEnclosingFunction.cpp \ $(NULL) # Disabled: an entirely unrelated test seems to cause this to fail. Moreover, # given the test's dependence on interactions between the compiler, the GC, and # conservative stack scanning, the fix isn't obvious: more investigation # needed. #CPPSRCS += \ # testRegExpInstanceProperties.cpp \
new file mode 100644 --- /dev/null +++ b/js/src/jsapi-tests/testEnclosingFunction.cpp @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * Test script cloning. + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "tests.h" +#include "jsfriendapi.h" +#include "jsdbgapi.h" + +using namespace js; + +JSScript *found = NULL; + +JSBool +CheckEnclosing(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + found = js::GetOutermostEnclosingFunctionOfScriptedCaller(cx); + + args.rval().set(UndefinedValue()); + return true; +} + +BEGIN_TEST(test_enclosingFunction) +{ + CHECK(JS_DefineFunction(cx, global, "checkEnclosing", CheckEnclosing, 0, 0)); + + EXEC("checkEnclosing()"); + CHECK(found == NULL); + + RootedFunction fun(cx); + + const char s1chars[] = "checkEnclosing()"; + fun = JS_CompileFunction(cx, global, "s1", 0, NULL, s1chars, strlen(s1chars), __FILE__, __LINE__); + CHECK(fun); + EXEC("s1()"); + CHECK(found == JS_GetFunctionScript(cx, fun)); + + const char s2chars[] = "return function() { checkEnclosing() }"; + fun = JS_CompileFunction(cx, global, "s2", 0, NULL, s2chars, strlen(s2chars), __FILE__, __LINE__); + CHECK(fun); + EXEC("s2()()"); + CHECK(found == JS_GetFunctionScript(cx, fun)); + + const char s3chars[] = "return function() { let (x) { function g() { checkEnclosing() } return g() } }"; + fun = JS_CompileFunction(cx, global, "s3", 0, NULL, s3chars, strlen(s3chars), __FILE__, __LINE__); + CHECK(fun); + EXEC("s3()()"); + CHECK(found == JS_GetFunctionScript(cx, fun)); + + return true; +} +END_TEST(test_enclosingFunction)
--- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -366,16 +366,35 @@ js::IsObjectInContextCompartment(RawObje } JS_FRIEND_API(bool) js::IsOriginalScriptFunction(JSFunction *fun) { return fun->script()->function() == fun; } +JS_FRIEND_API(JSScript *) +js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx) +{ + if (!cx->hasfp()) + return NULL; + + StackFrame *fp = cx->fp(); + if (!fp->isFunctionFrame()) + return NULL; + + JSFunction *scriptedCaller = fp->fun(); + RootedScript outermost(cx, scriptedCaller->script()); + for (StaticScopeIter i(scriptedCaller); !i.done(); i++) { + if (i.type() == StaticScopeIter::FUNCTION) + outermost = i.funScript(); + } + return outermost; +} + JS_FRIEND_API(JSFunction *) js::DefineFunctionWithReserved(JSContext *cx, JSObject *objArg, const char *name, JSNative call, unsigned nargs, unsigned attrs) { RootedObject obj(cx, objArg); JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); CHECK_REQUEST(cx); assertSameCompartment(cx, obj);
--- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -393,16 +393,28 @@ JS_FRIEND_API(JSObject *) GetGlobalForObjectCrossCompartment(RawObject obj); JS_FRIEND_API(void) NotifyAnimationActivity(RawObject obj); JS_FRIEND_API(bool) IsOriginalScriptFunction(JSFunction *fun); +/* + * Return the outermost enclosing function (script) of the scripted caller. + * This function returns NULL in several cases: + * - no script is running on the context + * - the caller is in global or eval code + * In particular, this function will "stop" its outermost search at eval() and + * thus it will really return the outermost enclosing function *since the + * innermost eval*. + */ +JS_FRIEND_API(JSScript *) +GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx); + JS_FRIEND_API(JSFunction *) DefineFunctionWithReserved(JSContext *cx, JSObject *obj, const char *name, JSNative call, unsigned nargs, unsigned attrs); JS_FRIEND_API(JSFunction *) NewFunctionWithReserved(JSContext *cx, JSNative call, unsigned nargs, unsigned flags, JSObject *parent, const char *name);