Bug 1271650 - Move EvaluateInEnv and DebuggerGenericEval. r=jimb

This commit is contained in:
Eddy Bruel 2016-08-14 09:49:54 +02:00
Родитель d125232b98
Коммит e430a1e3bd
1 изменённых файлов: 168 добавлений и 167 удалений

Просмотреть файл

@ -7291,6 +7291,174 @@ DebuggerFrame::getImplementation(HandleDebuggerFrame frame)
return DebuggerFrameImplementation::Interpreter;
}
/*
* Evaluate |chars[0..length-1]| in the environment |env|, treating that
* source as appearing starting at |lineno| in |filename|. Store the return
* value in |*rval|. Use |thisv| as the 'this' value.
*
* If |frame| is non-nullptr, evaluate as for a direct eval in that frame; |env|
* must be either |frame|'s DebugScopeObject, or some extension of that
* environment; either way, |frame|'s scope is where newly declared variables
* go. In this case, |frame| must have a computed 'this' value, equal to |thisv|.
*/
static bool
EvaluateInEnv(JSContext* cx, Handle<Env*> env, AbstractFramePtr frame,
jsbytecode* pc, mozilla::Range<const char16_t> chars, const char* filename,
unsigned lineno, MutableHandleValue rval)
{
assertSameCompartment(cx, env, frame);
MOZ_ASSERT_IF(frame, pc);
/*
* Pass in a StaticEvalScope *not* linked to env for evalStaticScope, as
* ScopeIter should stop at any non-ScopeObject or non-syntactic With
* boundaries, and we are putting a DebugScopeProxy or non-syntactic With on
* the scope chain.
*/
Rooted<StaticScope*> enclosingStaticScope(cx);
if (!IsGlobalLexicalScope(env)) {
// If we are doing a global evalWithBindings, we will still need to
// link the static global lexical scope to the static non-syntactic
// scope.
if (IsGlobalLexicalScope(env->enclosingScope()))
enclosingStaticScope = &cx->global()->lexicalScope().staticBlock();
enclosingStaticScope = StaticNonSyntacticScope::create(cx, enclosingStaticScope);
if (!enclosingStaticScope)
return false;
} else {
enclosingStaticScope = &cx->global()->lexicalScope().staticBlock();
}
// Do not consider executeInGlobal{WithBindings} as an eval, but instead
// as executing a series of statements at the global level. This is to
// circumvent the fresh lexical scope that all eval have, so that the
// users of executeInGlobal, like the web console, may add new bindings to
// the global scope.
Rooted<StaticScope*> staticScope(cx);
if (frame) {
staticScope = StaticEvalScope::create(cx, enclosingStaticScope);
if (!staticScope)
return false;
} else {
staticScope = enclosingStaticScope;
}
CompileOptions options(cx);
options.setIsRunOnce(true)
.setForEval(true)
.setNoScriptRval(false)
.setFileAndLine(filename, lineno)
.setCanLazilyParse(false)
.setIntroductionType("debugger eval")
.maybeMakeStrictMode(frame ? frame.script()->strict() : false);
RootedScript callerScript(cx, frame ? frame.script() : nullptr);
SourceBufferHolder srcBuf(chars.start().get(), chars.length(), SourceBufferHolder::NoOwnership);
RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), env, staticScope,
callerScript, options, srcBuf,
/* source = */ nullptr));
if (!script)
return false;
// Again, executeInGlobal is not considered eval.
if (frame) {
if (script->strict())
staticScope->as<StaticEvalScope>().setStrict();
script->setActiveEval();
}
return ExecuteKernel(cx, script, *env, NullValue(), frame, rval.address());
}
static bool
DebuggerGenericEval(JSContext* cx, const mozilla::Range<const char16_t> chars,
HandleObject bindings, const EvalOptions& options,
JSTrapStatus& status, MutableHandleValue value,
Debugger* dbg, HandleObject scope, ScriptFrameIter* iter)
{
/* Either we're specifying the frame, or a global. */
MOZ_ASSERT_IF(iter, !scope);
MOZ_ASSERT_IF(!iter, scope && IsGlobalLexicalScope(scope));
/*
* Gather keys and values of bindings, if any. This must be done in the
* debugger compartment, since that is where any exceptions must be
* thrown.
*/
AutoIdVector keys(cx);
AutoValueVector values(cx);
if (bindings) {
if (!GetPropertyKeys(cx, bindings, JSITER_OWNONLY, &keys) ||
!values.growBy(keys.length()))
{
return false;
}
for (size_t i = 0; i < keys.length(); i++) {
MutableHandleValue valp = values[i];
if (!GetProperty(cx, bindings, bindings, keys[i], valp) ||
!dbg->unwrapDebuggeeValue(cx, valp))
{
return false;
}
}
}
Maybe<AutoCompartment> ac;
if (iter)
ac.emplace(cx, iter->scopeChain(cx));
else
ac.emplace(cx, scope);
Rooted<Env*> env(cx);
if (iter) {
env = GetDebugScopeForFrame(cx, iter->abstractFramePtr(), iter->pc());
if (!env)
return false;
} else {
env = scope;
}
/* If evalWithBindings, create the inner environment. */
if (bindings) {
RootedPlainObject nenv(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
if (!nenv)
return false;
RootedId id(cx);
for (size_t i = 0; i < keys.length(); i++) {
id = keys[i];
MutableHandleValue val = values[i];
if (!cx->compartment()->wrap(cx, val) ||
!NativeDefineProperty(cx, nenv, id, val, nullptr, nullptr, 0))
{
return false;
}
}
AutoObjectVector scopeChain(cx);
if (!scopeChain.append(nenv))
return false;
RootedObject dynamicScope(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, env, &dynamicScope))
return false;
env = dynamicScope;
}
/* Run the code and produce the completion value. */
LeaveDebuggeeNoExecute nnx(cx);
RootedValue rval(cx);
AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr();
jsbytecode* pc = iter ? iter->pc() : nullptr;
bool ok = EvaluateInEnv(cx, env, frame, pc, chars,
options.filename() ? options.filename() : "debugger eval code",
options.lineno(), &rval);
Debugger::resultToCompletion(cx, ok, rval, &status, value);
ac.reset();
return dbg->wrapDebuggeeValue(cx, value);
}
/* statuc */ bool
DebuggerFrame::isLive() const
{
@ -7841,173 +8009,6 @@ DebuggerFrame_setOnPop(JSContext* cx, unsigned argc, Value* vp)
return true;
}
/*
* Evaluate |chars[0..length-1]| in the environment |env|, treating that
* source as appearing starting at |lineno| in |filename|. Store the return
* value in |*rval|. Use |thisv| as the 'this' value.
*
* If |frame| is non-nullptr, evaluate as for a direct eval in that frame; |env|
* must be either |frame|'s DebugScopeObject, or some extension of that
* environment; either way, |frame|'s scope is where newly declared variables
* go. In this case, |frame| must have a computed 'this' value, equal to |thisv|.
*/
static bool
EvaluateInEnv(JSContext* cx, Handle<Env*> env, AbstractFramePtr frame,
jsbytecode* pc, mozilla::Range<const char16_t> chars, const char* filename,
unsigned lineno, MutableHandleValue rval)
{
assertSameCompartment(cx, env, frame);
MOZ_ASSERT_IF(frame, pc);
/*
* Pass in a StaticEvalScope *not* linked to env for evalStaticScope, as
* ScopeIter should stop at any non-ScopeObject or non-syntactic With
* boundaries, and we are putting a DebugScopeProxy or non-syntactic With on
* the scope chain.
*/
Rooted<StaticScope*> enclosingStaticScope(cx);
if (!IsGlobalLexicalScope(env)) {
// If we are doing a global evalWithBindings, we will still need to
// link the static global lexical scope to the static non-syntactic
// scope.
if (IsGlobalLexicalScope(env->enclosingScope()))
enclosingStaticScope = &cx->global()->lexicalScope().staticBlock();
enclosingStaticScope = StaticNonSyntacticScope::create(cx, enclosingStaticScope);
if (!enclosingStaticScope)
return false;
} else {
enclosingStaticScope = &cx->global()->lexicalScope().staticBlock();
}
// Do not consider executeInGlobal{WithBindings} as an eval, but instead
// as executing a series of statements at the global level. This is to
// circumvent the fresh lexical scope that all eval have, so that the
// users of executeInGlobal, like the web console, may add new bindings to
// the global scope.
Rooted<StaticScope*> staticScope(cx);
if (frame) {
staticScope = StaticEvalScope::create(cx, enclosingStaticScope);
if (!staticScope)
return false;
} else {
staticScope = enclosingStaticScope;
}
CompileOptions options(cx);
options.setIsRunOnce(true)
.setForEval(true)
.setNoScriptRval(false)
.setFileAndLine(filename, lineno)
.setCanLazilyParse(false)
.setIntroductionType("debugger eval")
.maybeMakeStrictMode(frame ? frame.script()->strict() : false);
RootedScript callerScript(cx, frame ? frame.script() : nullptr);
SourceBufferHolder srcBuf(chars.start().get(), chars.length(), SourceBufferHolder::NoOwnership);
RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), env, staticScope,
callerScript, options, srcBuf,
/* source = */ nullptr));
if (!script)
return false;
// Again, executeInGlobal is not considered eval.
if (frame) {
if (script->strict())
staticScope->as<StaticEvalScope>().setStrict();
script->setActiveEval();
}
return ExecuteKernel(cx, script, *env, NullValue(), frame, rval.address());
}
static bool
DebuggerGenericEval(JSContext* cx, const mozilla::Range<const char16_t> chars,
HandleObject bindings, const EvalOptions& options,
JSTrapStatus& status, MutableHandleValue value,
Debugger* dbg, HandleObject scope, ScriptFrameIter* iter)
{
/* Either we're specifying the frame, or a global. */
MOZ_ASSERT_IF(iter, !scope);
MOZ_ASSERT_IF(!iter, scope && IsGlobalLexicalScope(scope));
/*
* Gather keys and values of bindings, if any. This must be done in the
* debugger compartment, since that is where any exceptions must be
* thrown.
*/
AutoIdVector keys(cx);
AutoValueVector values(cx);
if (bindings) {
if (!GetPropertyKeys(cx, bindings, JSITER_OWNONLY, &keys) ||
!values.growBy(keys.length()))
{
return false;
}
for (size_t i = 0; i < keys.length(); i++) {
MutableHandleValue valp = values[i];
if (!GetProperty(cx, bindings, bindings, keys[i], valp) ||
!dbg->unwrapDebuggeeValue(cx, valp))
{
return false;
}
}
}
Maybe<AutoCompartment> ac;
if (iter)
ac.emplace(cx, iter->scopeChain(cx));
else
ac.emplace(cx, scope);
Rooted<Env*> env(cx);
if (iter) {
env = GetDebugScopeForFrame(cx, iter->abstractFramePtr(), iter->pc());
if (!env)
return false;
} else {
env = scope;
}
/* If evalWithBindings, create the inner environment. */
if (bindings) {
RootedPlainObject nenv(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
if (!nenv)
return false;
RootedId id(cx);
for (size_t i = 0; i < keys.length(); i++) {
id = keys[i];
MutableHandleValue val = values[i];
if (!cx->compartment()->wrap(cx, val) ||
!NativeDefineProperty(cx, nenv, id, val, nullptr, nullptr, 0))
{
return false;
}
}
AutoObjectVector scopeChain(cx);
if (!scopeChain.append(nenv))
return false;
RootedObject dynamicScope(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, env, &dynamicScope))
return false;
env = dynamicScope;
}
/* Run the code and produce the completion value. */
LeaveDebuggeeNoExecute nnx(cx);
RootedValue rval(cx);
AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr();
jsbytecode* pc = iter ? iter->pc() : nullptr;
bool ok = EvaluateInEnv(cx, env, frame, pc, chars,
options.filename() ? options.filename() : "debugger eval code",
options.lineno(), &rval);
Debugger::resultToCompletion(cx, ok, rval, &status, value);
ac.reset();
return dbg->wrapDebuggeeValue(cx, value);
}
static bool
DebuggerFrame_eval(JSContext* cx, unsigned argc, Value* vp)
{