Backed out changeset 08e63874f0b4 (bug 1179063) for crashes CLOSED TREE

This commit is contained in:
Wes Kocher 2015-08-19 14:18:46 -07:00
parent eb55cb6ee0
commit 8859650705
11 changed files with 147 additions and 110 deletions

View File

@ -110,6 +110,16 @@ struct frontend::LoopStmtInfo : public StmtInfoBCE
}
};
void
FunctionBox::switchStaticScopeToFunction()
{
if (staticScope_->is<StaticFunctionBoxScopeObject>()) {
MOZ_ASSERT(staticScope_->as<StaticFunctionBoxScopeObject>().functionBox() == this);
staticScope_ = function();
}
MOZ_ASSERT(staticScope_ == function());
}
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
Parser<FullParseHandler>* parser, SharedContext* sc,
HandleScript script, Handle<LazyScript*> lazyScript,

View File

@ -1160,8 +1160,8 @@ ObjectBox::trace(JSTracer* trc)
if (box->isFunctionBox()) {
FunctionBox* funbox = box->asFunctionBox();
funbox->bindings.trace(trc);
if (funbox->enclosingStaticScope_)
TraceRoot(trc, &funbox->enclosingStaticScope_, "funbox-enclosingStaticScope");
if (funbox->staticScope_)
TraceRoot(trc, &funbox->staticScope_, "funbox-staticScope");
}
box = box->traceLink;
}

View File

