Bug 749371 - Remove now-unnecessary JS_ClearScope defense (r=bhackett)

This commit is contained in:
Luke Wagner 2012-08-27 09:13:44 -07:00
parent 3595a4cdb6
commit 872a0e6b97
12 changed files with 18 additions and 152 deletions

View File

@ -4193,7 +4193,7 @@ struct JSClass {
* with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
* prevously allowed, but is now an ES5 violation and thus unsupported. * prevously allowed, but is now an ES5 violation and thus unsupported.
*/ */
#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 24) #define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 23)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \ #define JSCLASS_GLOBAL_FLAGS \

View File

@ -1135,7 +1135,7 @@ UnknownPropertyAccess(JSScript *script, Type type)
{ {
return type.isUnknown() return type.isUnknown()
|| type.isAnyObject() || type.isAnyObject()
|| (!type.isObject() && !script->hasGlobal()); || (!type.isObject() && !script->compileAndGo);
} }
template <PropertyAccessKind access> template <PropertyAccessKind access>
@ -1448,7 +1448,7 @@ TypeConstraintTransformThis::newType(JSContext *cx, TypeSet *source, Type type)
* Note: if |this| is null or undefined, the pushed value is the outer window. We * Note: if |this| is null or undefined, the pushed value is the outer window. We
* can't use script->getGlobalType() here because it refers to the inner window. * can't use script->getGlobalType() here because it refers to the inner window.
*/ */
if (!script->hasGlobal() || if (!script->compileAndGo ||
type.isPrimitive(JSVAL_TYPE_NULL) || type.isPrimitive(JSVAL_TYPE_NULL) ||
type.isPrimitive(JSVAL_TYPE_UNDEFINED)) { type.isPrimitive(JSVAL_TYPE_UNDEFINED)) {
target->addType(cx, Type::UnknownType()); target->addType(cx, Type::UnknownType());
@ -2141,7 +2141,7 @@ types::UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc,
bool bool
types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script) types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script)
{ {
if (!cx->typeInferenceEnabled() || !script->hasGlobal()) if (!cx->typeInferenceEnabled() || !script->compileAndGo)
return true; return true;
JSObject *proto = script->global().getOrCreateArrayPrototype(cx); JSObject *proto = script->global().getOrCreateArrayPrototype(cx);
@ -3320,7 +3320,7 @@ CheckNextTest(jsbytecode *pc)
static inline TypeObject * static inline TypeObject *
GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc) GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
{ {
if (!script->hasGlobal()) if (!script->compileAndGo)
return NULL; return NULL;
JSOp op = JSOp(*pc); JSOp op = JSOp(*pc);
@ -3503,7 +3503,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
break; break;
case JSOP_REGEXP: case JSOP_REGEXP:
if (script->hasGlobal()) { if (script->compileAndGo) {
TypeObject *object = TypeScript::StandardType(cx, script, JSProto_RegExp); TypeObject *object = TypeScript::StandardType(cx, script, JSProto_RegExp);
if (!object) if (!object)
return false; return false;
@ -3715,7 +3715,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_REST: { case JSOP_REST: {
StackTypeSet *types = script->analysis()->bytecodeTypes(pc); StackTypeSet *types = script->analysis()->bytecodeTypes(pc);
if (script->hasGlobal()) { if (script->compileAndGo) {
TypeObject *rest = TypeScript::InitObject(cx, script, pc, JSProto_Array); TypeObject *rest = TypeScript::InitObject(cx, script, pc, JSProto_Array);
if (!rest) if (!rest)
return false; return false;
@ -3850,7 +3850,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
res = &pushed[0]; res = &pushed[0];
if (res) { if (res) {
if (script->hasGlobal() && !UseNewTypeForClone(obj->toFunction())) if (script->compileAndGo && !UseNewTypeForClone(obj->toFunction()))
res->addType(cx, Type::ObjectType(obj)); res->addType(cx, Type::ObjectType(obj));
else else
res->addType(cx, Type::UnknownType()); res->addType(cx, Type::UnknownType());
@ -3916,7 +3916,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
} }
TypeObject *initializer = GetInitializerType(cx, script, pc); TypeObject *initializer = GetInitializerType(cx, script, pc);
if (script->hasGlobal()) { if (script->compileAndGo) {
if (!initializer) if (!initializer)
return false; return false;
types->addType(cx, Type::ObjectType(initializer)); types->addType(cx, Type::ObjectType(initializer));
@ -4100,7 +4100,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_GENERATOR: case JSOP_GENERATOR:
if (script->function()) { if (script->function()) {
if (script->hasGlobal()) { if (script->compileAndGo) {
JSObject *proto = script->global().getOrCreateGeneratorPrototype(cx); JSObject *proto = script->global().getOrCreateGeneratorPrototype(cx);
if (!proto) if (!proto)
return false; return false;
@ -4153,7 +4153,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_CALLEE: { case JSOP_CALLEE: {
JSFunction *fun = script->function(); JSFunction *fun = script->function();
if (script->hasGlobal() && !UseNewTypeForClone(fun)) if (script->compileAndGo && !UseNewTypeForClone(fun))
pushed[0].addType(cx, Type::ObjectType(fun)); pushed[0].addType(cx, Type::ObjectType(fun));
else else
pushed[0].addType(cx, Type::UnknownType()); pushed[0].addType(cx, Type::UnknownType());
@ -4179,17 +4179,6 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
return; return;
} }
/*
* Refuse to analyze the types in a script which is compileAndGo but is
* running against a global with a cleared scope. Per GlobalObject::clear,
* we won't be running anymore compileAndGo code against the global
* (moreover, after clearing our analysis results will be wrong for the
* script and trying to reanalyze here can cause reentrance problems if we
* try to reinitialize standard classes that were cleared).
*/
if (script->hasClearedGlobal())
return;
if (!ranSSA()) { if (!ranSSA()) {
analyzeSSA(cx); analyzeSSA(cx);
if (failed()) if (failed())
@ -4414,9 +4403,6 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO
return false; return false;
} }
if (script->hasClearedGlobal())
return false;
ScriptAnalysis *analysis = script->analysis(); ScriptAnalysis *analysis = script->analysis();
/* /*

View File

@ -683,7 +683,7 @@ TypeScript::InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoK
/* :XXX: Limit script->length so we don't need to check the offset up front? */ /* :XXX: Limit script->length so we don't need to check the offset up front? */
uint32_t offset = pc - script->code; uint32_t offset = pc - script->code;
if (!cx->typeInferenceEnabled() || !script->hasGlobal() || offset >= AllocationSiteKey::OFFSET_LIMIT) if (!cx->typeInferenceEnabled() || !script->compileAndGo || offset >= AllocationSiteKey::OFFSET_LIMIT)
return GetTypeNewObject(cx, kind); return GetTypeNewObject(cx, kind);
AllocationSiteKey key; AllocationSiteKey key;

View File

@ -270,14 +270,6 @@ js::RunScript(JSContext *cx, JSScript *script, StackFrame *fp)
JS_CHECK_RECURSION(cx, return false); JS_CHECK_RECURSION(cx, return false);
/* FIXME: Once bug 470510 is fixed, make this an assert. */
if (script->compileAndGo) {
if (fp->global().isCleared()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CLEARED_SCOPE);
return false;
}
}
#ifdef DEBUG #ifdef DEBUG
struct CheckStackBalance { struct CheckStackBalance {
JSContext *cx; JSContext *cx;
@ -2424,16 +2416,9 @@ BEGIN_CASE(JSOP_FUNCALL)
goto error; goto error;
InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE; InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
bool newType = cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc); bool newType = cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc);
JSScript *newScript = fun->script(); JSScript *newScript = fun->script();
if (newScript->compileAndGo && newScript->hasClearedGlobal()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CLEARED_SCOPE);
goto error;
}
if (!cx->stack.pushInlineFrame(cx, regs, args, *fun, newScript, initial)) if (!cx->stack.pushInlineFrame(cx, regs, args, *fun, newScript, initial))
goto error; goto error;

View File

@ -580,9 +580,6 @@ struct JSScript : public js::gc::Cell
inline void clearPropertyReadTypes(); inline void clearPropertyReadTypes();
inline bool hasGlobal() const;
inline bool hasClearedGlobal() const;
inline js::GlobalObject &global() const; inline js::GlobalObject &global() const;
/* See StaticScopeIter comment. */ /* See StaticScopeIter comment. */

View File

@ -120,17 +120,6 @@ JSScript::isEmpty() const
return JSOp(*pc) == JSOP_STOP; return JSOp(*pc) == JSOP_STOP;
} }
inline bool
JSScript::hasGlobal() const
{
/*
* Make sure that we don't try to query information about global objects
* which have had their scopes cleared. compileAndGo code should not run
* anymore against such globals.
*/
return compileAndGo && !global().isCleared();
}
inline js::GlobalObject & inline js::GlobalObject &
JSScript::global() const JSScript::global() const
{ {
@ -141,13 +130,6 @@ JSScript::global() const
return *compartment()->maybeGlobal(); return *compartment()->maybeGlobal();
} }
inline bool
JSScript::hasClearedGlobal() const
{
JS_ASSERT(types);
return global().isCleared();
}
#ifdef JS_METHODJIT #ifdef JS_METHODJIT
inline bool inline bool
JSScript::ensureHasMJITInfo(JSContext *cx) JSScript::ensureHasMJITInfo(JSContext *cx)

View File

@ -59,7 +59,7 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript,
isConstructing(isConstructing), isConstructing(isConstructing),
outerChunk(outerJIT()->chunkDescriptor(chunkIndex)), outerChunk(outerJIT()->chunkDescriptor(chunkIndex)),
ssa(cx, outerScript), ssa(cx, outerScript),
globalObj(cx, outerScript->hasGlobal() ? &outerScript->global() : NULL), globalObj(cx, outerScript->compileAndGo ? &outerScript->global() : NULL),
globalSlots(globalObj ? globalObj->getRawSlots() : NULL), globalSlots(globalObj ? globalObj->getRawSlots() : NULL),
sps(&cx->runtime->spsProfiler, &script, &PC), sps(&cx->runtime->spsProfiler, &script, &PC),
masm(&sps), masm(&sps),
@ -134,11 +134,6 @@ mjit::Compiler::compile()
CompileStatus CompileStatus
mjit::Compiler::checkAnalysis(HandleScript script) mjit::Compiler::checkAnalysis(HandleScript script)
{ {
if (script->hasClearedGlobal()) {
JaegerSpew(JSpew_Abort, "script has a cleared global\n");
return Compile_Abort;
}
if (!script->ensureRanAnalysis(cx)) if (!script->ensureRanAnalysis(cx))
return Compile_Error; return Compile_Error;
@ -193,7 +188,7 @@ mjit::Compiler::scanInlineCalls(uint32_t index, uint32_t depth)
ScriptAnalysis *analysis = script->analysis(); ScriptAnalysis *analysis = script->analysis();
/* Don't inline from functions which could have a non-global scope object. */ /* Don't inline from functions which could have a non-global scope object. */
if (!script->hasGlobal() || if (!script->compileAndGo ||
&script->global() != globalObj || &script->global() != globalObj ||
(script->function() && script->function()->getParent() != globalObj) || (script->function() && script->function()->getParent() != globalObj) ||
(script->function() && script->function()->isHeavyweight()) || (script->function() && script->function()->isHeavyweight()) ||

View File

@ -881,7 +881,7 @@ class GetPropCompiler : public PICStubCompiler
LookupStatus generateStringPropertyStub() LookupStatus generateStringPropertyStub()
{ {
if (!f.fp()->script()->hasGlobal()) if (!f.fp()->script()->compileAndGo)
return disable("String.prototype without compile-and-go global"); return disable("String.prototype without compile-and-go global");
RecompilationMonitor monitor(f.cx); RecompilationMonitor monitor(f.cx);

View File

@ -2092,7 +2092,7 @@ class Debugger::ScriptQuery {
for (CompartmentSet::Range r = compartments.all(); !r.empty(); r.popFront()) { for (CompartmentSet::Range r = compartments.all(); !r.empty(); r.popFront()) {
for (gc::CellIter i(r.front(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { for (gc::CellIter i(r.front(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>(); JSScript *script = i.get<JSScript>();
if (script->hasGlobal() && !script->isForEval()) { if (script->compileAndGo && !script->isForEval()) {
if (!consider(script, &script->global(), vector)) if (!consider(script, &script->global(), vector))
return false; return false;
} }

View File

@ -10,18 +10,6 @@
namespace js { namespace js {
inline void
GlobalObject::setFlags(int32_t flags)
{
setSlot(FLAGS, Int32Value(flags));
}
inline void
GlobalObject::initFlags(int32_t flags)
{
initSlot(FLAGS, Int32Value(flags));
}
inline void inline void
GlobalObject::setDetailsForKey(JSProtoKey key, JSObject *ctor, JSObject *proto) GlobalObject::setDetailsForKey(JSProtoKey key, JSObject *ctor, JSObject *proto)
{ {

View File

@ -488,9 +488,8 @@ GlobalObject::create(JSContext *cx, Class *clasp)
JSObject *res = RegExpStatics::create(cx, global); JSObject *res = RegExpStatics::create(cx, global);
if (!res) if (!res)
return NULL; return NULL;
global->initSlot(REGEXP_STATICS, ObjectValue(*res));
global->initFlags(0);
global->initSlot(REGEXP_STATICS, ObjectValue(*res));
return global; return global;
} }
@ -533,60 +532,6 @@ GlobalObject::initStandardClasses(JSContext *cx, Handle<GlobalObject*> global)
GlobalObject::initSetIteratorProto(cx, global); GlobalObject::initSetIteratorProto(cx, global);
} }
void
GlobalObject::clear(JSContext *cx)
{
for (int key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
setSlot(key, UndefinedValue());
/* Clear regexp statics. */
getRegExpStatics()->clear();
/* Clear the runtime-codegen-enabled cache. */
setSlot(RUNTIME_CODEGEN_ENABLED, UndefinedValue());
/*
* Clear all slots storing values in case throwing trying to execute a
* script for this global must reinitialize standard classes. See
* bug 470150.
*/
setSlot(BOOLEAN_VALUEOF, UndefinedValue());
setSlot(EVAL, UndefinedValue());
setSlot(CREATE_DATAVIEW_FOR_THIS, UndefinedValue());
setSlot(THROWTYPEERROR, UndefinedValue());
setSlot(INTRINSICS, UndefinedValue());
setSlot(PROTO_GETTER, UndefinedValue());
/*
* Mark global as cleared. If we try to execute any compile-and-go
* scripts from here on, we will throw.
*/
int32_t flags = getSlot(FLAGS).toInt32();
flags |= FLAGS_CLEARED;
setSlot(FLAGS, Int32Value(flags));
/*
* Reset the new object cache in the compartment, which assumes that
* prototypes cached on the global object are immutable.
*/
cx->runtime->newObjectCache.purge();
#ifdef JS_METHODJIT
/*
* Destroy compiled code for any scripts parented to this global. Call ICs
* can directly call scripts which have associated JIT code, and do so
* without checking whether the script's global has been cleared.
*/
for (gc::CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if (script->compileAndGo && script->hasMJITInfo() && script->hasClearedGlobal()) {
mjit::Recompiler::clearStackReferences(cx->runtime->defaultFreeOp(), script);
mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), script);
}
}
#endif
}
bool bool
GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx) GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx)
{ {

View File

@ -98,8 +98,7 @@ class GlobalObject : public JSObject
static const unsigned REGEXP_STATICS = SET_ITERATOR_PROTO + 1; static const unsigned REGEXP_STATICS = SET_ITERATOR_PROTO + 1;
static const unsigned FUNCTION_NS = REGEXP_STATICS + 1; static const unsigned FUNCTION_NS = REGEXP_STATICS + 1;
static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1; static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
static const unsigned FLAGS = RUNTIME_CODEGEN_ENABLED + 1; static const unsigned DEBUGGERS = RUNTIME_CODEGEN_ENABLED + 1;
static const unsigned DEBUGGERS = FLAGS + 1;
static const unsigned INTRINSICS = DEBUGGERS + 1; static const unsigned INTRINSICS = DEBUGGERS + 1;
/* Total reserved-slot count for global objects. */ /* Total reserved-slot count for global objects. */
@ -114,11 +113,6 @@ class GlobalObject : public JSObject
JS_STATIC_ASSERT(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS); JS_STATIC_ASSERT(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS);
} }
static const int32_t FLAGS_CLEARED = 0x1;
inline void setFlags(int32_t flags);
inline void initFlags(int32_t flags);
friend JSObject * friend JSObject *
::js_InitObjectClass(JSContext *cx, JSObject *obj); ::js_InitObjectClass(JSContext *cx, JSObject *obj);
friend JSObject * friend JSObject *
@ -413,12 +407,6 @@ class GlobalObject : public JSObject
return getSlot(PROTO_GETTER); return getSlot(PROTO_GETTER);
} }
void clear(JSContext *cx);
bool isCleared() const {
return getSlot(FLAGS).toInt32() & FLAGS_CLEARED;
}
bool isRuntimeCodeGenEnabled(JSContext *cx); bool isRuntimeCodeGenEnabled(JSContext *cx);
const Value &getOriginalEval() const { const Value &getOriginalEval() const {