Merge mozilla-central into mozilla-inbound on a CLOSED TREE

This commit is contained in:
Ehsan Akhgari 2012-05-02 21:52:33 -04:00
commit 4c2155d99e
17 changed files with 404 additions and 124 deletions

View File

@ -375,12 +375,12 @@ frontend::CompileFunctionBody(JSContext *cx, JSFunction *fun,
* NB: do not use AutoLocalNameArray because it will release space
* allocated from cx->tempLifoAlloc by DefineArg.
*/
Vector<JSAtom *> names(cx);
BindingNames names(cx);
if (!funbce.bindings.getLocalNameArray(cx, &names)) {
fn = NULL;
} else {
for (unsigned i = 0; i < nargs; i++) {
if (!DefineArg(fn, names[i], i, &funbce)) {
if (!DefineArg(fn, names[i].maybeAtom, i, &funbce)) {
fn = NULL;
break;
}

View File

@ -544,7 +544,7 @@ class GCConstList {
Vector<Value> list;
public:
GCConstList(JSContext *cx) : list(cx) {}
bool append(Value v) { return list.append(v); }
bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
size_t length() const { return list.length(); }
void finish(ConstArray *array);
};

View File

@ -0,0 +1,24 @@
var g = newGlobal('new-compartment');
g.f = new Function('return function(x) { return x }');
assertEq(g.eval("clone(f)()(9)"), 9);
g.f = new Function('return function(x) { let(y = x+1) { return y } }');
assertEq(g.eval("clone(f)()(9)"), 10);
g.f = new Function('return function(x) { let(y = x, z = 1) { return y+z } }');
assertEq(g.eval("clone(f)()(9)"), 10);
g.f = new Function('return function(x) { return x.search(/ponies/) }');
assertEq(g.eval("clone(f)()('123ponies')"), 3);
g.f = new Function('return function(x,y) { return x.search(/a/) + y.search(/b/) }');
assertEq(g.eval("clone(f)()('12a','foo')"), 1);
g.f = new Function('return [function(x) x+2, function(y) let(z=y+1) z]');
assertEq(g.eval("let ([f,g] = clone(f)()) f(g(4))"), 7);
g.f = new Function('return function(x) { switch(x) { case "a": return "b"; case null: return "c" } }');
assertEq(g.eval("clone(f)()('a')"), "b");
assertEq(g.eval("clone(f)()(null)"), "c");
assertEq(g.eval("clone(f)()(3)"), undefined);

View File

@ -667,14 +667,18 @@ bool
js::XDRAtom(XDRState<mode> *xdr, JSAtom **atomp)
{
if (mode == XDR_ENCODE) {
JSString *str = *atomp;
return xdr->codeString(&str);
uint32_t nchars = (*atomp)->length();
if (!xdr->codeUint32(&nchars))
return false;
jschar *chars = const_cast<jschar *>((*atomp)->getChars(xdr->cx()));
if (!chars)
return false;
return xdr->codeChars(chars, nchars);
}
/*
* Inline XDRState::codeString when decoding to avoid JSString allocation
* for already existing atoms. See bug 321985.
*/
/* Avoid JSString allocation for already existing atoms. See bug 321985. */
uint32_t nchars;
if (!xdr->codeUint32(&nchars))
return false;

View File

@ -436,7 +436,7 @@ JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun)
extern JS_PUBLIC_API(uintptr_t *)
JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp)
{
Vector<JSAtom *> localNames(cx);
BindingNames localNames(cx);
if (!fun->script()->bindings.getLocalNameArray(cx, &localNames))
return NULL;
@ -449,15 +449,16 @@ JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp)
return NULL;
}
JS_ASSERT(sizeof(*names) == sizeof(*localNames.begin()));
js_memcpy(names, localNames.begin(), localNames.length() * sizeof(*names));
for (size_t i = 0; i < localNames.length(); i++)
names[i] = reinterpret_cast<uintptr_t>(localNames[i].maybeAtom);
return names;
}
extern JS_PUBLIC_API(JSAtom *)
JS_LocalNameToAtom(uintptr_t w)
{
return JS_LOCAL_NAME_TO_ATOM(w);
return reinterpret_cast<JSAtom *>(w);
}
extern JS_PUBLIC_API(JSString *)

View File

@ -374,6 +374,7 @@ template<XDRMode mode>
bool
js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript)
{
/* NB: Keep this in sync with CloneInterpretedFunction. */
JSFunction *fun;
JSAtom *atom;
uint32_t firstword; /* flag telling whether fun->atom is non-null,
@ -442,6 +443,35 @@ js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *xdr, JSObject **objp, JSScript
template bool
js::XDRInterpretedFunction(XDRState<XDR_DECODE> *xdr, JSObject **objp, JSScript *parentScript);
JSObject *
js::CloneInterpretedFunction(JSContext *cx, JSFunction *srcFun)
{
/* NB: Keep this in sync with XDRInterpretedFunction. */
RootedVarObject parent(cx, NULL);
JSFunction *clone = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, parent, NULL);
if (!clone)
return NULL;
if (!clone->clearParent(cx))
return NULL;
if (!clone->clearType(cx))
return NULL;
JSScript *clonedScript = CloneScript(cx, srcFun->script());
if (!clonedScript)
return NULL;
clone->nargs = srcFun->nargs;
clone->flags = srcFun->flags;
clone->atom.init(srcFun->atom);
clone->initScript(clonedScript);
if (!clonedScript->typeSetFunction(cx, clone))
return NULL;
js_CallNewScriptHook(cx, clone->script(), clone);
return clone;
}
/*
* [[HasInstance]] internal method for Function objects: fetch the .prototype
* property of its 'this' parameter, and walks the prototype chain of v (only

View File

@ -121,9 +121,6 @@ struct JSFunction : public JSObject
/* uint16_t representation bounds number of call object dynamic slots. */
enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
#define JS_LOCAL_NAME_TO_ATOM(nameWord) ((JSAtom *) ((nameWord) & ~uintptr_t(1)))
#define JS_LOCAL_NAME_IS_CONST(nameWord) ((((nameWord) & uintptr_t(1))) != 0)
/*
* For an interpreted function, accessors for the initial scope object of
* activations (stack frames) of the function.
@ -314,6 +311,9 @@ template<XDRMode mode>
bool
XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript);
extern JSObject *
CloneInterpretedFunction(JSContext *cx, JSFunction *fun);
} /* namespace js */
extern JSBool

View File

@ -1091,7 +1091,7 @@ struct JSPrinter
jsbytecode *dvgfence; /* DecompileExpression fencepost */
jsbytecode **pcstack; /* DecompileExpression modeled stack */
JSFunction *fun; /* interpreted function */
Vector<JSAtom *> *localNames; /* argument and variable names */
BindingNames *localNames; /* argument and variable names */
Vector<DecompiledOpcode> *decompiledOpcodes; /* optional state for decompiled ops */
DecompiledOpcode &decompiled(jsbytecode *pc) {
@ -1122,7 +1122,7 @@ js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun,
jp->localNames = NULL;
jp->decompiledOpcodes = NULL;
if (fun && fun->isInterpreted() && fun->script()->bindings.count() > 0) {
jp->localNames = cx->new_<Vector<JSAtom *> >(cx);
jp->localNames = cx->new_<BindingNames>(cx);
if (!jp->localNames || !fun->script()->bindings.getLocalNameArray(cx, jp->localNames)) {
js_DestroyPrinter(jp);
return NULL;
@ -1771,7 +1771,7 @@ GetArgOrVarAtom(JSPrinter *jp, unsigned slot)
{
LOCAL_ASSERT_RV(jp->fun, NULL);
LOCAL_ASSERT_RV(slot < jp->fun->script()->bindings.count(), NULL);
JSAtom *name = (*jp->localNames)[slot];
JSAtom *name = (*jp->localNames)[slot].maybeAtom;
#if !JS_HAS_DESTRUCTURING
LOCAL_ASSERT_RV(name, NULL);
#endif
@ -4667,8 +4667,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
#if JS_HAS_GENERATOR_EXPRS
sn = js_GetSrcNote(jp->script, pc);
if (sn && SN_TYPE(sn) == SRC_GENEXP) {
Vector<JSAtom *> *innerLocalNames;
Vector<JSAtom *> *outerLocalNames;
BindingNames *innerLocalNames;
BindingNames *outerLocalNames;
JSScript *inner, *outer;
Vector<DecompiledOpcode> *decompiledOpcodes;
SprintStack ss2(cx);
@ -4684,7 +4684,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
*/
LifoAllocScope las(&cx->tempLifoAlloc());
if (fun->script()->bindings.count() > 0) {
innerLocalNames = cx->new_<Vector<JSAtom *> >(cx);
innerLocalNames = cx->new_<BindingNames>(cx);
if (!innerLocalNames ||
!fun->script()->bindings.getLocalNameArray(cx, innerLocalNames))
{

View File

@ -76,6 +76,8 @@
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
#include "vm/RegExpObject-inl.h"
using namespace js;
using namespace js::gc;
using namespace js::frontend;
@ -214,12 +216,13 @@ Bindings::callObjectShape(JSContext *cx) const
}
bool
Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
Bindings::getLocalNameArray(JSContext *cx, BindingNames *namesp)
{
JS_ASSERT(lastBinding);
JS_ASSERT(count() > 0);
if (count() == 0)
return true;
Vector<JSAtom *> &names = *namesp;
BindingNames &names = *namesp;
JS_ASSERT(names.empty());
unsigned n = count();
@ -229,7 +232,7 @@ Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
#ifdef DEBUG
JSAtom * const POISON = reinterpret_cast<JSAtom *>(0xdeadbeef);
for (unsigned i = 0; i < n; i++)
names[i] = POISON;
names[i].maybeAtom = POISON;
#endif
for (Shape::Range r = lastBinding->all(); !r.empty(); r.popFront()) {
@ -238,23 +241,25 @@ Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
if (shape.getter() == CallObject::getArgOp) {
JS_ASSERT(index < nargs);
names[index].kind = ARGUMENT;
} else {
JS_ASSERT(index < nvars);
index += nargs;
names[index].kind = shape.writable() ? VARIABLE : CONSTANT;
}
if (JSID_IS_ATOM(shape.propid())) {
names[index] = JSID_TO_ATOM(shape.propid());
names[index].maybeAtom = JSID_TO_ATOM(shape.propid());
} else {
JS_ASSERT(JSID_IS_INT(shape.propid()));
JS_ASSERT(shape.getter() == CallObject::getArgOp);
names[index] = NULL;
names[index].maybeAtom = NULL;
}
}
#ifdef DEBUG
for (unsigned i = 0; i < n; i++)
JS_ASSERT(names[i] != POISON);
JS_ASSERT(names[i].maybeAtom != POISON);
#endif
return true;
@ -308,7 +313,7 @@ XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp)
enum ConstTag {
SCRIPT_INT = 0,
SCRIPT_DOUBLE = 1,
SCRIPT_STRING = 2,
SCRIPT_ATOM = 2,
SCRIPT_TRUE = 3,
SCRIPT_FALSE = 4,
SCRIPT_NULL = 5,
@ -322,7 +327,7 @@ XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp)
} else if (vp->isDouble()) {
tag = SCRIPT_DOUBLE;
} else if (vp->isString()) {
tag = SCRIPT_STRING;
tag = SCRIPT_ATOM;
} else if (vp->isTrue()) {
tag = SCRIPT_TRUE;
} else if (vp->isFalse()) {
@ -359,14 +364,14 @@ XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp)
vp->init(DoubleValue(d));
break;
}
case SCRIPT_STRING: {
JSString *str;
case SCRIPT_ATOM: {
JSAtom *atom;
if (mode == XDR_ENCODE)
str = vp->toString();
if (!xdr->codeString(&str))
atom = &vp->toString()->asAtom();
if (!XDRAtom(xdr, &atom))
return false;
if (mode == XDR_DECODE)
vp->init(StringValue(str));
vp->init(StringValue(atom));
break;
}
case SCRIPT_TRUE:
@ -393,6 +398,8 @@ template<XDRMode mode>
bool
js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
{
/* NB: Keep this in sync with CloneScript. */
enum ScriptBits {
NoScriptRval,
SavedCallerFun,
@ -465,13 +472,13 @@ js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
return false;
}
Vector<JSAtom *> names(cx);
BindingNames names(cx);
if (mode == XDR_ENCODE) {
if (!script->bindings.getLocalNameArray(cx, &names))
return false;
PodZero(bitmap, bitmapLength);
for (unsigned i = 0; i < nameCount; i++) {
if (i < nargs && names[i])
if (i < nargs && names[i].maybeAtom)
bitmap[i >> JS_BITS_PER_UINT32_LOG2] |= JS_BIT(i & (JS_BITS_PER_UINT32 - 1));
}
}
@ -489,14 +496,14 @@ js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
if (!bindings.addDestructuring(cx, &dummy))
return false;
} else {
JS_ASSERT(!names[i]);
JS_ASSERT(!names[i].maybeAtom);
}
continue;
}
RootedVarAtom name(cx);
if (mode == XDR_ENCODE)
name = names[i];
name = names[i].maybeAtom;
if (!XDRAtom(xdr, name.address()))
return false;
if (mode == XDR_DECODE) {
@ -1120,11 +1127,10 @@ JS_STATIC_ASSERT(sizeof(ConstArray) +
< JSScript::INVALID_OFFSET);
JS_STATIC_ASSERT(JSScript::INVALID_OFFSET <= 255);
JSScript *
JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
uint32_t nobjects, uint32_t nregexps,
uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals,
uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets, JSVersion version)
static inline size_t
ScriptDataSize(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
uint32_t nobjects, uint32_t nregexps, uint32_t ntrynotes, uint32_t nconsts,
uint32_t nglobals, uint16_t nClosedArgs, uint16_t nClosedVars)
{
size_t size = 0;
@ -1146,16 +1152,33 @@ JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t
size += length * sizeof(jsbytecode);
size += nsrcnotes * sizeof(jssrcnote);
return size;
}
/*
* We assume that calloc aligns on sizeof(Value) if the size we ask to
* allocate divides sizeof(Value).
*/
JS_STATIC_ASSERT(sizeof(Value) == sizeof(double));
static inline uint8_t *
AllocScriptData(JSContext *cx, size_t size)
{
uint8_t *data = static_cast<uint8_t *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
if (!data)
return NULL;
JS_ASSERT(size_t(data) % sizeof(Value) == 0);
return data;
}
JSScript *
JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
uint32_t nobjects, uint32_t nregexps,
uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals,
uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets, JSVersion version)
{
size_t size = ScriptDataSize(cx, length, nsrcnotes, natoms, nobjects, nregexps,
ntrynotes, nconsts, nglobals, nClosedArgs, nClosedVars);
uint8_t *data = AllocScriptData(cx, size);
if (!data)
return NULL;
JSScript *script = js_NewGCScript(cx);
if (!script) {
Foreground::free_(data);
@ -1449,6 +1472,10 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
Debugger::onNewScript(cx, script, compileAndGoGlobal);
}
/*
* initScriptCounts updates scriptCountsMap if necessary. The other script
* maps in JSCompartment are populated lazily.
*/
if (cx->hasRunOption(JSOPTION_PCCOUNT))
(void) script->initScriptCounts(cx);
@ -1738,28 +1765,186 @@ CurrentScriptFileLineOriginSlow(JSContext *cx, const char **file, unsigned *line
} /* namespace js */
JSScript *
js::CloneScript(JSContext *cx, JSScript *script)
template <class T>
static inline T *
Rebase(JSScript *dst, JSScript *src, T *srcp)
{
JS_ASSERT(cx->compartment != script->compartment());
size_t off = reinterpret_cast<uint8_t *>(srcp) - src->data;
return reinterpret_cast<T *>(dst->data + off);
}
/* Serialize script. */
XDREncoder encoder(cx);
JSScript *
js::CloneScript(JSContext *cx, JSScript *src)
{
/* NB: Keep this in sync with XDRScript. */
if (!XDRScript(&encoder, &script, NULL))
uint32_t nconsts = JSScript::isValidOffset(src->constsOffset) ? src->consts()->length : 0;
uint32_t nobjects = JSScript::isValidOffset(src->objectsOffset) ? src->objects()->length : 0;
uint32_t nregexps = JSScript::isValidOffset(src->regexpsOffset) ? src->regexps()->length : 0;
uint32_t ntrynotes = JSScript::isValidOffset(src->trynotesOffset) ? src->trynotes()->length : 0;
uint32_t nClosedArgs = src->numClosedArgs();
uint32_t nClosedVars = src->numClosedVars();
JS_ASSERT(!JSScript::isValidOffset(src->globalsOffset));
uint32_t nglobals = 0;
/* Script data */
size_t size = ScriptDataSize(cx, src->length, src->numNotes(), src->natoms,
nobjects, nregexps, ntrynotes, nconsts, nglobals,
nClosedArgs, nClosedVars);
uint8_t *data = AllocScriptData(cx, size);
if (!data)
return NULL;
uint32_t nbytes;
const void *p = encoder.getData(&nbytes);
/* Bindings */
/* De-serialize script. */
XDRDecoder decoder(cx, p, nbytes, cx->compartment->principals, script->originPrincipals);
Bindings bindings(cx);
BindingNames names(cx);
if (!src->bindings.getLocalNameArray(cx, &names))
return false;
JSScript *newScript;
if (!XDRScript(&decoder, &newScript, NULL))
for (unsigned i = 0; i < names.length(); ++i) {
if (JSAtom *atom = names[i].maybeAtom) {
if (!bindings.add(cx, RootedVarAtom(cx, atom), names[i].kind))
return false;
} else {
uint16_t _;
if (!bindings.addDestructuring(cx, &_))
return false;
}
}
if (!bindings.ensureShape(cx))
return false;
bindings.makeImmutable();
/* Objects */
AutoObjectVector objects(cx);
if (nobjects != 0) {
HeapPtrObject *vector = src->objects()->vector;
for (unsigned i = 0; i < nobjects; i++) {
JSObject *clone = vector[i]->isStaticBlock()
? CloneStaticBlockObject(cx, vector[i]->asStaticBlock(), objects, src)
: CloneInterpretedFunction(cx, vector[i]->toFunction());
if (!clone || !objects.append(clone))
return false;
}
}
/* RegExps */
AutoObjectVector regexps(cx);
for (unsigned i = 0; i < nregexps; i++) {
HeapPtrObject *vector = src->regexps()->vector;
for (unsigned i = 0; i < nregexps; i++) {
JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->asRegExp());
if (!clone || !regexps.append(clone))
return false;
}
}
/* Now that all fallible allocation is complete, create the GC thing. */
JSScript *dst = js_NewGCScript(cx);
if (!dst) {
Foreground::free_(data);
return NULL;
}
return newScript;
PodZero(dst);
new (&dst->bindings) Bindings(cx);
dst->bindings.transfer(cx, &bindings);
/* This assignment must occur before all the Rebase calls. */
dst->data = data;
memcpy(data, src->data, size);
dst->code = Rebase<jsbytecode>(dst, src, src->code);
/* Script filenames are runtime-wide. */
dst->filename = src->filename;
/* Atoms are runtime-wide. */
if (src->natoms != 0)
dst->atoms = Rebase<HeapPtrAtom>(dst, src, src->atoms);
dst->principals = cx->compartment->principals;
if (dst->principals)
JS_HoldPrincipals(dst->principals);
/* Establish invariant: principals implies originPrincipals. */
dst->originPrincipals = src->originPrincipals;
if (!dst->originPrincipals)
dst->originPrincipals = dst->principals;
if (dst->originPrincipals)
JS_HoldPrincipals(dst->originPrincipals);
dst->length = src->length;
dst->lineno = src->lineno;
dst->mainOffset = src->mainOffset;
dst->natoms = src->natoms;
dst->setVersion(src->getVersion());
dst->nfixed = src->nfixed;
dst->nTypeSets = src->nTypeSets;
dst->nslots = src->nslots;
dst->staticLevel = src->staticLevel;
if (src->argumentsHasLocalBinding()) {
dst->setArgumentsHasLocalBinding(src->argumentsLocalSlot());
if (src->analyzedArgsUsage())
dst->setNeedsArgsObj(src->needsArgsObj());
}
dst->constsOffset = src->constsOffset;
dst->objectsOffset = src->objectsOffset;
dst->regexpsOffset = src->regexpsOffset;
dst->trynotesOffset = src->trynotesOffset;
dst->globalsOffset = src->globalsOffset;
dst->closedArgsOffset = src->closedArgsOffset;
dst->closedVarsOffset = src->closedVarsOffset;
dst->noScriptRval = src->noScriptRval;
dst->savedCallerFun = src->savedCallerFun;
dst->strictModeCode = src->strictModeCode;
dst->compileAndGo = src->compileAndGo;
dst->bindingsAccessedDynamically = src->bindingsAccessedDynamically;
dst->hasSingletons = src->hasSingletons;
dst->isGenerator = src->isGenerator;
/*
* initScriptCounts updates scriptCountsMap if necessary. The other script
* maps in JSCompartment are populated lazily.
*/
if (cx->hasRunOption(JSOPTION_PCCOUNT))
(void) dst->initScriptCounts(cx);
if (nconsts != 0) {
HeapValue *vector = Rebase<HeapValue>(dst, src, src->consts()->vector);
dst->consts()->vector = vector;
for (unsigned i = 0; i < nconsts; ++i)
JS_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom());
}
if (nobjects != 0) {
HeapPtrObject *vector = Rebase<HeapPtr<JSObject> >(dst, src, src->objects()->vector);
dst->objects()->vector = vector;
for (unsigned i = 0; i < nobjects; ++i)
vector[i].init(objects[i]);
}
if (nregexps != 0) {
HeapPtrObject *vector = Rebase<HeapPtr<JSObject> >(dst, src, src->regexps()->vector);
dst->regexps()->vector = vector;
for (unsigned i = 0; i < nregexps; ++i)
vector[i].init(regexps[i]);
}
if (ntrynotes != 0)
dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
if (nClosedArgs != 0)
dst->closedArgs()->vector = Rebase<uint32_t>(dst, src, src->closedArgs()->vector);
if (nClosedVars != 0)
dst->closedVars()->vector = Rebase<uint32_t>(dst, src, src->closedVars()->vector);
JS_ASSERT(nglobals == 0);
return dst;
}
DebugScript *

View File

@ -110,6 +110,13 @@ struct Shape;
enum BindingKind { NONE, ARGUMENT, VARIABLE, CONSTANT };
struct BindingName {
JSAtom *maybeAtom;
BindingKind kind;
};
typedef Vector<BindingName, 32> BindingNames;
/*
* Formal parameters and local variables are stored in a shape tree
* path encapsulated within this class. This class represents bindings for
@ -238,7 +245,7 @@ class Bindings
* The name at an element will be null when the element is for an argument
* corresponding to a destructuring pattern.
*/
bool getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp);
bool getLocalNameArray(JSContext *cx, BindingNames *namesp);
/*
* Protect stored bindings from mutation. Subsequent attempts to add
@ -585,6 +592,8 @@ struct JSScript : public js::gc::Cell
JSVersion version);
static JSScript *NewScriptFromEmitter(JSContext *cx, js::BytecodeEmitter *bce);
void setVersion(JSVersion v) { version = v; }
/* See TCF_ARGUMENTS_HAS_LOCAL_BINDING comment. */
bool argumentsHasLocalBinding() const { return argsHasLocalBinding_; }
jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; }

View File

@ -3676,12 +3676,12 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp)
JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
if (fun->nargs > 0) {
Vector<JSAtom *> names(cx);
BindingNames names(cx);
if (!fun->script()->bindings.getLocalNameArray(cx, &names))
return false;
for (size_t i = 0; i < fun->nargs; i++) {
JSAtom *name = names[i];
JSAtom *name = names[i].maybeAtom;
result->setDenseArrayElement(i, name ? StringValue(name) : UndefinedValue());
}
}

View File

@ -762,6 +762,8 @@ template<XDRMode mode>
bool
js::XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp)
{
/* NB: Keep this in sync with CloneScriptRegExpObject. */
RootedVarAtom source(xdr->cx());
uint32_t flagsword = 0;
@ -793,3 +795,19 @@ js::XDRScriptRegExpObject(XDRState<XDR_ENCODE> *xdr, HeapPtrObject *objp);
template bool
js::XDRScriptRegExpObject(XDRState<XDR_DECODE> *xdr, HeapPtrObject *objp);
JSObject *
js::CloneScriptRegExpObject(JSContext *cx, RegExpObject &reobj)
{
/* NB: Keep this in sync with XDRScriptRegExpObject. */
RootedVarAtom source(cx, reobj.getSource());
RegExpObject *clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), NULL);
if (!clone)
return NULL;
if (!clone->clearParent(cx))
return false;
if (!clone->clearType(cx))
return false;
return clone;
}

View File

@ -474,6 +474,9 @@ template<XDRMode mode>
bool
XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp);
extern JSObject *
CloneScriptRegExpObject(JSContext *cx, RegExpObject &re);
} /* namespace js */
#endif

View File

@ -877,18 +877,23 @@ Class js::BlockClass = {
#define NO_PARENT_INDEX UINT32_MAX
/*
* If there's a parent id, then get the parent out of our script's object
* array. We know that we clone block objects in outer-to-inner order, which
* means that getting the parent now will work.
*/
static uint32_t
FindObjectIndex(ObjectArray *array, JSObject *obj)
FindObjectIndex(JSScript *script, StaticBlockObject *maybeBlock)
{
size_t i;
if (!maybeBlock || !JSScript::isValidOffset(script->objectsOffset))
return NO_PARENT_INDEX;
if (array) {
i = array->length;
do {
if (array->vector[--i] == obj)
return i;
} while (i != 0);
ObjectArray *objects = script->objects();
HeapPtrObject *vector = objects->vector;
unsigned length = objects->length;
for (unsigned i = 0; i < length; ++i) {
if (vector[i] == maybeBlock)
return i;
}
return NO_PARENT_INDEX;
@ -898,6 +903,8 @@ template<XDRMode mode>
bool
js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp)
{
/* NB: Keep this in sync with CloneStaticBlockObject. */
JSContext *cx = xdr->cx();
StaticBlockObject *obj = NULL;
@ -906,9 +913,7 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObjec
uint32_t depthAndCount = 0;
if (mode == XDR_ENCODE) {
obj = *objp;
parentId = script->hasObjects()
? FindObjectIndex(script->objects(), obj->enclosingBlock())
: NO_PARENT_INDEX;
parentId = FindObjectIndex(script, obj->enclosingBlock());
uint32_t depth = obj->stackDepth();
JS_ASSERT(depth <= UINT16_MAX);
count = obj->slotCount();
@ -926,11 +931,6 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObjec
return false;
*objp = obj;
/*
* If there's a parent id, then get the parent out of our script's
* object array. We know that we XDR block object in outer-to-inner
* order, which means that getting the parent now will work.
*/
obj->setEnclosingBlock(parentId == NO_PARENT_INDEX
? NULL
: &script->getObject(parentId)->asStaticBlock());
@ -975,7 +975,8 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObjec
}
} else {
AutoShapeVector shapes(cx);
shapes.growBy(count);
if (!shapes.growBy(count))
return false;
for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
const Shape *shape = &r.front();
@ -1015,3 +1016,43 @@ js::XDRStaticBlockObject(XDRState<XDR_ENCODE> *xdr, JSScript *script, StaticBloc
template bool
js::XDRStaticBlockObject(XDRState<XDR_DECODE> *xdr, JSScript *script, StaticBlockObject **objp);
JSObject *
js::CloneStaticBlockObject(JSContext *cx, StaticBlockObject &srcBlock,
const AutoObjectVector &objects, JSScript *src)
{
/* NB: Keep this in sync with XDRStaticBlockObject. */
StaticBlockObject *clone = StaticBlockObject::create(cx);
if (!clone)
return false;
uint32_t parentId = FindObjectIndex(src, srcBlock.enclosingBlock());
clone->setEnclosingBlock(parentId == NO_PARENT_INDEX
? NULL
: &objects[parentId]->asStaticBlock());
clone->setStackDepth(srcBlock.stackDepth());
/* Shape::Range is reverse order, so build a list in forward order. */
AutoShapeVector shapes(cx);
if (!shapes.growBy(srcBlock.slotCount()))
return false;
for (Shape::Range r = srcBlock.lastProperty()->all(); !r.empty(); r.popFront())
shapes[r.front().shortid()] = &r.front();
for (const Shape **p = shapes.begin(); p != shapes.end(); ++p) {
jsid id = (*p)->propid();
unsigned i = (*p)->shortid();
bool redeclared;
if (!clone->addVar(cx, id, i, &redeclared)) {
JS_ASSERT(!redeclared);
return false;
}
clone->setAliased(i, srcBlock.isAliased(i));
}
return clone;
}

View File

@ -299,6 +299,10 @@ template<XDRMode mode>
bool
XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp);
extern JSObject *
CloneStaticBlockObject(JSContext *cx, StaticBlockObject &srcBlock,
const AutoObjectVector &objects, JSScript *src);
} /* namespace js */
#endif /* ScopeObject_h___ */

View File

@ -129,44 +129,6 @@ XDRState<mode>::codeChars(jschar *chars, size_t nchars)
return true;
}
/*
* Convert between a JS (Unicode) string and the XDR representation.
*/
template<XDRMode mode>
bool
XDRState<mode>::codeString(JSString **strp)
{
uint32_t nchars;
jschar *chars;
if (mode == XDR_ENCODE)
nchars = (*strp)->length();
if (!codeUint32(&nchars))
return false;
if (mode == XDR_DECODE)
chars = (jschar *) cx()->malloc_((nchars + 1) * sizeof(jschar));
else
chars = const_cast<jschar *>((*strp)->getChars(cx()));
if (!chars)
return false;
if (!codeChars(chars, nchars))
goto bad;
if (mode == XDR_DECODE) {
chars[nchars] = 0;
*strp = JS_NewUCString(cx(), chars, nchars);
if (!*strp)
goto bad;
}
return true;
bad:
if (mode == XDR_DECODE)
Foreground::free_(chars);
return false;
}
template<XDRMode mode>
static bool
VersionCheck(XDRState<mode> *xdr)

View File

@ -57,7 +57,7 @@ namespace js {
* and saved versions. If deserialization fails, the data should be
* invalidated if possible.
*/
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 114);
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 115);
class XDRBuffer {
public:
@ -287,7 +287,6 @@ class XDRState {
}
bool codeChars(jschar *chars, size_t nchars);
bool codeString(JSString **strp);
bool codeFunction(JSObject **objp);
bool codeScript(JSScript **scriptp);