@ -48,22 +48,6 @@ using mozilla::Maybe;
using JS::AutoGCRooter;
JSFunction::AutoParseUsingFunctionBox::AutoParseUsingFunctionBox(ExclusiveContext* cx,
frontend::FunctionBox* funbox)
: fun_(cx, funbox->function()),
oldEnv_(cx, fun_->environment())
{
fun_->setFunctionBox(funbox);
funbox->computeAllowSyntax(fun_);
funbox->computeInWith(fun_);
}
JSFunction::AutoParseUsingFunctionBox::~AutoParseUsingFunctionBox()
{
fun_->unsetFunctionBox();
fun_->setEnvironment(oldEnv_);
}
namespace js {
namespace frontend {
@ -629,12 +613,12 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
template <typename ParseHandler>
FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun,
JSObject* enclosingStaticScope, ParseContext<ParseHandler>* outerpc,
JSObject* staticScope, ParseContext<ParseHandler>* outerpc,
Directives directives, bool extraWarnings, GeneratorKind generatorKind)
: ObjectBox(fun, traceListHead),
SharedContext(cx, directives, extraWarnings),
bindings(),
enclosingStaticScope_(enclosingStaticScope),
staticScope_(staticScope),
bufStart(0),
bufEnd(0),
length(0),
@ -652,17 +636,22 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
// baked into JIT code, so they must be allocated tenured. They are held by
// the JSScript so cannot be collected during a minor GC anyway.
MOZ_ASSERT(fun->isTenured());
if (staticScope->is<StaticFunctionBoxScopeObject>())
staticScope->as<StaticFunctionBoxScopeObject>().setFunctionBox(this);
computeAllowSyntax(staticScope);
computeInWith(staticScope);
}
template <typename ParseHandler>
FunctionBox*
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun,
ParseContext<ParseHandler>* outerpc,
Directives inheritedDirectives,
GeneratorKind generatorKind,
JSObject* enclosingStaticScope)
Parser<ParseHandler>::newFunctionBoxWithScope(Node fn, JSFunction* fun,
ParseContext<ParseHandler>* outerpc,
Directives inheritedDirectives,
GeneratorKind generatorKind,
JSObject* staticScope)
{
MOZ_ASSERT_IF(outerpc, enclosingStaticScope == outerpc->innermostStaticScope());
MOZ_ASSERT(fun);
/*
@ -673,8 +662,9 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun,
* function.
*/
FunctionBox* funbox =
alloc.new_<FunctionBox>(context, traceListHead, fun, enclosingStaticScope, outerpc,
inheritedDirectives, options().extraWarningsOption,
alloc.new_<FunctionBox>(context, traceListHead, fun, staticScope, outerpc,
inheritedDirectives,
options().extraWarningsOption,
generatorKind);
if (!funbox) {
ReportOutOfMemory(context);
@ -688,6 +678,29 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun,
return funbox;
}
template <typename ParseHandler>
FunctionBox*
Parser<ParseHandler>::newFunctionBox(Node fn, HandleFunction fun,
ParseContext<ParseHandler>* outerpc,
Directives inheritedDirectives,
GeneratorKind generatorKind,
HandleObject enclosingStaticScope)
{
MOZ_ASSERT_IF(outerpc, enclosingStaticScope == outerpc->innermostStaticScope());
StaticFunctionBoxScopeObject* scope =
StaticFunctionBoxScopeObject::create(context, enclosingStaticScope);
if (!scope)
return nullptr;
FunctionBox* funbox = newFunctionBoxWithScope(fn, fun, outerpc, inheritedDirectives,
generatorKind, scope);
if (!funbox)
return nullptr;
return funbox;
}
template <typename ParseHandler>
void
Parser<ParseHandler>::trace(JSTracer* trc)

View File

@ -106,11 +106,6 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
Node maybeFunction; /* sc->isFunctionBox, the pn where pn->pn_funbox == sc */
// If sc->isFunctionBox(), this is used to temporarily link up the
// FunctionBox with the JSFunction so the static scope chain may be walked
// without a JSScript.
mozilla::Maybe<JSFunction::AutoParseUsingFunctionBox> parseUsingFunctionBox;
// lastYieldOffset stores the offset of the last yield that was parsed.
// NoYieldOffset is its initial value.
static const uint32_t NoYieldOffset = UINT32_MAX;
@ -275,8 +270,6 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
inDeclDestructuring(false)
{
prs->pc = this;
if (sc->isFunctionBox())
parseUsingFunctionBox.emplace(prs->context, sc->asFunctionBox());
}
~ParseContext();
@ -470,10 +463,17 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
* cx->tempLifoAlloc.
*/
ObjectBox* newObjectBox(JSObject* obj);
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, ParseContext<ParseHandler>* outerpc,
Directives directives, GeneratorKind generatorKind,
JSObject* enclosingStaticScope);
FunctionBox* newFunctionBoxWithScope(Node fn, JSFunction* fun,
ParseContext<ParseHandler>* outerpc,
Directives directives, GeneratorKind generatorKind,
JSObject* staticScope);
private:
FunctionBox* newFunctionBox(Node fn, HandleFunction fun, ParseContext<ParseHandler>* outerpc,
Directives directives, GeneratorKind generatorKind,
HandleObject enclosingStaticScope);
public:
// Use when the funbox is the outermost.
FunctionBox* newFunctionBox(Node fn, HandleFunction fun, Directives directives,
GeneratorKind generatorKind, HandleObject enclosingStaticScope)

View File

@ -191,6 +191,10 @@ class SharedContext
bool inWith_;
bool superScopeAlreadyNeedsHomeObject_;
protected:
void computeAllowSyntax(JSObject* staticScope);
void computeInWith(JSObject* staticScope);
public:
SharedContext(ExclusiveContext* cx, Directives directives,
bool extraWarnings)
@ -211,8 +215,6 @@ class SharedContext
// for the static scope. FunctionBoxes are LifoAlloc'd and need to
// manually trace their static scope.
virtual JSObject* staticScope() const = 0;
void computeAllowSyntax(JSObject* staticScope);
void computeInWith(JSObject* staticScope);
virtual ObjectBox* toObjectBox() { return nullptr; }
inline bool isFunctionBox() { return toObjectBox() && toObjectBox()->isFunctionBox(); }
@ -275,7 +277,7 @@ class FunctionBox : public ObjectBox, public SharedContext
{
public:
Bindings bindings; /* bindings for this function */
JSObject* enclosingStaticScope_;
JSObject* staticScope_;
uint32_t bufStart;
uint32_t bufEnd;
uint32_t startLine;
@ -283,6 +285,7 @@ class FunctionBox : public ObjectBox, public SharedContext
uint16_t length;
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
bool inWith_:1; /* some enclosing scope is a with-statement */
bool inGenexpLambda:1; /* lambda from generator expression */
bool hasDestructuringArgs:1; /* arguments list contains destructuring expression */
bool useAsm:1; /* see useAsmOrInsideUseAsm */
@ -297,13 +300,13 @@ class FunctionBox : public ObjectBox, public SharedContext
template <typename ParseHandler>
FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun,
JSObject* enclosingStaticScope, ParseContext<ParseHandler>* pc,
JSObject* staticScope, ParseContext<ParseHandler>* pc,
Directives directives, bool extraWarnings, GeneratorKind generatorKind);
ObjectBox* toObjectBox() override { return this; }
JSFunction* function() const { return &object->as<JSFunction>(); }
JSObject* staticScope() const override { return function(); }
JSObject* enclosingStaticScope() const { return enclosingStaticScope_; }
JSObject* staticScope() const override { return staticScope_; }
void switchStaticScopeToFunction();
GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
bool isGenerator() const { return generatorKind() != NotGenerator; }

View File

@ -687,12 +687,12 @@ JSFunction::trace(JSTracer* trc)
// Functions can be be marked as interpreted despite having no script
// yet at some points when parsing, and can be lazy with no lazy script
// for self-hosted code.
if (hasScript() && !hasUncompiledScript())
if (hasScript() && u.i.s.script_)
TraceManuallyBarrieredEdge(trc, &u.i.s.script_, "script");
else if (isInterpretedLazy() && u.i.s.lazy_)
TraceManuallyBarrieredEdge(trc, &u.i.s.lazy_, "lazyScript");
if (!isBeingParsed() && u.i.env_)
if (u.i.env_)
TraceManuallyBarrieredEdge(trc, &u.i.env_, "fun_environment");
}
}

