mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 783315 - Don't touch script->bindings.bindingArray if the script isn't fully compiled (r=billm)
--HG-- extra : rebase_source : fb4e163eaf9f3f7d84ad632d5f940b9d343c8ffc
This commit is contained in:
parent
8dab9caf9c
commit
b41894b285
@ -102,7 +102,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
|
|||||||
|
|
||||||
// Global/eval script bindings are always empty (all names are added to the
|
// Global/eval script bindings are always empty (all names are added to the
|
||||||
// scope dynamically via JSOP_DEFFUN/VAR).
|
// scope dynamically via JSOP_DEFFUN/VAR).
|
||||||
if (!script->bindings.init(cx, 0, 0, NULL))
|
if (!script->bindings.initWithTemporaryStorage(cx, 0, 0, NULL))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// We can specialize a bit for the given scope chain if that scope chain is the global object.
|
// We can specialize a bit for the given scope chain if that scope chain is the global object.
|
||||||
|
@ -223,7 +223,7 @@ TreeContext::generateFunctionBindings(JSContext *cx, Bindings *bindings) const
|
|||||||
AppendPackedBindings(this, args_, packedBindings);
|
AppendPackedBindings(this, args_, packedBindings);
|
||||||
AppendPackedBindings(this, vars_, packedBindings + args_.length());
|
AppendPackedBindings(this, vars_, packedBindings + args_.length());
|
||||||
|
|
||||||
if (!bindings->init(cx, args_.length(), vars_.length(), packedBindings))
|
if (!bindings->initWithTemporaryStorage(cx, args_.length(), vars_.length(), packedBindings))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bindings->hasAnyAliasedBindings() || sc->funHasExtensibleScope())
|
if (bindings->hasAnyAliasedBindings() || sc->funHasExtensibleScope())
|
||||||
|
@ -62,10 +62,10 @@ Bindings::argumentsVarIndex(JSContext *cx) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Bindings::init(JSContext *cx, unsigned numArgs, unsigned numVars, Binding *bindingArray)
|
Bindings::initWithTemporaryStorage(JSContext *cx, unsigned numArgs, unsigned numVars, Binding *bindingArray)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!callObjShape_);
|
JS_ASSERT(!callObjShape_);
|
||||||
JS_ASSERT(!bindingArray_);
|
JS_ASSERT(bindingArrayAndFlag_ == TEMPORARY_STORAGE_BIT);
|
||||||
|
|
||||||
if (numArgs > UINT16_MAX || numVars > UINT16_MAX) {
|
if (numArgs > UINT16_MAX || numVars > UINT16_MAX) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
@ -75,11 +75,11 @@ Bindings::init(JSContext *cx, unsigned numArgs, unsigned numVars, Binding *bindi
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingArray_ = bindingArray;
|
JS_ASSERT(!(uintptr_t(bindingArray) & TEMPORARY_STORAGE_BIT));
|
||||||
|
bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT;
|
||||||
numArgs_ = numArgs;
|
numArgs_ = numArgs;
|
||||||
numVars_ = numVars;
|
numVars_ = numVars;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the initial shape to use when creating CallObjects for this script.
|
* Get the initial shape to use when creating CallObjects for this script.
|
||||||
* Since unaliased variables are, by definition, only accessed by local
|
* Since unaliased variables are, by definition, only accessed by local
|
||||||
@ -135,10 +135,13 @@ Bindings::init(JSContext *cx, unsigned numArgs, unsigned numVars, Binding *bindi
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *
|
uint8_t *
|
||||||
Bindings::switchStorageTo(Binding *newBindingArray)
|
Bindings::switchToScriptStorage(Binding *newBindingArray)
|
||||||
{
|
{
|
||||||
PodCopy(newBindingArray, bindingArray_, count());
|
JS_ASSERT(bindingArrayUsingTemporaryStorage());
|
||||||
bindingArray_ = newBindingArray;
|
JS_ASSERT(!(uintptr_t(newBindingArray) & TEMPORARY_STORAGE_BIT));
|
||||||
|
|
||||||
|
PodCopy(newBindingArray, bindingArray(), count());
|
||||||
|
bindingArrayAndFlag_ = uintptr_t(newBindingArray);
|
||||||
return reinterpret_cast<uint8_t *>(newBindingArray + count());
|
return reinterpret_cast<uint8_t *>(newBindingArray + count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +150,7 @@ Bindings::clone(JSContext *cx, uint8_t *dstScriptData, HandleScript srcScript)
|
|||||||
{
|
{
|
||||||
/* The clone has the same bindingArray_ offset as 'src'. */
|
/* The clone has the same bindingArray_ offset as 'src'. */
|
||||||
Bindings &src = srcScript->bindings;
|
Bindings &src = srcScript->bindings;
|
||||||
ptrdiff_t off = (uint8_t *)src.bindingArray_ - srcScript->data;
|
ptrdiff_t off = (uint8_t *)src.bindingArray() - srcScript->data;
|
||||||
JS_ASSERT(off >= 0);
|
JS_ASSERT(off >= 0);
|
||||||
JS_ASSERT(off <= (srcScript->code - srcScript->data));
|
JS_ASSERT(off <= (srcScript->code - srcScript->data));
|
||||||
Binding *dstPackedBindings = (Binding *)(dstScriptData + off);
|
Binding *dstPackedBindings = (Binding *)(dstScriptData + off);
|
||||||
@ -156,8 +159,10 @@ Bindings::clone(JSContext *cx, uint8_t *dstScriptData, HandleScript srcScript)
|
|||||||
* Since atoms are shareable throughout the runtime, we can simply copy
|
* Since atoms are shareable throughout the runtime, we can simply copy
|
||||||
* the source's bindingArray directly.
|
* the source's bindingArray directly.
|
||||||
*/
|
*/
|
||||||
PodCopy(dstPackedBindings, src.bindingArray_, src.count());
|
if (!initWithTemporaryStorage(cx, src.numArgs(), src.numVars(), src.bindingArray()))
|
||||||
return init(cx, src.numArgs(), src.numVars(), dstPackedBindings);
|
return false;
|
||||||
|
switchToScriptStorage(dstPackedBindings);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<XDRMode mode>
|
template<XDRMode mode>
|
||||||
@ -207,7 +212,7 @@ XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, un
|
|||||||
bindingArray[i] = Binding(name, kind, aliased);
|
bindingArray[i] = Binding(name, kind, aliased);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!script->bindings.init(cx, numArgs, numVars, bindingArray))
|
if (!script->bindings.initWithTemporaryStorage(cx, numArgs, numVars, bindingArray))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +223,7 @@ bool
|
|||||||
Bindings::bindingIsAliased(unsigned bindingIndex)
|
Bindings::bindingIsAliased(unsigned bindingIndex)
|
||||||
{
|
{
|
||||||
JS_ASSERT(bindingIndex < count());
|
JS_ASSERT(bindingIndex < count());
|
||||||
return bindingArray_[bindingIndex].aliased();
|
return bindingArray()[bindingIndex].aliased();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -227,7 +232,15 @@ Bindings::trace(JSTracer *trc)
|
|||||||
if (callObjShape_)
|
if (callObjShape_)
|
||||||
MarkShape(trc, &callObjShape_, "callObjShape");
|
MarkShape(trc, &callObjShape_, "callObjShape");
|
||||||
|
|
||||||
for (Binding *b = bindingArray_, *end = b + count(); b != end; b++) {
|
/*
|
||||||
|
* As the comment in Bindings explains, bindingsArray may point into freed
|
||||||
|
* storage when bindingArrayUsingTemporaryStorage so we don't mark it.
|
||||||
|
* Note: during compilation, atoms are already kept alive by gcKeepAtoms.
|
||||||
|
*/
|
||||||
|
if (bindingArrayUsingTemporaryStorage())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (Binding *b = bindingArray(), *end = b + count(); b != end; b++) {
|
||||||
PropertyName *name = b->name();
|
PropertyName *name = b->name();
|
||||||
MarkStringUnbarriered(trc, &name, "bindingArray");
|
MarkStringUnbarriered(trc, &name, "bindingArray");
|
||||||
}
|
}
|
||||||
@ -1573,7 +1586,7 @@ JSScript::partiallyInit(JSContext *cx, Handle<JSScript*> script,
|
|||||||
cursor += vectorSize;
|
cursor += vectorSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = script->bindings.switchStorageTo(reinterpret_cast<Binding *>(cursor));
|
cursor = script->bindings.switchToScriptStorage(reinterpret_cast<Binding *>(cursor));
|
||||||
|
|
||||||
script->code = (jsbytecode *)cursor;
|
script->code = (jsbytecode *)cursor;
|
||||||
JS_ASSERT(cursor + length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote) == script->data + size);
|
JS_ASSERT(cursor + length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote) == script->data + size);
|
||||||
|
@ -87,20 +87,20 @@ class Binding
|
|||||||
* One JSScript stores one Binding per formal/variable so we use a
|
* One JSScript stores one Binding per formal/variable so we use a
|
||||||
* packed-word representation.
|
* packed-word representation.
|
||||||
*/
|
*/
|
||||||
size_t bits_;
|
uintptr_t bits_;
|
||||||
|
|
||||||
static const size_t KIND_MASK = 0x3;
|
static const uintptr_t KIND_MASK = 0x3;
|
||||||
static const size_t ALIASED_BIT = 0x4;
|
static const uintptr_t ALIASED_BIT = 0x4;
|
||||||
static const size_t NAME_MASK = ~(KIND_MASK | ALIASED_BIT);
|
static const uintptr_t NAME_MASK = ~(KIND_MASK | ALIASED_BIT);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Binding() : bits_(0) {}
|
explicit Binding() : bits_(0) {}
|
||||||
|
|
||||||
Binding(PropertyName *name, BindingKind kind, bool aliased) {
|
Binding(PropertyName *name, BindingKind kind, bool aliased) {
|
||||||
JS_STATIC_ASSERT(CONSTANT <= KIND_MASK);
|
JS_STATIC_ASSERT(CONSTANT <= KIND_MASK);
|
||||||
JS_ASSERT((size_t(name) & ~NAME_MASK) == 0);
|
JS_ASSERT((uintptr_t(name) & ~NAME_MASK) == 0);
|
||||||
JS_ASSERT((size_t(kind) & ~KIND_MASK) == 0);
|
JS_ASSERT((uintptr_t(kind) & ~KIND_MASK) == 0);
|
||||||
bits_ = size_t(name) | size_t(kind) | (aliased ? ALIASED_BIT : 0);
|
bits_ = uintptr_t(name) | uintptr_t(kind) | (aliased ? ALIASED_BIT : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyName *name() const {
|
PropertyName *name() const {
|
||||||
@ -116,7 +116,7 @@ class Binding
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
JS_STATIC_ASSERT(sizeof(Binding) == sizeof(size_t));
|
JS_STATIC_ASSERT(sizeof(Binding) == sizeof(uintptr_t));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Formal parameters and local variables are stored in a shape tree
|
* Formal parameters and local variables are stored in a shape tree
|
||||||
@ -130,20 +130,38 @@ class Bindings
|
|||||||
friend class AliasedFormalIter;
|
friend class AliasedFormalIter;
|
||||||
|
|
||||||
HeapPtr<Shape> callObjShape_;
|
HeapPtr<Shape> callObjShape_;
|
||||||
Binding *bindingArray_;
|
uintptr_t bindingArrayAndFlag_;
|
||||||
uint16_t numArgs_;
|
uint16_t numArgs_;
|
||||||
uint16_t numVars_;
|
uint16_t numVars_;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* During parsing, bindings are allocated out of a temporary LifoAlloc.
|
||||||
|
* After parsing, a JSScript object is created and the bindings are
|
||||||
|
* permanently transferred to it. On error paths, the JSScript object may
|
||||||
|
* end up with bindings that still point to the (new released) LifoAlloc
|
||||||
|
* memory. To avoid tracing these bindings during GC, we keep track of
|
||||||
|
* whether the bindings are temporary or permanent in the low bit of
|
||||||
|
* bindingArrayAndFlag_.
|
||||||
|
*/
|
||||||
|
static const uintptr_t TEMPORARY_STORAGE_BIT = 0x1;
|
||||||
|
bool bindingArrayUsingTemporaryStorage() const {
|
||||||
|
return bindingArrayAndFlag_ & TEMPORARY_STORAGE_BIT;
|
||||||
|
}
|
||||||
|
Binding *bindingArray() const {
|
||||||
|
return reinterpret_cast<Binding *>(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline Bindings();
|
inline Bindings();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize a Bindings. bindingArray must have length numArgs+numVars and
|
* Initialize a Bindings with a pointer into temporary storage.
|
||||||
* must outlive Bindings. To use a temporary bindingArray, the caller may
|
* bindingArray must have length numArgs+numVars. Before the temporary
|
||||||
* call switchStorageTo, providing new storage for Bindings to use.
|
* storage is release, switchToScriptStorage must be called, providing a
|
||||||
|
* pointer into the Binding array stored in script->data.
|
||||||
*/
|
*/
|
||||||
bool init(JSContext *cx, unsigned numArgs, unsigned numVars, Binding *bindingArray);
|
bool initWithTemporaryStorage(JSContext *cx, unsigned numArgs, unsigned numVars, Binding *bindingArray);
|
||||||
uint8_t *switchStorageTo(Binding *newStorage);
|
uint8_t *switchToScriptStorage(Binding *newStorage);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clone srcScript's bindings (as part of js::CloneScript). dstScriptData
|
* Clone srcScript's bindings (as part of js::CloneScript). dstScriptData
|
||||||
@ -858,8 +876,8 @@ class BindingIter
|
|||||||
return i_ < bindings_->numArgs() ? i_ : i_ - bindings_->numArgs();
|
return i_ < bindings_->numArgs() ? i_ : i_ - bindings_->numArgs();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Binding &operator*() const { JS_ASSERT(!done()); return bindings_->bindingArray_[i_]; }
|
const Binding &operator*() const { JS_ASSERT(!done()); return bindings_->bindingArray()[i_]; }
|
||||||
const Binding *operator->() const { JS_ASSERT(!done()); return &bindings_->bindingArray_[i_]; }
|
const Binding *operator->() const { JS_ASSERT(!done()); return &bindings_->bindingArray()[i_]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -24,7 +24,7 @@ namespace js {
|
|||||||
|
|
||||||
inline
|
inline
|
||||||
Bindings::Bindings()
|
Bindings::Bindings()
|
||||||
: callObjShape_(NULL), bindingArray_(NULL), numArgs_(0), numVars_(0)
|
: callObjShape_(NULL), bindingArrayAndFlag_(TEMPORARY_STORAGE_BIT), numArgs_(0), numVars_(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -35,7 +35,7 @@ Bindings::extensibleParents()
|
|||||||
|
|
||||||
inline
|
inline
|
||||||
AliasedFormalIter::AliasedFormalIter(JSScript *script)
|
AliasedFormalIter::AliasedFormalIter(JSScript *script)
|
||||||
: begin_(script->bindings.bindingArray_),
|
: begin_(script->bindings.bindingArray()),
|
||||||
p_(begin_),
|
p_(begin_),
|
||||||
end_(begin_ + (script->funHasAnyAliasedFormal ? script->bindings.numArgs() : 0)),
|
end_(begin_ + (script->funHasAnyAliasedFormal ? script->bindings.numArgs() : 0)),
|
||||||
slot_(CallObject::RESERVED_SLOTS)
|
slot_(CallObject::RESERVED_SLOTS)
|
||||||
|
Loading…
Reference in New Issue
Block a user