mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-09 04:25:38 +00:00
Bug 780309 - Implement InternalHandle and use it for Bindings. r=terrence
This commit is contained in:
parent
5de9a55989
commit
2f044a0ac0
@ -114,7 +114,8 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
|
||||
|
||||
// Global/eval script bindings are always empty (all names are added to the
|
||||
// scope dynamically via JSOP_DEFFUN/VAR).
|
||||
if (!script->bindings.initWithTemporaryStorage(cx, 0, 0, NULL))
|
||||
InternalHandle<Bindings*> bindings(script, &script->bindings);
|
||||
if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, NULL))
|
||||
return NULL;
|
||||
|
||||
// We can specialize a bit for the given scope chain if that scope chain is the global object.
|
||||
@ -327,7 +328,8 @@ frontend::CompileFunctionBody(JSContext *cx, HandleFunction fun, CompileOptions
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
if (!funpc.generateFunctionBindings(cx, &script->bindings))
|
||||
InternalHandle<Bindings*> bindings(script, &script->bindings);
|
||||
if (!funpc.generateFunctionBindings(cx, bindings))
|
||||
return false;
|
||||
|
||||
BytecodeEmitter funbce(/* parent = */ NULL, &parser, &funsc, script, /* callerFrame = */ NULL,
|
||||
|
@ -296,7 +296,7 @@ AppendPackedBindings(const ParseContext *pc, const DeclVector &vec, Binding *dst
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::generateFunctionBindings(JSContext *cx, Bindings *bindings) const
|
||||
ParseContext::generateFunctionBindings(JSContext *cx, InternalHandle<Bindings*> bindings) const
|
||||
{
|
||||
JS_ASSERT(sc->inFunction());
|
||||
|
||||
@ -310,8 +310,11 @@ ParseContext::generateFunctionBindings(JSContext *cx, Bindings *bindings) const
|
||||
AppendPackedBindings(this, args_, packedBindings);
|
||||
AppendPackedBindings(this, vars_, packedBindings + args_.length());
|
||||
|
||||
if (!bindings->initWithTemporaryStorage(cx, args_.length(), vars_.length(), packedBindings))
|
||||
if (!Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
|
||||
packedBindings))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bindings->hasAnyAliasedBindings() || sc->funHasExtensibleScope())
|
||||
sc->funbox()->fun()->flags |= JSFUN_HEAVYWEIGHT;
|
||||
@ -1257,7 +1260,9 @@ LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL,
|
||||
}
|
||||
}
|
||||
|
||||
if (!funpc->generateFunctionBindings(cx, &funbox->bindings))
|
||||
InternalHandle<Bindings*> bindings =
|
||||
InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
|
||||
if (!funpc->generateFunctionBindings(cx, bindings))
|
||||
return false;
|
||||
|
||||
funpc->lexdeps.releaseMap(cx);
|
||||
|
@ -151,7 +151,7 @@ struct ParseContext /* tree context for semantic checks */
|
||||
* - Sometimes a script's bindings are accessed at runtime to retrieve the
|
||||
* contents of the lexical scope (e.g., from the debugger).
|
||||
*/
|
||||
bool generateFunctionBindings(JSContext *cx, Bindings *bindings) const;
|
||||
bool generateFunctionBindings(JSContext *cx, InternalHandle<Bindings*> bindings) const;
|
||||
|
||||
public:
|
||||
ParseNode *yieldNode; /* parse node for a yield expression that might
|
||||
|
@ -240,6 +240,73 @@ typedef JSObject * RawObject;
|
||||
typedef JSString * RawString;
|
||||
typedef Value RawValue;
|
||||
|
||||
/*
|
||||
* InternalHandle is a handle to an internal pointer into a gcthing. Use
|
||||
* InternalHandle when you have a pointer to a direct field of a gcthing, or
|
||||
* when you need a parameter type for something that *may* be a pointer to a
|
||||
* direct field of a gcthing.
|
||||
*/
|
||||
class InternalHandleBase
|
||||
{
|
||||
protected:
|
||||
static void * const zeroPointer;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class InternalHandle { };
|
||||
|
||||
template <typename T>
|
||||
class InternalHandle<T*> : public InternalHandleBase
|
||||
{
|
||||
void * const *holder;
|
||||
size_t offset;
|
||||
|
||||
public:
|
||||
/*
|
||||
* Create an InternalHandle using a Handle to the gcthing containing the
|
||||
* field in question, and a pointer to the field.
|
||||
*/
|
||||
template<typename H>
|
||||
InternalHandle(const Handle<H> &handle, T *field)
|
||||
: holder((void**)handle.address()), offset(uintptr_t(field) - uintptr_t(handle.get()))
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an InternalHandle to a field within a Rooted<>.
|
||||
*/
|
||||
template<typename R>
|
||||
InternalHandle(const Rooted<R> &root, T *field)
|
||||
: holder((void**)root.address()), offset(uintptr_t(field) - uintptr_t(root.get()))
|
||||
{
|
||||
}
|
||||
|
||||
T *get() const { return reinterpret_cast<T*>(uintptr_t(*holder) + offset); }
|
||||
|
||||
const T& operator *() const { return *get(); }
|
||||
T* operator ->() const { return get(); }
|
||||
|
||||
static InternalHandle<T*> fromMarkedLocation(T *fieldPtr) {
|
||||
return InternalHandle(fieldPtr);
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* Create an InternalHandle to something that is not a pointer to a
|
||||
* gcthing, and so does not need to be rooted in the first place. Use these
|
||||
* InternalHandles to pass pointers into functions that also need to accept
|
||||
* regular InternalHandles to gcthing fields.
|
||||
*
|
||||
* Make this private to prevent accidental misuse; this is only for
|
||||
* fromMarkedLocation().
|
||||
*/
|
||||
InternalHandle(T *field)
|
||||
: holder(reinterpret_cast<void * const *>(&zeroPointer)),
|
||||
offset(uintptr_t(field))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
extern mozilla::ThreadLocal<JSRuntime *> TlsRuntime;
|
||||
|
||||
/*
|
||||
|
@ -1061,7 +1061,6 @@ class JS_PUBLIC_API(AutoGCRooter) {
|
||||
SHAPERANGE = -20, /* js::Shape::Range::AutoRooter */
|
||||
STACKSHAPE = -21, /* js::StackShape::AutoRooter */
|
||||
STACKBASESHAPE=-22,/* js::StackBaseShape::AutoRooter */
|
||||
BINDINGS = -23, /* js::Bindings::AutoRooter */
|
||||
GETTERSETTER =-24, /* js::AutoRooterGetterSetter */
|
||||
REGEXPSTATICS=-25, /* js::RegExpStatics::AutoRooter */
|
||||
NAMEVECTOR = -26, /* js::AutoNameVector */
|
||||
|
@ -103,6 +103,8 @@ using namespace mozilla;
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
void * const JS::InternalHandleBase::zeroPointer = NULL;
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
@ -2402,12 +2404,6 @@ AutoGCRooter::trace(JSTracer *trc)
|
||||
return;
|
||||
}
|
||||
|
||||
case BINDINGS: {
|
||||
Bindings::AutoRooter *rooter = static_cast<Bindings::AutoRooter *>(this);
|
||||
rooter->trace(trc);
|
||||
return;
|
||||
}
|
||||
|
||||
case GETTERSETTER: {
|
||||
AutoRooterGetterSetter::Inner *rooter = static_cast<AutoRooterGetterSetter::Inner *>(this);
|
||||
if ((rooter->attrs & JSPROP_GETTER) && *rooter->pgetter)
|
||||
@ -2453,12 +2449,6 @@ Shape::Range::AutoRooter::trace(JSTracer *trc)
|
||||
MarkShapeRoot(trc, const_cast<Shape**>(&r->cursor), "Shape::Range::AutoRooter");
|
||||
}
|
||||
|
||||
void
|
||||
Bindings::AutoRooter::trace(JSTracer *trc)
|
||||
{
|
||||
bindings->trace(trc);
|
||||
}
|
||||
|
||||
void
|
||||
RegExpStatics::AutoRooter::trace(JSTracer *trc)
|
||||
{
|
||||
|
@ -60,23 +60,25 @@ Bindings::argumentsVarIndex(JSContext *cx) const
|
||||
}
|
||||
|
||||
bool
|
||||
Bindings::initWithTemporaryStorage(JSContext *cx, unsigned numArgs, unsigned numVars, Binding *bindingArray)
|
||||
Bindings::initWithTemporaryStorage(JSContext *cx, InternalHandle<Bindings*> self,
|
||||
unsigned numArgs, unsigned numVars,
|
||||
Binding *bindingArray)
|
||||
{
|
||||
JS_ASSERT(!callObjShape_);
|
||||
JS_ASSERT(bindingArrayAndFlag_ == TEMPORARY_STORAGE_BIT);
|
||||
JS_ASSERT(!self->callObjShape_);
|
||||
JS_ASSERT(self->bindingArrayAndFlag_ == TEMPORARY_STORAGE_BIT);
|
||||
|
||||
if (numArgs > UINT16_MAX || numVars > UINT16_MAX) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
numArgs_ > numVars_ ?
|
||||
self->numArgs_ > self->numVars_ ?
|
||||
JSMSG_TOO_MANY_FUN_ARGS :
|
||||
JSMSG_TOO_MANY_LOCALS);
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_ASSERT(!(uintptr_t(bindingArray) & TEMPORARY_STORAGE_BIT));
|
||||
bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT;
|
||||
numArgs_ = numArgs;
|
||||
numVars_ = numVars;
|
||||
self->bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT;
|
||||
self->numArgs_ = numArgs;
|
||||
self->numVars_ = numVars;
|
||||
|
||||
/*
|
||||
* Get the initial shape to use when creating CallObjects for this script.
|
||||
@ -90,8 +92,8 @@ Bindings::initWithTemporaryStorage(JSContext *cx, unsigned numArgs, unsigned num
|
||||
JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == 2);
|
||||
gc::AllocKind allocKind = gc::FINALIZE_OBJECT2_BACKGROUND;
|
||||
JS_ASSERT(gc::GetGCKindSlots(allocKind) == CallObject::RESERVED_SLOTS);
|
||||
callObjShape_ = EmptyShape::getInitialShape(cx, &CallClass, NULL, cx->global(),
|
||||
allocKind, BaseShape::VAROBJ);
|
||||
self->callObjShape_ = EmptyShape::getInitialShape(cx, &CallClass, NULL, cx->global(),
|
||||
allocKind, BaseShape::VAROBJ);
|
||||
|
||||
#ifdef DEBUG
|
||||
HashSet<PropertyName *> added(cx);
|
||||
@ -99,9 +101,9 @@ Bindings::initWithTemporaryStorage(JSContext *cx, unsigned numArgs, unsigned num
|
||||
return false;
|
||||
#endif
|
||||
|
||||
BindingIter bi(*this);
|
||||
BindingIter bi(*self);
|
||||
unsigned slot = CallObject::RESERVED_SLOTS;
|
||||
for (unsigned i = 0, n = count(); i < n; i++, bi++) {
|
||||
for (unsigned i = 0, n = self->count(); i < n; i++, bi++) {
|
||||
if (!bi->aliased())
|
||||
continue;
|
||||
|
||||
@ -123,8 +125,8 @@ Bindings::initWithTemporaryStorage(JSContext *cx, unsigned numArgs, unsigned num
|
||||
unsigned frameIndex = bi.frameIndex();
|
||||
StackShape child(nbase, id, slot++, 0, attrs, Shape::HAS_SHORTID, frameIndex);
|
||||
|
||||
callObjShape_ = callObjShape_->getChildBinding(cx, child);
|
||||
if (!callObjShape_)
|
||||
self->callObjShape_ = self->callObjShape_->getChildBinding(cx, child);
|
||||
if (!self->callObjShape_)
|
||||
return false;
|
||||
}
|
||||
JS_ASSERT(!bi);
|
||||
@ -144,7 +146,9 @@ Bindings::switchToScriptStorage(Binding *newBindingArray)
|
||||
}
|
||||
|
||||
bool
|
||||
Bindings::clone(JSContext *cx, uint8_t *dstScriptData, HandleScript srcScript)
|
||||
Bindings::clone(JSContext *cx, InternalHandle<Bindings*> self,
|
||||
uint8_t *dstScriptData,
|
||||
HandleScript srcScript)
|
||||
{
|
||||
/* The clone has the same bindingArray_ offset as 'src'. */
|
||||
Bindings &src = srcScript->bindings;
|
||||
@ -157,9 +161,9 @@ Bindings::clone(JSContext *cx, uint8_t *dstScriptData, HandleScript srcScript)
|
||||
* Since atoms are shareable throughout the runtime, we can simply copy
|
||||
* the source's bindingArray directly.
|
||||
*/
|
||||
if (!initWithTemporaryStorage(cx, src.numArgs(), src.numVars(), src.bindingArray()))
|
||||
if (!initWithTemporaryStorage(cx, self, src.numArgs(), src.numVars(), src.bindingArray()))
|
||||
return false;
|
||||
switchToScriptStorage(dstPackedBindings);
|
||||
self->switchToScriptStorage(dstPackedBindings);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -210,7 +214,8 @@ XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, un
|
||||
bindingArray[i] = Binding(name, kind, aliased);
|
||||
}
|
||||
|
||||
if (!script->bindings.initWithTemporaryStorage(cx, numArgs, numVars, bindingArray))
|
||||
InternalHandle<Bindings*> bindings(script, &script->bindings);
|
||||
if (!Bindings::initWithTemporaryStorage(cx, bindings, numArgs, numVars, bindingArray))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2064,8 +2069,9 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
/* Bindings */
|
||||
|
||||
Bindings bindings;
|
||||
Bindings::AutoRooter bindingRooter(cx, &bindings);
|
||||
if (!bindings.clone(cx, data, src))
|
||||
InternalHandle<Bindings*> bindingsHandle =
|
||||
InternalHandle<Bindings*>::fromMarkedLocation(&bindings);
|
||||
if (!Bindings::clone(cx, bindingsHandle, data, src))
|
||||
return NULL;
|
||||
|
||||
/* Objects */
|
||||
@ -2130,6 +2136,7 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
js_free(data);
|
||||
return NULL;
|
||||
}
|
||||
AutoAssertNoGC nogc;
|
||||
|
||||
dst->bindings = bindings;
|
||||
|
||||
|
@ -160,14 +160,17 @@ class Bindings
|
||||
* storage is release, switchToScriptStorage must be called, providing a
|
||||
* pointer into the Binding array stored in script->data.
|
||||
*/
|
||||
bool initWithTemporaryStorage(JSContext *cx, unsigned numArgs, unsigned numVars, Binding *bindingArray);
|
||||
static bool initWithTemporaryStorage(JSContext *cx, InternalHandle<Bindings*> self,
|
||||
unsigned numArgs, unsigned numVars,
|
||||
Binding *bindingArray);
|
||||
|
||||
uint8_t *switchToScriptStorage(Binding *newStorage);
|
||||
|
||||
/*
|
||||
* Clone srcScript's bindings (as part of js::CloneScript). dstScriptData
|
||||
* is the pointer to what will eventually be dstScript->data.
|
||||
*/
|
||||
bool clone(JSContext *cx, uint8_t *dstScriptData, HandleScript srcScript);
|
||||
static bool clone(JSContext *cx, InternalHandle<Bindings*> self, uint8_t *dstScriptData, HandleScript srcScript);
|
||||
|
||||
unsigned numArgs() const { return numArgs_; }
|
||||
unsigned numVars() const { return numVars_; }
|
||||
@ -186,26 +189,6 @@ class Bindings
|
||||
bool hasAnyAliasedBindings() const { return !callObjShape_->isEmptyShape(); }
|
||||
|
||||
void trace(JSTracer *trc);
|
||||
class AutoRooter;
|
||||
};
|
||||
|
||||
class Bindings::AutoRooter : private AutoGCRooter
|
||||
{
|
||||
public:
|
||||
explicit AutoRooter(JSContext *cx, Bindings *bindings_
|
||||
JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoGCRooter(cx, BINDINGS), bindings(bindings_), skip(cx, bindings_)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
private:
|
||||
Bindings *bindings;
|
||||
SkipRoot skip;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class ScriptCounts
|
||||
|
Loading…
x
Reference in New Issue
Block a user