View File

@ -16,11 +16,6 @@
#include "jstypes.h"
namespace js {
namespace frontend {
class FunctionBox;
}
class FunctionExtended;
typedef JSNative Native;
@ -62,11 +57,9 @@ class JSFunction : public js::NativeObject
INTERPRETED_LAZY = 0x0200, /* function is interpreted but doesn't have a script yet */
RESOLVED_LENGTH = 0x0400, /* f.length has been resolved (see fun_resolve). */
RESOLVED_NAME = 0x0800, /* f.name has been resolved (see fun_resolve). */
BEING_PARSED = 0x1000, /* function is currently being parsed; has
a funbox in place of an environment */
FUNCTION_KIND_SHIFT = 13,
FUNCTION_KIND_MASK = 0x7 << FUNCTION_KIND_SHIFT,
FUNCTION_KIND_SHIFT = 12,
FUNCTION_KIND_MASK = 0xf << FUNCTION_KIND_SHIFT,
ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
@ -100,18 +93,6 @@ class JSFunction : public js::NativeObject
static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= FUNCTION_KIND_MASK,
"FunctionKind doesn't fit into flags_");
// Implemented in Parser.cpp. Used so the static scope chain may be walked
// in Parser without a JSScript.
class MOZ_STACK_CLASS AutoParseUsingFunctionBox
{
js::RootedFunction fun_;
js::RootedObject oldEnv_;
public:
AutoParseUsingFunctionBox(js::ExclusiveContext* cx, js::frontend::FunctionBox* funbox);
~AutoParseUsingFunctionBox();
};
private:
uint16_t nargs_; /* number of formal arguments
(including defaults and the rest parameter unlike f.length) */
@ -130,11 +111,8 @@ class JSFunction : public js::NativeObject
use the accessor! */
js::LazyScript* lazy_; /* lazily compiled script, or nullptr */
} s;
union {
JSObject* env_; /* environment for new activations;
use the accessor! */
js::frontend::FunctionBox* funbox_; /* the function box when parsing */
};
JSObject* env_; /* environment for new activations;
use the accessor! */
} i;
void* nativeOrScript;
} u;
@ -145,7 +123,6 @@ class JSFunction : public js::NativeObject
/* Call objects must be created for each invocation of a heavyweight function. */
bool isHeavyweight() const {
MOZ_ASSERT(!isInterpretedLazy());
MOZ_ASSERT(!isBeingParsed());
if (isNative())
return false;
@ -188,7 +165,6 @@ class JSFunction : public js::NativeObject
bool hasRest() const { return flags() & HAS_REST; }
bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; }
bool hasScript() const { return flags() & INTERPRETED; }
bool isBeingParsed() const { return flags() & BEING_PARSED; }
// Arrow functions store their lexical |this| in the first extended slot.
bool isArrow() const { return kind() == Arrow; }
@ -312,34 +288,20 @@ class JSFunction : public js::NativeObject
* activations (stack frames) of the function.
*/
JSObject* environment() const {
MOZ_ASSERT(isInterpreted() && !isBeingParsed());
MOZ_ASSERT(isInterpreted());
return u.i.env_;
}
void setEnvironment(JSObject* obj) {
MOZ_ASSERT(isInterpreted() && !isBeingParsed());
MOZ_ASSERT(isInterpreted());
*(js::HeapPtrObject*)&u.i.env_ = obj;
}
void initEnvironment(JSObject* obj) {
MOZ_ASSERT(isInterpreted() && !isBeingParsed());
MOZ_ASSERT(isInterpreted());
((js::HeapPtrObject*)&u.i.env_)->init(obj);
}
private:
void setFunctionBox(js::frontend::FunctionBox* funbox) {
MOZ_ASSERT(isInterpreted());
flags_ |= BEING_PARSED;
u.i.funbox_ = funbox;
}
void unsetFunctionBox() {
MOZ_ASSERT(isBeingParsed());
flags_ &= ~BEING_PARSED;
u.i.funbox_ = nullptr;
}
public:
static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); }
static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags_); }
static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
@ -437,11 +399,6 @@ class JSFunction : public js::NativeObject
return u.i.s.lazy_;
}
js::frontend::FunctionBox* functionBox() const {
MOZ_ASSERT(isBeingParsed());
return u.i.funbox_;
}
js::GeneratorKind generatorKind() const {
if (!isInterpreted())
return js::NotGenerator;

View File

@ -2650,6 +2650,10 @@ JSScript::linkToFunctionFromEmitter(js::ExclusiveContext* cx, JS::Handle<JSScrip
fun->setUnlazifiedScript(script);
else
fun->setScript(script);
// Switch the static scope over to the JSFunction now that we have a
// JSScript.
funbox->switchStaticScopeToFunction();
}
/* static */ bool

View File

@ -80,13 +80,11 @@ StaticScopeIter<allowGC>::operator++(int)
obj = obj->template as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
} else if (obj->template is<StaticNonSyntacticScopeObjects>()) {
obj = obj->template as<StaticNonSyntacticScopeObjects>().enclosingScopeForStaticScopeIter();
} else if (obj->template is<StaticFunctionBoxScopeObject>()) {
obj = obj->template as<StaticFunctionBoxScopeObject>().enclosingScopeForStaticScopeIter();
} else if (onNamedLambda || !obj->template as<JSFunction>().isNamedLambda()) {
onNamedLambda = false;
JSFunction& fun = obj->template as<JSFunction>();
if (fun.isBeingParsed())
obj = fun.functionBox()->enclosingStaticScope();
else
obj = fun.nonLazyScript()->enclosingStaticScope();
obj = obj->template as<JSFunction>().nonLazyScript()->enclosingStaticScope();
} else {
onNamedLambda = true;
}
@ -98,12 +96,10 @@ template <AllowGC allowGC>
inline bool
StaticScopeIter<allowGC>::hasSyntacticDynamicScopeObject() const
{
if (obj->template is<JSFunction>()) {
JSFunction& fun = obj->template as<JSFunction>();
if (fun.isBeingParsed())
return fun.functionBox()->isHeavyweight();
return fun.isHeavyweight();
}
if (obj->template is<JSFunction>())
return obj->template as<JSFunction>().isHeavyweight();
if (obj->template is<StaticFunctionBoxScopeObject>())
return obj->template as<StaticFunctionBoxScopeObject>().functionBox()->isHeavyweight();
if (obj->template is<StaticBlockObject>())
return obj->template as<StaticBlockObject>().needsClone();
if (obj->template is<StaticWithObject>())
@ -187,6 +183,8 @@ inline JSFunction&
StaticScopeIter<allowGC>::fun() const
{
MOZ_ASSERT(type() == Function);
if (maybeFunctionBox())
return *maybeFunctionBox()->function();
return obj->template as<JSFunction>();
}
@ -195,8 +193,8 @@ inline frontend::FunctionBox*
StaticScopeIter<allowGC>::maybeFunctionBox() const
{
MOZ_ASSERT(type() == Function);
if (fun().isBeingParsed())
return fun().functionBox();
if (obj->template is<StaticFunctionBoxScopeObject>())
return obj->template as<StaticFunctionBoxScopeObject>().functionBox();
return nullptr;
}

View File

@ -593,6 +593,25 @@ const Class NonSyntacticVariablesObject::class_ = {
JSCLASS_IS_ANONYMOUS
};
/* static */ StaticFunctionBoxScopeObject*
StaticFunctionBoxScopeObject::create(ExclusiveContext* cx, HandleObject enclosing)
{
StaticFunctionBoxScopeObject* obj =
NewObjectWithNullTaggedProto<StaticFunctionBoxScopeObject>(cx, GenericObject,
BaseShape::DELEGATE);
if (!obj)
return nullptr;
obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(enclosing));
return obj;
}
const Class StaticFunctionBoxScopeObject::class_ = {
"StaticFunctionBoxScopeObject",
JSCLASS_HAS_RESERVED_SLOTS(StaticFunctionBoxScopeObject::RESERVED_SLOTS) |
JSCLASS_IS_ANONYMOUS
};
/*****************************************************************************/
/* static */ ClonedBlockObject*
@ -2593,7 +2612,7 @@ js::DumpStaticScopeChain(JSObject* staticScope)
for (StaticScopeIter<NoGC> ssi(staticScope); !ssi.done(); ssi++) {
switch (ssi.type()) {
case StaticScopeIter<NoGC>::Function:
if (ssi.fun().isBeingParsed())
if (ssi.maybeFunctionBox())
fprintf(stdout, "funbox [%p fun=%p]", ssi.maybeFunctionBox(), &ssi.fun());
else
fprintf(stdout, "function [%p]", &ssi.fun());

View File

@ -26,6 +26,7 @@ class FunctionBox;
class StaticWithObject;
class StaticEvalObject;
class StaticNonSyntacticScopeObjects;
class StaticFunctionBoxScopeObject;
/*****************************************************************************/
@ -58,6 +59,10 @@ class StaticNonSyntacticScopeObjects;
* StaticNonSyntacticScopeObjects
* Signals presence of "polluting" scope objects. Used by Gecko.
*
* StaticFunctionBoxScopeObject
* Stands in for JSFunctions in the Parser, before their JSScripts
* are compiled.
*
* There is an additional scope for named lambdas without a static scope
* object. E.g., in:
*
@ -78,6 +83,7 @@ class StaticScopeIter
obj->is<StaticWithObject>() ||
obj->is<StaticEvalObject>() ||
obj->is<StaticNonSyntacticScopeObjects>() ||
obj->is<StaticFunctionBoxScopeObject>() ||
obj->is<JSFunction>();
}
@ -453,6 +459,33 @@ class NonSyntacticVariablesObject : public ScopeObject
static NonSyntacticVariablesObject* create(JSContext* cx, Handle<GlobalObject*> global);
};
// Function static scopes that wrap around FunctionBoxes used in the Parser,
// before a JSScript has been created.
class StaticFunctionBoxScopeObject : public ScopeObject
{
static const unsigned FUNCTION_BOX_SLOT = 1;
public:
static const unsigned RESERVED_SLOTS = 2;
static const Class class_;
static StaticFunctionBoxScopeObject* create(ExclusiveContext* cx,
HandleObject enclosing);
void setFunctionBox(frontend::FunctionBox* funbox) {
setReservedSlot(FUNCTION_BOX_SLOT, PrivateValue(funbox));
}
frontend::FunctionBox* functionBox() {
return reinterpret_cast<frontend::FunctionBox*>(
getReservedSlot(FUNCTION_BOX_SLOT).toPrivate());
}
JSObject* enclosingScopeForStaticScopeIter() {
return getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull();
}
};
class NestedScopeObject : public ScopeObject
{
public: