Bug 776332 - Fix the rooting of Function's toSource/toString. r=terrence

This commit is contained in:
Benjamin Peterson 2012-07-24 14:23:36 -07:00
parent cd57edc68c
commit 639c29d087
3 changed files with 36 additions and 35 deletions

View File

@ -5342,29 +5342,32 @@ JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, unsigned i
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
if (script->function())
return JS_DecompileFunction(cx, script->function(), indent);
RootedFunction fun(cx, script->function());
if (fun)
return JS_DecompileFunction(cx, fun, indent);
return script->sourceData(cx);
}
JS_PUBLIC_API(JSString *)
JS_DecompileFunction(JSContext *cx, JSFunction *fun, unsigned indent)
JS_DecompileFunction(JSContext *cx, JSFunction *funArg, unsigned indent)
{
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, fun);
return fun->toString(cx, false, !(indent & JS_DONT_PRETTY_PRINT));
assertSameCompartment(cx, funArg);
RootedFunction fun(cx, funArg);
return FunctionToString(cx, fun, false, !(indent & JS_DONT_PRETTY_PRINT));
}
JS_PUBLIC_API(JSString *)
JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, unsigned indent)
JS_DecompileFunctionBody(JSContext *cx, JSFunction *funArg, unsigned indent)
{
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, fun);
return fun->toString(cx, true, !(indent & JS_DONT_PRETTY_PRINT));
assertSameCompartment(cx, funArg);
RootedFunction fun(cx, funArg);
return FunctionToString(cx, fun, true, !(indent & JS_DONT_PRETTY_PRINT));
}
JS_NEVER_INLINE JS_PUBLIC_API(JSBool)

View File

