From f044b1e28b14f12479f2b4453cd149103e8266df Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Wed, 22 Jan 2014 16:41:16 -0800 Subject: [PATCH] Bug 944121: Abstract JS shell's compilation options parsing out into its own function. r=bhackett --- js/src/jsapi.cpp | 11 ++- js/src/jsapi.h | 4 + js/src/shell/js.cpp | 177 +++++++++++++++++++++++--------------------- 3 files changed, 106 insertions(+), 86 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 55347eceb30e..36e2a758291f 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4339,7 +4339,7 @@ JS::OwningCompileOptions::copy(JSContext *cx, const ReadOnlyCompileOptions &rhs) } bool -JS::OwningCompileOptions::setFileAndLine(JSContext *cx, const char *f, unsigned l) +JS::OwningCompileOptions::setFile(JSContext *cx, const char *f) { char *copy = nullptr; if (f) { @@ -4352,6 +4352,15 @@ JS::OwningCompileOptions::setFileAndLine(JSContext *cx, const char *f, unsigned js_free(const_cast(filename_)); filename_ = copy; + return true; +} + +bool +JS::OwningCompileOptions::setFileAndLine(JSContext *cx, const char *f, unsigned l) +{ + if (!setFile(cx, f)) + return false; + lineno = l; return true; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 1674f8312d2a..fa1c939212ee 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3549,10 +3549,12 @@ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions bool copy(JSContext *cx, const ReadOnlyCompileOptions &rhs); /* These setters make copies of their string arguments, and are fallible. */ + bool setFile(JSContext *cx, const char *f); bool setFileAndLine(JSContext *cx, const char *f, unsigned l); bool setSourceMapURL(JSContext *cx, const jschar *s); /* These setters are infallible, and can be chained. */ + OwningCompileOptions &setLine(unsigned l) { lineno = l; return *this; } OwningCompileOptions &setElement(JSObject *e) { elementRoot = e; return *this; } OwningCompileOptions &setElementProperty(JSString *p) { elementPropertyRoot = p; return *this; } OwningCompileOptions &setPrincipals(JSPrincipals *p) { @@ -3614,6 +3616,8 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti JSObject *element() const MOZ_OVERRIDE { return elementRoot; } JSString *elementProperty() const MOZ_OVERRIDE { return elementPropertyRoot; } + CompileOptions &setFile(const char *f) { filename_ = f; return *this; } + CompileOptions &setLine(unsigned l) { lineno = l; return *this; } CompileOptions &setFileAndLine(const char *f, unsigned l) { filename_ = f; lineno = l; return *this; } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index e627151841ef..12c44750f326 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -765,6 +765,87 @@ LoadScriptRelativeToScript(JSContext *cx, unsigned argc, jsval *vp) return LoadScript(cx, argc, vp, true); } +// Populate |options| with the options given by |opts|'s properties. If we +// need to convert a filename to a C string, let fileNameBytes own the +// bytes. +static bool +ParseCompileOptions(JSContext *cx, CompileOptions &options, HandleObject opts, + JSAutoByteString &fileNameBytes) +{ + RootedValue v(cx); + RootedString s(cx); + + if (!JS_GetProperty(cx, opts, "compileAndGo", &v)) + return false; + if (!v.isUndefined()) + options.setCompileAndGo(ToBoolean(v)); + + if (!JS_GetProperty(cx, opts, "noScriptRval", &v)) + return false; + if (!v.isUndefined()) + options.setNoScriptRval(ToBoolean(v)); + + if (!JS_GetProperty(cx, opts, "fileName", &v)) + return false; + if (v.isNull()) { + options.setFile(nullptr); + } else if (!v.isUndefined()) { + s = ToString(cx, v); + if (!s) + return false; + char *fileName = fileNameBytes.encodeLatin1(cx, s); + if (!fileName) + return false; + options.setFile(fileName); + } + + if (!JS_GetProperty(cx, opts, "element", &v)) + return false; + if (v.isObject()) + options.setElement(&v.toObject()); + + if (!JS_GetProperty(cx, opts, "elementProperty", &v)) + return false; + if (!v.isUndefined()) { + s = ToString(cx, v); + if (!s) + return false; + options.setElementProperty(s); + } + + if (!JS_GetProperty(cx, opts, "lineNumber", &v)) + return false; + if (!v.isUndefined()) { + uint32_t u; + if (!ToUint32(cx, v, &u)) + return false; + options.setLine(u); + } + + if (!JS_GetProperty(cx, opts, "sourcePolicy", &v)) + return false; + if (!v.isUndefined()) { + JSString *s = ToString(cx, v); + if (!s) + return false; + char *policy = JS_EncodeStringToUTF8(cx, s); + if (!policy) + return false; + if (strcmp(policy, "NO_SOURCE") == 0) { + options.setSourcePolicy(CompileOptions::NO_SOURCE); + } else if (strcmp(policy, "LAZY_SOURCE") == 0) { + options.setSourcePolicy(CompileOptions::LAZY_SOURCE); + } else if (strcmp(policy, "SAVE_SOURCE") == 0) { + options.setSourcePolicy(CompileOptions::SAVE_SOURCE); + } else { + JS_ReportError(cx, "bad 'sourcePolicy' option: '%s'", policy); + return false; + } + } + + return true; +} + class AutoNewContext { private: @@ -849,21 +930,17 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp) return false; } - bool newContext = false; - bool compileAndGo = true; - bool noScriptRval = false; - const char *fileName = "@evaluate"; - RootedObject element(cx); - RootedString elementProperty(cx); + CompileOptions options(cx); JSAutoByteString fileNameBytes; + bool newContext = false; RootedString displayURL(cx); RootedString sourceMapURL(cx); - unsigned lineNumber = 1; RootedObject global(cx, nullptr); bool catchTermination = false; bool saveFrameChain = false; RootedObject callerGlobal(cx, cx->global()); - CompileOptions::SourcePolicy sourcePolicy = CompileOptions::SAVE_SOURCE; + + options.setFileAndLine("@evaluate", 1); global = JS_GetGlobalForObject(cx, &args.callee()); if (!global) @@ -873,47 +950,14 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp) RootedObject opts(cx, &args[1].toObject()); RootedValue v(cx); + if (!ParseCompileOptions(cx, options, opts, fileNameBytes)) + return false; + if (!JS_GetProperty(cx, opts, "newContext", &v)) return false; if (!v.isUndefined()) newContext = ToBoolean(v); - if (!JS_GetProperty(cx, opts, "compileAndGo", &v)) - return false; - if (!v.isUndefined()) - compileAndGo = ToBoolean(v); - - if (!JS_GetProperty(cx, opts, "noScriptRval", &v)) - return false; - if (!v.isUndefined()) - noScriptRval = ToBoolean(v); - - if (!JS_GetProperty(cx, opts, "fileName", &v)) - return false; - if (v.isNull()) { - fileName = nullptr; - } else if (!v.isUndefined()) { - JSString *s = ToString(cx, v); - if (!s) - return false; - fileName = fileNameBytes.encodeLatin1(cx, s); - if (!fileName) - return false; - } - - if (!JS_GetProperty(cx, opts, "element", &v)) - return false; - if (v.isObject()) - element = &v.toObject(); - - if (!JS_GetProperty(cx, opts, "elementProperty", &v)) - return false; - if (!v.isUndefined()) { - elementProperty = ToString(cx, v); - if (!elementProperty) - return false; - } - if (!JS_GetProperty(cx, opts, "displayURL", &v)) return false; if (!v.isUndefined()) { @@ -930,15 +974,6 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp) return false; } - if (!JS_GetProperty(cx, opts, "lineNumber", &v)) - return false; - if (!v.isUndefined()) { - uint32_t u; - if (!ToUint32(cx, v, &u)) - return false; - lineNumber = u; - } - if (!JS_GetProperty(cx, opts, "global", &v)) return false; if (!v.isUndefined()) { @@ -963,28 +998,6 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp) return false; if (!v.isUndefined()) saveFrameChain = ToBoolean(v); - - if (!JS_GetProperty(cx, opts, "sourcePolicy", &v)) - return false; - if (!v.isUndefined()) { - JSString *s = ToString(cx, v); - if (!s) - return false; - char *policy = JS_EncodeStringToUTF8(cx, s); - if (!policy) - return false; - if (strcmp(policy, "NO_SOURCE") == 0) { - sourcePolicy = CompileOptions::NO_SOURCE; - } else if (strcmp(policy, "LAZY_SOURCE") == 0) { - sourcePolicy = CompileOptions::LAZY_SOURCE; - } else if (strcmp(policy, "SAVE_SOURCE") == 0) { - sourcePolicy = CompileOptions::SAVE_SOURCE; - } else { - JS_ReportError(cx, "bad 'sourcePolicy' option passed to 'evaluate': '%s'", - policy); - return false; - } - } } RootedString code(cx, args[0].toString()); @@ -1009,18 +1022,12 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp) JSAutoCompartment ac(cx, global); RootedScript script(cx); + if (!options.wrap(cx, cx->compartment())) + return false; + { JS::AutoSaveContextOptions asco(cx); - JS::ContextOptionsRef(cx).setNoScriptRval(noScriptRval); - - CompileOptions options(cx); - options.setFileAndLine(fileName, lineNumber) - .setElement(element) - .setElementProperty(elementProperty) - .setSourcePolicy(sourcePolicy) - .setCompileAndGo(compileAndGo); - if (!options.wrap(cx, cx->compartment())) - return false; + JS::ContextOptionsRef(cx).setNoScriptRval(options.noScriptRval); script = JS::Compile(cx, global, options, codeChars, codeLength); if (!script)