зеркало из https://github.com/mozilla/gecko-dev.git
Bug 990353 - Make the decision to discard source entirely per-global, rather than per-script. r=luke
This is effectively a policy decision based on the kind of code we expect to be running somewhere. This is in contrast to lazy source, which is often a practical per-script consideration of whether or not we can retrieve the source if requested. More importantly, tracking this information on the global is much easier to get right than tracking it on the script.
This commit is contained in:
Родитель
2fe6cc7db5
Коммит
f8ee5952ab
|
@ -2656,8 +2656,7 @@ nsXULPrototypeScript::Compile(const char16_t* aText,
|
|||
// If the script was inline, tell the JS parser to save source for
|
||||
// Function.prototype.toSource(). If it's out of line, we retrieve the
|
||||
// source from the files on demand.
|
||||
options.setSourcePolicy(mOutOfLine ? JS::CompileOptions::LAZY_SOURCE
|
||||
: JS::CompileOptions::SAVE_SOURCE);
|
||||
options.setSourceIsLazy(mOutOfLine);
|
||||
JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
|
||||
if (scope) {
|
||||
JS::ExposeObjectToActiveJS(scope);
|
||||
|
|
|
@ -146,7 +146,8 @@ CanLazilyParse(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
|
|||
{
|
||||
return options.canLazilyParse &&
|
||||
options.compileAndGo &&
|
||||
options.sourcePolicy == CompileOptions::SAVE_SOURCE &&
|
||||
!cx->compartment()->options().discardSource() &&
|
||||
!options.sourceIsLazy &&
|
||||
!(cx->compartment()->debugMode() &&
|
||||
cx->compartment()->runtimeFromAnyThread()->debugHooks.newScriptHook);
|
||||
}
|
||||
|
@ -212,7 +213,7 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
|
|||
|
||||
if (!CheckLength(cx, length))
|
||||
return nullptr;
|
||||
JS_ASSERT_IF(staticLevel != 0, options.sourcePolicy != CompileOptions::LAZY_SOURCE);
|
||||
JS_ASSERT_IF(staticLevel != 0, !options.sourceIsLazy);
|
||||
|
||||
RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
|
||||
if (!sourceObject)
|
||||
|
@ -223,16 +224,11 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
|
|||
SourceCompressionTask mysct(cx);
|
||||
SourceCompressionTask *sct = extraSct ? extraSct : &mysct;
|
||||
|
||||
switch (options.sourcePolicy) {
|
||||
case CompileOptions::SAVE_SOURCE:
|
||||
if (!ss->setSourceCopy(cx, chars, length, false, sct))
|
||||
return nullptr;
|
||||
break;
|
||||
case CompileOptions::LAZY_SOURCE:
|
||||
if (!cx->compartment()->options().discardSource()) {
|
||||
if (options.sourceIsLazy)
|
||||
ss->setSourceRetrievable();
|
||||
break;
|
||||
case CompileOptions::NO_SOURCE:
|
||||
break;
|
||||
else if (!ss->setSourceCopy(cx, chars, length, false, sct))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool canLazilyParse = CanLazilyParse(cx, options);
|
||||
|
@ -517,8 +513,8 @@ CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp
|
|||
ScriptSource *ss = sourceObject->source();
|
||||
|
||||
SourceCompressionTask sct(cx);
|
||||
JS_ASSERT(options.sourcePolicy != CompileOptions::LAZY_SOURCE);
|
||||
if (options.sourcePolicy == CompileOptions::SAVE_SOURCE) {
|
||||
JS_ASSERT(!options.sourceIsLazy);
|
||||
if (!cx->compartment()->options().discardSource()) {
|
||||
if (!ss->setSourceCopy(cx, chars, length, true, &sct))
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -35,20 +35,20 @@ withSourceHook(function (url) {
|
|||
}, function () {
|
||||
log += 'I';
|
||||
return evaluate('(function inner() { 2; })',
|
||||
{ fileName: 'inner', sourcePolicy: 'LAZY_SOURCE' })
|
||||
{ fileName: 'inner', sourceIsLazy: true })
|
||||
.toSource();
|
||||
}),
|
||||
'(function inner() { 1; })');
|
||||
// Verify that the source hook that throws has been reinstated.
|
||||
evaluate('(function middle() { })',
|
||||
{ fileName: 'middle', sourcePolicy: 'LAZY_SOURCE' })
|
||||
{ fileName: 'middle', sourceIsLazy: true })
|
||||
.toSource();
|
||||
});
|
||||
}, 'borborygmus');
|
||||
|
||||
// Verify that the outermost source hook has been restored.
|
||||
assertEq(evaluate('(function outer() { 4; })',
|
||||
{ fileName: 'outer', sourcePolicy: 'LAZY_SOURCE' })
|
||||
{ fileName: 'outer', sourceIsLazy: true })
|
||||
.toSource(),
|
||||
'(function outer() { 3; })');
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@ function test(source) {
|
|||
}
|
||||
|
||||
g.evaluate(source, { fileName: "BanalBivalve.jsm",
|
||||
sourcePolicy: "LAZY_SOURCE"});
|
||||
sourceIsLazy: true });
|
||||
});
|
||||
|
||||
assertEq(log, 'ds');
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
BEGIN_TEST(testBug795104)
|
||||
{
|
||||
JS::CompileOptions opts(cx);
|
||||
opts.setSourcePolicy(JS::CompileOptions::NO_SOURCE);
|
||||
JS::CompartmentOptionsRef(cx->compartment()).setDiscardSource(true);
|
||||
const size_t strLen = 60002;
|
||||
char *s = static_cast<char *>(JS_malloc(cx, strLen));
|
||||
CHECK(s);
|
||||
|
|
|
@ -2479,6 +2479,12 @@ JS::CompartmentOptionsRef(JSCompartment *compartment)
|
|||
return compartment->options();
|
||||
}
|
||||
|
||||
JS::CompartmentOptions &
|
||||
JS::CompartmentOptionsRef(JSObject *obj)
|
||||
{
|
||||
return obj->compartment()->options();
|
||||
}
|
||||
|
||||
JS::CompartmentOptions &
|
||||
JS::CompartmentOptionsRef(JSContext *cx)
|
||||
{
|
||||
|
@ -4348,7 +4354,7 @@ JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions &rhs)
|
|||
asmJSOption = rhs.asmJSOption;
|
||||
forceAsync = rhs.forceAsync;
|
||||
installedFile = rhs.installedFile;
|
||||
sourcePolicy = rhs.sourcePolicy;
|
||||
sourceIsLazy = rhs.sourceIsLazy;
|
||||
introductionType = rhs.introductionType;
|
||||
introductionLineno = rhs.introductionLineno;
|
||||
introductionOffset = rhs.introductionOffset;
|
||||
|
|
|
@ -2549,6 +2549,7 @@ class JS_PUBLIC_API(CompartmentOptions)
|
|||
: version_(JSVERSION_UNKNOWN)
|
||||
, invisibleToDebugger_(false)
|
||||
, mergeable_(false)
|
||||
, discardSource_(false)
|
||||
, traceGlobal_(nullptr)
|
||||
, singletonsAsTemplates_(true)
|
||||
{
|
||||
|
@ -2582,6 +2583,15 @@ class JS_PUBLIC_API(CompartmentOptions)
|
|||
return *this;
|
||||
}
|
||||
|
||||
// For certain globals, we know enough about the code that will run in them
|
||||
// that we can discard script source entirely.
|
||||
bool discardSource() const { return discardSource_; }
|
||||
CompartmentOptions &setDiscardSource(bool flag) {
|
||||
discardSource_ = flag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool cloneSingletons(JSContext *cx) const;
|
||||
Override &cloneSingletonsOverride() { return cloneSingletonsOverride_; }
|
||||
|
||||
|
@ -2612,6 +2622,7 @@ class JS_PUBLIC_API(CompartmentOptions)
|
|||
JSVersion version_;
|
||||
bool invisibleToDebugger_;
|
||||
bool mergeable_;
|
||||
bool discardSource_;
|
||||
Override cloneSingletonsOverride_;
|
||||
union {
|
||||
ZoneSpecifier spec;
|
||||
|
@ -2628,6 +2639,9 @@ class JS_PUBLIC_API(CompartmentOptions)
|
|||
JS_PUBLIC_API(CompartmentOptions &)
|
||||
CompartmentOptionsRef(JSCompartment *compartment);
|
||||
|
||||
JS_PUBLIC_API(CompartmentOptions &)
|
||||
CompartmentOptionsRef(JSObject *obj);
|
||||
|
||||
JS_PUBLIC_API(CompartmentOptions &)
|
||||
CompartmentOptionsRef(JSContext *cx);
|
||||
|
||||
|
@ -3402,7 +3416,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
|
|||
asmJSOption(false),
|
||||
forceAsync(false),
|
||||
installedFile(false),
|
||||
sourcePolicy(SAVE_SOURCE),
|
||||
sourceIsLazy(false),
|
||||
introductionType(nullptr),
|
||||
introductionLineno(0),
|
||||
introductionOffset(0),
|
||||
|
@ -3442,11 +3456,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
|
|||
bool asmJSOption;
|
||||
bool forceAsync;
|
||||
bool installedFile; // 'true' iff pre-compiling js file in packaged app
|
||||
enum SourcePolicy {
|
||||
NO_SOURCE,
|
||||
LAZY_SOURCE,
|
||||
SAVE_SOURCE
|
||||
} sourcePolicy;
|
||||
bool sourceIsLazy;
|
||||
|
||||
// |introductionType| is a statically allocated C string:
|
||||
// one of "eval", "Function", or "GeneratorFunction".
|
||||
|
@ -3538,7 +3548,7 @@ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions
|
|||
OwningCompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
|
||||
OwningCompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; }
|
||||
OwningCompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; }
|
||||
OwningCompileOptions &setSourcePolicy(SourcePolicy sp) { sourcePolicy = sp; return *this; }
|
||||
OwningCompileOptions &setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; }
|
||||
OwningCompileOptions &setIntroductionType(const char *t) { introductionType = t; return *this; }
|
||||
bool setIntroductionInfo(JSContext *cx, const char *introducerFn, const char *intro,
|
||||
unsigned line, JSScript *script, uint32_t offset)
|
||||
|
@ -3624,7 +3634,7 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti
|
|||
CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
|
||||
CompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; }
|
||||
CompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; }
|
||||
CompileOptions &setSourcePolicy(SourcePolicy sp) { sourcePolicy = sp; return *this; }
|
||||
CompileOptions &setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; }
|
||||
CompileOptions &setIntroductionType(const char *t) { introductionType = t; return *this; }
|
||||
CompileOptions &setIntroductionInfo(const char *introducerFn, const char *intro,
|
||||
unsigned line, JSScript *script, uint32_t offset)
|
||||
|
|
|
@ -383,13 +383,13 @@ proxy_Slice(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end,
|
|||
/*
|
||||
* A class of objects that return source code on demand.
|
||||
*
|
||||
* When code is compiled with CompileOptions::LAZY_SOURCE, SpiderMonkey
|
||||
* doesn't retain the source code (and doesn't do lazy bytecode
|
||||
* generation). If we ever need the source code, say, in response to a call
|
||||
* to Function.prototype.toSource or Debugger.Source.prototype.text, then
|
||||
* we call the 'load' member function of the instance of this class that
|
||||
* has hopefully been registered with the runtime, passing the code's URL,
|
||||
* and hope that it will be able to find the source.
|
||||
* When code is compiled with setSourceIsLazy(true), SpiderMonkey doesn't
|
||||
* retain the source code (and doesn't do lazy bytecode generation). If we ever
|
||||
* need the source code, say, in response to a call to Function.prototype.
|
||||
* toSource or Debugger.Source.prototype.text, then we call the 'load' member
|
||||
* function of the instance of this class that has hopefully been registered
|
||||
* with the runtime, passing the code's URL, and hope that it will be able to
|
||||
* find the source.
|
||||
*/
|
||||
class SourceHook {
|
||||
public:
|
||||
|
@ -404,7 +404,7 @@ class SourceHook {
|
|||
};
|
||||
|
||||
/*
|
||||
* Have |rt| use |hook| to retrieve LAZY_SOURCE source code. See the
|
||||
* Have |rt| use |hook| to retrieve lazily-retrieved source code. See the
|
||||
* comments for SourceHook. The runtime takes ownership of the hook, and
|
||||
* will delete it when the runtime itself is deleted, or when a new hook is
|
||||
* set.
|
||||
|
|
|
@ -866,28 +866,10 @@ ParseCompileOptions(JSContext *cx, CompileOptions &options, HandleObject opts,
|
|||
options.setLine(u);
|
||||
}
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "sourcePolicy", &v))
|
||||
if (!JS_GetProperty(cx, opts, "sourceIsLazy", &v))
|
||||
return false;
|
||||
if (!v.isUndefined()) {
|
||||
RootedString s(cx, ToString(cx, v));
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
JSAutoByteString bytes;
|
||||
char *policy = bytes.encodeUtf8(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;
|
||||
}
|
||||
}
|
||||
if (v.isBoolean())
|
||||
options.setSourceIsLazy(v.toBoolean());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3637,7 +3619,7 @@ OffThreadCompileScript(JSContext *cx, unsigned argc, jsval *vp)
|
|||
|
||||
// These option settings must override whatever the caller requested.
|
||||
options.setCompileAndGo(true)
|
||||
.setSourcePolicy(CompileOptions::SAVE_SOURCE);
|
||||
.setSourceIsLazy(false);
|
||||
|
||||
// We assume the caller wants caching if at all possible, ignoring
|
||||
// heuristics that make sense for a real browser.
|
||||
|
@ -4390,9 +4372,9 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
|
|||
" provide that as the code's source map URL. If omitted, attach no\n"
|
||||
" source map URL to the code (although the code may provide one itself,\n"
|
||||
" via a //#sourceMappingURL comment).\n"
|
||||
" sourcePolicy: if present, the value converted to a string must be either\n"
|
||||
" 'NO_SOURCE', 'LAZY_SOURCE', or 'SAVE_SOURCE'; use the given source\n"
|
||||
" retention policy for this compilation.\n"
|
||||
" sourceIsLazy: if present and true, indicates that, after compilation, \n"
|
||||
"script source should not be cached by the JS engine and should be \n"
|
||||
"lazily loaded from the embedding as-needed.\n"
|
||||
" loadBytecode: if true, and if the source is a CacheEntryObject,\n"
|
||||
" the bytecode would be loaded and decoded from the cache entry instead\n"
|
||||
" of being parsed, then it would be executed as usual.\n"
|
||||
|
|
|
@ -904,7 +904,6 @@ js::FillSelfHostingCompileOptions(CompileOptions &options)
|
|||
options.setFileAndLine("self-hosted", 1);
|
||||
options.setSelfHostingMode(true);
|
||||
options.setCanLazilyParse(false);
|
||||
options.setSourcePolicy(CompileOptions::NO_SOURCE);
|
||||
options.setVersion(JSVERSION_LATEST);
|
||||
options.werrorOption = true;
|
||||
options.strictOption = true;
|
||||
|
@ -934,8 +933,11 @@ JSRuntime::initSelfHosting(JSContext *cx)
|
|||
RootedObject savedGlobal(cx, receivesDefaultObject
|
||||
? js::DefaultObjectForContextOrNull(cx)
|
||||
: nullptr);
|
||||
JS::CompartmentOptions compartmentOptions;
|
||||
compartmentOptions.setDiscardSource(true);
|
||||
if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class,
|
||||
nullptr, JS::DontFireOnNewGlobalHook)))
|
||||
nullptr, JS::DontFireOnNewGlobalHook,
|
||||
compartmentOptions)))
|
||||
return false;
|
||||
JSAutoCompartment ac(cx, selfHostingGlobal_);
|
||||
if (receivesDefaultObject)
|
||||
|
|
|
@ -814,13 +814,16 @@ mozJSComponentLoader::ObjectForLocation(nsIFile *aComponentFile,
|
|||
if (aPropagateExceptions)
|
||||
ContextOptionsRef(cx).setDontReportUncaught(true);
|
||||
|
||||
// Note - if mReuseLoaderGlobal is true, then we can't do lazy source,
|
||||
// because we compile things as functions (rather than script), and lazy
|
||||
// source isn't supported in that configuration. That's ok though,
|
||||
// because we only do mReuseLoaderGlobal on b2g, where we invoke
|
||||
// setDiscardSource(true) on the entire global.
|
||||
CompileOptions options(cx);
|
||||
options.setNoScriptRval(mReuseLoaderGlobal ? false : true)
|
||||
.setVersion(JSVERSION_LATEST)
|
||||
.setFileAndLine(nativePath.get(), 1)
|
||||
.setSourcePolicy(mReuseLoaderGlobal ?
|
||||
CompileOptions::NO_SOURCE :
|
||||
CompileOptions::LAZY_SOURCE);
|
||||
.setSourceIsLazy(!mReuseLoaderGlobal);
|
||||
|
||||
if (realFile) {
|
||||
#ifdef HAVE_PR_MEMMAP
|
||||
|
|
|
@ -164,10 +164,10 @@ mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObj
|
|||
script.Length());
|
||||
}
|
||||
} else {
|
||||
// We only use LAZY_SOURCE when no special encoding is specified because
|
||||
// We only use lazy source when no special encoding is specified because
|
||||
// the lazy source loader doesn't know the encoding.
|
||||
if (!reuseGlobal) {
|
||||
options.setSourcePolicy(JS::CompileOptions::LAZY_SOURCE);
|
||||
options.setSourceIsLazy(true);
|
||||
*scriptp = JS::Compile(cx, target_obj, options, buf.get(), len);
|
||||
} else {
|
||||
*functionp = JS::CompileFunction(cx, target_obj, options,
|
||||
|
|
Загрузка…
Ссылка в новой задаче