@ -526,7 +526,7 @@ JS_FRIEND_DATA(Class) js::FunctionClass = {
/* Find the body of a function (not including braces). */
static bool
FindBody(JSContext *cx, JSFunction *fun, const jschar *chars, size_t length,
FindBody(JSContext *cx, HandleFunction fun, const jschar *chars, size_t length,
size_t *bodyStart, size_t *bodyEnd)
{
// We don't need principals, since those are only used for error reporting.
@ -573,11 +573,11 @@ FindBody(JSContext *cx, JSFunction *fun, const jschar *chars, size_t length,
}
JSString *
JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
js::FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen)
{
StringBuffer out(cx);
if (isInterpreted() && script()->isGeneratorExp) {
if (fun->isInterpreted() && fun->script()->isGeneratorExp) {
if ((!bodyOnly && !out.append("function genexp() {")) ||
!out.append("\n [generator expression]\n") ||
(!bodyOnly && !out.append("}"))) {
@ -587,32 +587,33 @@ JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
}
if (!bodyOnly) {
// If we're not in pretty mode, put parentheses around lambda functions.
if (isInterpreted() && !lambdaParen && (flags & JSFUN_LAMBDA)) {
if (fun->isInterpreted() && !lambdaParen && (fun->flags & JSFUN_LAMBDA)) {
if (!out.append("("))
return NULL;
}
if (!out.append("function "))
return NULL;
if (atom) {
if (!out.append(atom))
if (fun->atom) {
if (!out.append(fun->atom))
return NULL;
}
}
bool haveSource = isInterpreted();
if (haveSource && !script()->source && !script()->loadSource(cx, &haveSource))
bool haveSource = fun->isInterpreted();
if (haveSource && !fun->script()->source && !fun->script()->loadSource(cx, &haveSource))
return NULL;
if (haveSource) {
RootedString src(cx, script()->sourceData(cx));
RootedScript script(cx, fun->script());
RootedString src(cx, fun->script()->sourceData(cx));
if (!src)
return NULL;
const jschar *chars = src->getChars(cx);
if (!chars)
return NULL;
bool exprBody = flags & JSFUN_EXPR_CLOSURE;
bool exprBody = fun->flags & JSFUN_EXPR_CLOSURE;
// The source data for functions created by calling the Function
// constructor is only the function's body.
bool funCon = script()->sourceStart == 0 && script()->source->argumentsNotIncluded();
bool funCon = script->sourceStart == 0 && script->source->argumentsNotIncluded();
// Functions created with the constructor should not be using the
// expression body extension.
@ -623,7 +624,7 @@ JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
// have "use strict", we insert "use strict" into the body of the
// function. This ensures that if the result of toString is evaled, the
// resulting function will have the same semantics.
bool addUseStrict = script()->strictModeCode && !script()->explicitUseStrict;
bool addUseStrict = script->strictModeCode && !script->explicitUseStrict;
// Functions created with the constructor can't have inherited strict
// mode.
@ -640,11 +641,11 @@ JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
// Fish out the argument names.
BindingVector *localNames = cx->new_<BindingVector>(cx);
js::ScopedDeletePtr<BindingVector> freeNames(localNames);
if (!GetOrderedBindings(cx, script()->bindings, localNames))
if (!GetOrderedBindings(cx, script->bindings, localNames))
return NULL;
for (unsigned i = 0; i < nargs; i++) {
for (unsigned i = 0; i < fun->nargs; i++) {
if ((i && !out.append(", ")) ||
(i == unsigned(nargs - 1) && hasRest() && !out.append("...")) ||
(i == unsigned(fun->nargs - 1) && fun->hasRest() && !out.append("...")) ||
!out.append((*localNames)[i].maybeName)) {
return NULL;
}
@ -657,7 +658,7 @@ JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
// return the body or we need to insert "use strict" into the body.
JS_ASSERT(!buildBody);
size_t bodyStart = 0, bodyEnd = 0;
if (!FindBody(cx, this, chars, src->length(), &bodyStart, &bodyEnd))
if (!FindBody(cx, fun, chars, src->length(), &bodyStart, &bodyEnd))
return NULL;
if (addUseStrict) {
@ -693,19 +694,19 @@ JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
// Slap a semicolon on the end of functions with an expression body.
if (exprBody && !out.append(";"))
return NULL;
} else if (!lambdaParen && (flags & JSFUN_LAMBDA)) {
} else if (!lambdaParen && (fun->flags & JSFUN_LAMBDA)) {
if (!out.append(")"))
return NULL;
}
} else if (isInterpreted()) {
} else if (fun->isInterpreted()) {
if ((!bodyOnly && !out.append("() {\n ")) ||
!out.append("[sourceless code]") ||
(!bodyOnly && !out.append("\n}")))
return NULL;
if (!lambdaParen && (flags & JSFUN_LAMBDA) && (!out.append(")")))
if (!lambdaParen && (fun->flags & JSFUN_LAMBDA) && (!out.append(")")))
return NULL;
} else {
JS_ASSERT(!(flags & JSFUN_EXPR_CLOSURE));
JS_ASSERT(!(fun->flags & JSFUN_EXPR_CLOSURE));
if ((!bodyOnly && !out.append("() {\n ")) ||
!out.append("[native code]") ||
(!bodyOnly && !out.append("\n}")))
@ -727,11 +728,8 @@ fun_toStringHelper(JSContext *cx, JSObject *obj, unsigned indent)
return NULL;
}
JSFunction *fun = obj->toFunction();
if (!fun)
return NULL;
return fun->toString(cx, false, indent != JS_DONT_PRETTY_PRINT);
RootedFunction fun(cx, obj->toFunction());
return FunctionToString(cx, fun, false, indent != JS_DONT_PRETTY_PRINT);
}
static JSBool

View File

@ -153,8 +153,6 @@ struct JSFunction : public JSObject
inline const js::Value &getBoundFunctionArgument(unsigned which) const;
inline size_t getBoundFunctionArgumentCount() const;
JSString *toString(JSContext *cx, bool bodyOnly, bool pretty);
private:
inline js::FunctionExtended *toExtended();
inline const js::FunctionExtended *toExtended() const;
@ -248,6 +246,8 @@ JSFunction::toExtended() const
namespace js {
JSString *FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen);
template<XDRMode mode>
bool
XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope,