mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-02 06:22:20 +00:00
Merge mozilla-central into mozilla-inbound on a CLOSED TREE
This commit is contained in:
commit
4c2155d99e
@ -375,12 +375,12 @@ frontend::CompileFunctionBody(JSContext *cx, JSFunction *fun,
|
|||||||
* NB: do not use AutoLocalNameArray because it will release space
|
* NB: do not use AutoLocalNameArray because it will release space
|
||||||
* allocated from cx->tempLifoAlloc by DefineArg.
|
* allocated from cx->tempLifoAlloc by DefineArg.
|
||||||
*/
|
*/
|
||||||
Vector<JSAtom *> names(cx);
|
BindingNames names(cx);
|
||||||
if (!funbce.bindings.getLocalNameArray(cx, &names)) {
|
if (!funbce.bindings.getLocalNameArray(cx, &names)) {
|
||||||
fn = NULL;
|
fn = NULL;
|
||||||
} else {
|
} else {
|
||||||
for (unsigned i = 0; i < nargs; i++) {
|
for (unsigned i = 0; i < nargs; i++) {
|
||||||
if (!DefineArg(fn, names[i], i, &funbce)) {
|
if (!DefineArg(fn, names[i].maybeAtom, i, &funbce)) {
|
||||||
fn = NULL;
|
fn = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -544,7 +544,7 @@ class GCConstList {
|
|||||||
Vector<Value> list;
|
Vector<Value> list;
|
||||||
public:
|
public:
|
||||||
GCConstList(JSContext *cx) : list(cx) {}
|
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(); }
|
size_t length() const { return list.length(); }
|
||||||
void finish(ConstArray *array);
|
void finish(ConstArray *array);
|
||||||
};
|
};
|
||||||
|
24
js/src/jit-test/tests/basic/testScriptCloning.js
Normal file
24
js/src/jit-test/tests/basic/testScriptCloning.js
Normal 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);
|
@ -667,14 +667,18 @@ bool
|
|||||||
js::XDRAtom(XDRState<mode> *xdr, JSAtom **atomp)
|
js::XDRAtom(XDRState<mode> *xdr, JSAtom **atomp)
|
||||||
{
|
{
|
||||||
if (mode == XDR_ENCODE) {
|
if (mode == XDR_ENCODE) {
|
||||||
JSString *str = *atomp;
|
uint32_t nchars = (*atomp)->length();
|
||||||
return xdr->codeString(&str);
|
if (!xdr->codeUint32(&nchars))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
jschar *chars = const_cast<jschar *>((*atomp)->getChars(xdr->cx()));
|
||||||
|
if (!chars)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return xdr->codeChars(chars, nchars);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Avoid JSString allocation for already existing atoms. See bug 321985. */
|
||||||
* Inline XDRState::codeString when decoding to avoid JSString allocation
|
|
||||||
* for already existing atoms. See bug 321985.
|
|
||||||
*/
|
|
||||||
uint32_t nchars;
|
uint32_t nchars;
|
||||||
if (!xdr->codeUint32(&nchars))
|
if (!xdr->codeUint32(&nchars))
|
||||||
return false;
|
return false;
|
||||||
|
@ -436,7 +436,7 @@ JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun)
|
|||||||
extern JS_PUBLIC_API(uintptr_t *)
|
extern JS_PUBLIC_API(uintptr_t *)
|
||||||
JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp)
|
JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp)
|
||||||
{
|
{
|
||||||
Vector<JSAtom *> localNames(cx);
|
BindingNames localNames(cx);
|
||||||
if (!fun->script()->bindings.getLocalNameArray(cx, &localNames))
|
if (!fun->script()->bindings.getLocalNameArray(cx, &localNames))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -449,15 +449,16 @@ JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(sizeof(*names) == sizeof(*localNames.begin()));
|
for (size_t i = 0; i < localNames.length(); i++)
|
||||||
js_memcpy(names, localNames.begin(), localNames.length() * sizeof(*names));
|
names[i] = reinterpret_cast<uintptr_t>(localNames[i].maybeAtom);
|
||||||
|
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSAtom *)
|
extern JS_PUBLIC_API(JSAtom *)
|
||||||
JS_LocalNameToAtom(uintptr_t w)
|
JS_LocalNameToAtom(uintptr_t w)
|
||||||
{
|
{
|
||||||
return JS_LOCAL_NAME_TO_ATOM(w);
|
return reinterpret_cast<JSAtom *>(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSString *)
|
extern JS_PUBLIC_API(JSString *)
|
||||||
|
@ -374,6 +374,7 @@ template<XDRMode mode>
|
|||||||
bool
|
bool
|
||||||
js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript)
|
js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript)
|
||||||
{
|
{
|
||||||
|
/* NB: Keep this in sync with CloneInterpretedFunction. */
|
||||||
JSFunction *fun;
|
JSFunction *fun;
|
||||||
JSAtom *atom;
|
JSAtom *atom;
|
||||||
uint32_t firstword; /* flag telling whether fun->atom is non-null,
|
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
|
template bool
|
||||||
js::XDRInterpretedFunction(XDRState<XDR_DECODE> *xdr, JSObject **objp, JSScript *parentScript);
|
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
|
* [[HasInstance]] internal method for Function objects: fetch the .prototype
|
||||||
* property of its 'this' parameter, and walks the prototype chain of v (only
|
* property of its 'this' parameter, and walks the prototype chain of v (only
|
||||||
|
@ -121,9 +121,6 @@ struct JSFunction : public JSObject
|
|||||||
/* uint16_t representation bounds number of call object dynamic slots. */
|
/* uint16_t representation bounds number of call object dynamic slots. */
|
||||||
enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
|
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
|
* For an interpreted function, accessors for the initial scope object of
|
||||||
* activations (stack frames) of the function.
|
* activations (stack frames) of the function.
|
||||||
@ -314,6 +311,9 @@ template<XDRMode mode>
|
|||||||
bool
|
bool
|
||||||
XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript);
|
XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript);
|
||||||
|
|
||||||
|
extern JSObject *
|
||||||
|
CloneInterpretedFunction(JSContext *cx, JSFunction *fun);
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
|
@ -1091,7 +1091,7 @@ struct JSPrinter
|
|||||||
jsbytecode *dvgfence; /* DecompileExpression fencepost */
|
jsbytecode *dvgfence; /* DecompileExpression fencepost */
|
||||||
jsbytecode **pcstack; /* DecompileExpression modeled stack */
|
jsbytecode **pcstack; /* DecompileExpression modeled stack */
|
||||||
JSFunction *fun; /* interpreted function */
|
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 */
|
Vector<DecompiledOpcode> *decompiledOpcodes; /* optional state for decompiled ops */
|
||||||
|
|
||||||
DecompiledOpcode &decompiled(jsbytecode *pc) {
|
DecompiledOpcode &decompiled(jsbytecode *pc) {
|
||||||
@ -1122,7 +1122,7 @@ js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun,
|
|||||||
jp->localNames = NULL;
|
jp->localNames = NULL;
|
||||||
jp->decompiledOpcodes = NULL;
|
jp->decompiledOpcodes = NULL;
|
||||||
if (fun && fun->isInterpreted() && fun->script()->bindings.count() > 0) {
|
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)) {
|
if (!jp->localNames || !fun->script()->bindings.getLocalNameArray(cx, jp->localNames)) {
|
||||||
js_DestroyPrinter(jp);
|
js_DestroyPrinter(jp);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1771,7 +1771,7 @@ GetArgOrVarAtom(JSPrinter *jp, unsigned slot)
|
|||||||
{
|
{
|
||||||
LOCAL_ASSERT_RV(jp->fun, NULL);
|
LOCAL_ASSERT_RV(jp->fun, NULL);
|
||||||
LOCAL_ASSERT_RV(slot < jp->fun->script()->bindings.count(), 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
|
#if !JS_HAS_DESTRUCTURING
|
||||||
LOCAL_ASSERT_RV(name, NULL);
|
LOCAL_ASSERT_RV(name, NULL);
|
||||||
#endif
|
#endif
|
||||||
@ -4667,8 +4667,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
|
|||||||
#if JS_HAS_GENERATOR_EXPRS
|
#if JS_HAS_GENERATOR_EXPRS
|
||||||
sn = js_GetSrcNote(jp->script, pc);
|
sn = js_GetSrcNote(jp->script, pc);
|
||||||
if (sn && SN_TYPE(sn) == SRC_GENEXP) {
|
if (sn && SN_TYPE(sn) == SRC_GENEXP) {
|
||||||
Vector<JSAtom *> *innerLocalNames;
|
BindingNames *innerLocalNames;
|
||||||
Vector<JSAtom *> *outerLocalNames;
|
BindingNames *outerLocalNames;
|
||||||
JSScript *inner, *outer;
|
JSScript *inner, *outer;
|
||||||
Vector<DecompiledOpcode> *decompiledOpcodes;
|
Vector<DecompiledOpcode> *decompiledOpcodes;
|
||||||
SprintStack ss2(cx);
|
SprintStack ss2(cx);
|
||||||
@ -4684,7 +4684,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
|
|||||||
*/
|
*/
|
||||||
LifoAllocScope las(&cx->tempLifoAlloc());
|
LifoAllocScope las(&cx->tempLifoAlloc());
|
||||||
if (fun->script()->bindings.count() > 0) {
|
if (fun->script()->bindings.count() > 0) {
|
||||||
innerLocalNames = cx->new_<Vector<JSAtom *> >(cx);
|
innerLocalNames = cx->new_<BindingNames>(cx);
|
||||||
if (!innerLocalNames ||
|
if (!innerLocalNames ||
|
||||||
!fun->script()->bindings.getLocalNameArray(cx, innerLocalNames))
|
!fun->script()->bindings.getLocalNameArray(cx, innerLocalNames))
|
||||||
{
|
{
|
||||||
|
@ -76,6 +76,8 @@
|
|||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
|
||||||
|
#include "vm/RegExpObject-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
using namespace js::frontend;
|
using namespace js::frontend;
|
||||||
@ -214,12 +216,13 @@ Bindings::callObjectShape(JSContext *cx) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
|
Bindings::getLocalNameArray(JSContext *cx, BindingNames *namesp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(lastBinding);
|
JS_ASSERT(lastBinding);
|
||||||
JS_ASSERT(count() > 0);
|
if (count() == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
Vector<JSAtom *> &names = *namesp;
|
BindingNames &names = *namesp;
|
||||||
JS_ASSERT(names.empty());
|
JS_ASSERT(names.empty());
|
||||||
|
|
||||||
unsigned n = count();
|
unsigned n = count();
|
||||||
@ -229,7 +232,7 @@ Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSAtom * const POISON = reinterpret_cast<JSAtom *>(0xdeadbeef);
|
JSAtom * const POISON = reinterpret_cast<JSAtom *>(0xdeadbeef);
|
||||||
for (unsigned i = 0; i < n; i++)
|
for (unsigned i = 0; i < n; i++)
|
||||||
names[i] = POISON;
|
names[i].maybeAtom = POISON;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (Shape::Range r = lastBinding->all(); !r.empty(); r.popFront()) {
|
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) {
|
if (shape.getter() == CallObject::getArgOp) {
|
||||||
JS_ASSERT(index < nargs);
|
JS_ASSERT(index < nargs);
|
||||||
|
names[index].kind = ARGUMENT;
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(index < nvars);
|
JS_ASSERT(index < nvars);
|
||||||
index += nargs;
|
index += nargs;
|
||||||
|
names[index].kind = shape.writable() ? VARIABLE : CONSTANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSID_IS_ATOM(shape.propid())) {
|
if (JSID_IS_ATOM(shape.propid())) {
|
||||||
names[index] = JSID_TO_ATOM(shape.propid());
|
names[index].maybeAtom = JSID_TO_ATOM(shape.propid());
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(JSID_IS_INT(shape.propid()));
|
JS_ASSERT(JSID_IS_INT(shape.propid()));
|
||||||
JS_ASSERT(shape.getter() == CallObject::getArgOp);
|
JS_ASSERT(shape.getter() == CallObject::getArgOp);
|
||||||
names[index] = NULL;
|
names[index].maybeAtom = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for (unsigned i = 0; i < n; i++)
|
for (unsigned i = 0; i < n; i++)
|
||||||
JS_ASSERT(names[i] != POISON);
|
JS_ASSERT(names[i].maybeAtom != POISON);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -308,7 +313,7 @@ XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp)
|
|||||||
enum ConstTag {
|
enum ConstTag {
|
||||||
SCRIPT_INT = 0,
|
SCRIPT_INT = 0,
|
||||||
SCRIPT_DOUBLE = 1,
|
SCRIPT_DOUBLE = 1,
|
||||||
SCRIPT_STRING = 2,
|
SCRIPT_ATOM = 2,
|
||||||
SCRIPT_TRUE = 3,
|
SCRIPT_TRUE = 3,
|
||||||
SCRIPT_FALSE = 4,
|
SCRIPT_FALSE = 4,
|
||||||
SCRIPT_NULL = 5,
|
SCRIPT_NULL = 5,
|
||||||
@ -322,7 +327,7 @@ XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp)
|
|||||||
} else if (vp->isDouble()) {
|
} else if (vp->isDouble()) {
|
||||||
tag = SCRIPT_DOUBLE;
|
tag = SCRIPT_DOUBLE;
|
||||||
} else if (vp->isString()) {
|
} else if (vp->isString()) {
|
||||||
tag = SCRIPT_STRING;
|
tag = SCRIPT_ATOM;
|
||||||
} else if (vp->isTrue()) {
|
} else if (vp->isTrue()) {
|
||||||
tag = SCRIPT_TRUE;
|
tag = SCRIPT_TRUE;
|
||||||
} else if (vp->isFalse()) {
|
} else if (vp->isFalse()) {
|
||||||
@ -359,14 +364,14 @@ XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp)
|
|||||||
vp->init(DoubleValue(d));
|
vp->init(DoubleValue(d));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCRIPT_STRING: {
|
case SCRIPT_ATOM: {
|
||||||
JSString *str;
|
JSAtom *atom;
|
||||||
if (mode == XDR_ENCODE)
|
if (mode == XDR_ENCODE)
|
||||||
str = vp->toString();
|
atom = &vp->toString()->asAtom();
|
||||||
if (!xdr->codeString(&str))
|
if (!XDRAtom(xdr, &atom))
|
||||||
return false;
|
return false;
|
||||||
if (mode == XDR_DECODE)
|
if (mode == XDR_DECODE)
|
||||||
vp->init(StringValue(str));
|
vp->init(StringValue(atom));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCRIPT_TRUE:
|
case SCRIPT_TRUE:
|
||||||
@ -393,6 +398,8 @@ template<XDRMode mode>
|
|||||||
bool
|
bool
|
||||||
js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
|
js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
|
||||||
{
|
{
|
||||||
|
/* NB: Keep this in sync with CloneScript. */
|
||||||
|
|
||||||
enum ScriptBits {
|
enum ScriptBits {
|
||||||
NoScriptRval,
|
NoScriptRval,
|
||||||
SavedCallerFun,
|
SavedCallerFun,
|
||||||
@ -465,13 +472,13 @@ js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<JSAtom *> names(cx);
|
BindingNames names(cx);
|
||||||
if (mode == XDR_ENCODE) {
|
if (mode == XDR_ENCODE) {
|
||||||
if (!script->bindings.getLocalNameArray(cx, &names))
|
if (!script->bindings.getLocalNameArray(cx, &names))
|
||||||
return false;
|
return false;
|
||||||
PodZero(bitmap, bitmapLength);
|
PodZero(bitmap, bitmapLength);
|
||||||
for (unsigned i = 0; i < nameCount; i++) {
|
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));
|
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))
|
if (!bindings.addDestructuring(cx, &dummy))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(!names[i]);
|
JS_ASSERT(!names[i].maybeAtom);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedVarAtom name(cx);
|
RootedVarAtom name(cx);
|
||||||
if (mode == XDR_ENCODE)
|
if (mode == XDR_ENCODE)
|
||||||
name = names[i];
|
name = names[i].maybeAtom;
|
||||||
if (!XDRAtom(xdr, name.address()))
|
if (!XDRAtom(xdr, name.address()))
|
||||||
return false;
|
return false;
|
||||||
if (mode == XDR_DECODE) {
|
if (mode == XDR_DECODE) {
|
||||||
@ -1120,11 +1127,10 @@ JS_STATIC_ASSERT(sizeof(ConstArray) +
|
|||||||
< JSScript::INVALID_OFFSET);
|
< JSScript::INVALID_OFFSET);
|
||||||
JS_STATIC_ASSERT(JSScript::INVALID_OFFSET <= 255);
|
JS_STATIC_ASSERT(JSScript::INVALID_OFFSET <= 255);
|
||||||
|
|
||||||
JSScript *
|
static inline size_t
|
||||||
JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
|
ScriptDataSize(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
|
||||||
uint32_t nobjects, uint32_t nregexps,
|
uint32_t nobjects, uint32_t nregexps, uint32_t ntrynotes, uint32_t nconsts,
|
||||||
uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals,
|
uint32_t nglobals, uint16_t nClosedArgs, uint16_t nClosedVars)
|
||||||
uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets, JSVersion version)
|
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
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 += length * sizeof(jsbytecode);
|
||||||
size += nsrcnotes * sizeof(jssrcnote);
|
size += nsrcnotes * sizeof(jssrcnote);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
static inline uint8_t *
|
||||||
* We assume that calloc aligns on sizeof(Value) if the size we ask to
|
AllocScriptData(JSContext *cx, size_t size)
|
||||||
* allocate divides sizeof(Value).
|
{
|
||||||
*/
|
|
||||||
JS_STATIC_ASSERT(sizeof(Value) == sizeof(double));
|
|
||||||
uint8_t *data = static_cast<uint8_t *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
|
uint8_t *data = static_cast<uint8_t *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
|
||||||
if (!data)
|
if (!data)
|
||||||
return NULL;
|
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);
|
JSScript *script = js_NewGCScript(cx);
|
||||||
if (!script) {
|
if (!script) {
|
||||||
Foreground::free_(data);
|
Foreground::free_(data);
|
||||||
@ -1449,6 +1472,10 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
|
|||||||
Debugger::onNewScript(cx, script, compileAndGoGlobal);
|
Debugger::onNewScript(cx, script, compileAndGoGlobal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initScriptCounts updates scriptCountsMap if necessary. The other script
|
||||||
|
* maps in JSCompartment are populated lazily.
|
||||||
|
*/
|
||||||
if (cx->hasRunOption(JSOPTION_PCCOUNT))
|
if (cx->hasRunOption(JSOPTION_PCCOUNT))
|
||||||
(void) script->initScriptCounts(cx);
|
(void) script->initScriptCounts(cx);
|
||||||
|
|
||||||
@ -1738,28 +1765,186 @@ CurrentScriptFileLineOriginSlow(JSContext *cx, const char **file, unsigned *line
|
|||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
JSScript *
|
template <class T>
|
||||||
js::CloneScript(JSContext *cx, JSScript *script)
|
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. */
|
JSScript *
|
||||||
XDREncoder encoder(cx);
|
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;
|
return NULL;
|
||||||
|
|
||||||
uint32_t nbytes;
|
/* Bindings */
|
||||||
const void *p = encoder.getData(&nbytes);
|
|
||||||
|
|
||||||
/* De-serialize script. */
|
Bindings bindings(cx);
|
||||||
XDRDecoder decoder(cx, p, nbytes, cx->compartment->principals, script->originPrincipals);
|
BindingNames names(cx);
|
||||||
|
if (!src->bindings.getLocalNameArray(cx, &names))
|
||||||
|
return false;
|
||||||
|
|
||||||
JSScript *newScript;
|
for (unsigned i = 0; i < names.length(); ++i) {
|
||||||
if (!XDRScript(&decoder, &newScript, NULL))
|
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 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 *
|
DebugScript *
|
||||||
|
@ -110,6 +110,13 @@ struct Shape;
|
|||||||
|
|
||||||
enum BindingKind { NONE, ARGUMENT, VARIABLE, CONSTANT };
|
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
|
* Formal parameters and local variables are stored in a shape tree
|
||||||
* path encapsulated within this class. This class represents bindings for
|
* 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
|
* The name at an element will be null when the element is for an argument
|
||||||
* corresponding to a destructuring pattern.
|
* 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
|
* Protect stored bindings from mutation. Subsequent attempts to add
|
||||||
@ -585,6 +592,8 @@ struct JSScript : public js::gc::Cell
|
|||||||
JSVersion version);
|
JSVersion version);
|
||||||
static JSScript *NewScriptFromEmitter(JSContext *cx, js::BytecodeEmitter *bce);
|
static JSScript *NewScriptFromEmitter(JSContext *cx, js::BytecodeEmitter *bce);
|
||||||
|
|
||||||
|
void setVersion(JSVersion v) { version = v; }
|
||||||
|
|
||||||
/* See TCF_ARGUMENTS_HAS_LOCAL_BINDING comment. */
|
/* See TCF_ARGUMENTS_HAS_LOCAL_BINDING comment. */
|
||||||
bool argumentsHasLocalBinding() const { return argsHasLocalBinding_; }
|
bool argumentsHasLocalBinding() const { return argsHasLocalBinding_; }
|
||||||
jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; }
|
jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; }
|
||||||
|
@ -3676,12 +3676,12 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
|
JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
|
||||||
|
|
||||||
if (fun->nargs > 0) {
|
if (fun->nargs > 0) {
|
||||||
Vector<JSAtom *> names(cx);
|
BindingNames names(cx);
|
||||||
if (!fun->script()->bindings.getLocalNameArray(cx, &names))
|
if (!fun->script()->bindings.getLocalNameArray(cx, &names))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (size_t i = 0; i < fun->nargs; i++) {
|
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());
|
result->setDenseArrayElement(i, name ? StringValue(name) : UndefinedValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -762,6 +762,8 @@ template<XDRMode mode>
|
|||||||
bool
|
bool
|
||||||
js::XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp)
|
js::XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp)
|
||||||
{
|
{
|
||||||
|
/* NB: Keep this in sync with CloneScriptRegExpObject. */
|
||||||
|
|
||||||
RootedVarAtom source(xdr->cx());
|
RootedVarAtom source(xdr->cx());
|
||||||
uint32_t flagsword = 0;
|
uint32_t flagsword = 0;
|
||||||
|
|
||||||
@ -793,3 +795,19 @@ js::XDRScriptRegExpObject(XDRState<XDR_ENCODE> *xdr, HeapPtrObject *objp);
|
|||||||
|
|
||||||
template bool
|
template bool
|
||||||
js::XDRScriptRegExpObject(XDRState<XDR_DECODE> *xdr, HeapPtrObject *objp);
|
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;
|
||||||
|
}
|
||||||
|
@ -474,6 +474,9 @@ template<XDRMode mode>
|
|||||||
bool
|
bool
|
||||||
XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp);
|
XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp);
|
||||||
|
|
||||||
|
extern JSObject *
|
||||||
|
CloneScriptRegExpObject(JSContext *cx, RegExpObject &re);
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -877,18 +877,23 @@ Class js::BlockClass = {
|
|||||||
|
|
||||||
#define NO_PARENT_INDEX UINT32_MAX
|
#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
|
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) {
|
ObjectArray *objects = script->objects();
|
||||||
i = array->length;
|
HeapPtrObject *vector = objects->vector;
|
||||||
do {
|
unsigned length = objects->length;
|
||||||
|
for (unsigned i = 0; i < length; ++i) {
|
||||||
if (array->vector[--i] == obj)
|
if (vector[i] == maybeBlock)
|
||||||
return i;
|
return i;
|
||||||
} while (i != 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NO_PARENT_INDEX;
|
return NO_PARENT_INDEX;
|
||||||
@ -898,6 +903,8 @@ template<XDRMode mode>
|
|||||||
bool
|
bool
|
||||||
js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp)
|
js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp)
|
||||||
{
|
{
|
||||||
|
/* NB: Keep this in sync with CloneStaticBlockObject. */
|
||||||
|
|
||||||
JSContext *cx = xdr->cx();
|
JSContext *cx = xdr->cx();
|
||||||
|
|
||||||
StaticBlockObject *obj = NULL;
|
StaticBlockObject *obj = NULL;
|
||||||
@ -906,9 +913,7 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObjec
|
|||||||
uint32_t depthAndCount = 0;
|
uint32_t depthAndCount = 0;
|
||||||
if (mode == XDR_ENCODE) {
|
if (mode == XDR_ENCODE) {
|
||||||
obj = *objp;
|
obj = *objp;
|
||||||
parentId = script->hasObjects()
|
parentId = FindObjectIndex(script, obj->enclosingBlock());
|
||||||
? FindObjectIndex(script->objects(), obj->enclosingBlock())
|
|
||||||
: NO_PARENT_INDEX;
|
|
||||||
uint32_t depth = obj->stackDepth();
|
uint32_t depth = obj->stackDepth();
|
||||||
JS_ASSERT(depth <= UINT16_MAX);
|
JS_ASSERT(depth <= UINT16_MAX);
|
||||||
count = obj->slotCount();
|
count = obj->slotCount();
|
||||||
@ -926,11 +931,6 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObjec
|
|||||||
return false;
|
return false;
|
||||||
*objp = obj;
|
*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
|
obj->setEnclosingBlock(parentId == NO_PARENT_INDEX
|
||||||
? NULL
|
? NULL
|
||||||
: &script->getObject(parentId)->asStaticBlock());
|
: &script->getObject(parentId)->asStaticBlock());
|
||||||
@ -975,7 +975,8 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObjec
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AutoShapeVector shapes(cx);
|
AutoShapeVector shapes(cx);
|
||||||
shapes.growBy(count);
|
if (!shapes.growBy(count))
|
||||||
|
return false;
|
||||||
|
|
||||||
for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
|
for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
|
||||||
const Shape *shape = &r.front();
|
const Shape *shape = &r.front();
|
||||||
@ -1015,3 +1016,43 @@ js::XDRStaticBlockObject(XDRState<XDR_ENCODE> *xdr, JSScript *script, StaticBloc
|
|||||||
|
|
||||||
template bool
|
template bool
|
||||||
js::XDRStaticBlockObject(XDRState<XDR_DECODE> *xdr, JSScript *script, StaticBlockObject **objp);
|
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;
|
||||||
|
}
|
||||||
|
@ -299,6 +299,10 @@ template<XDRMode mode>
|
|||||||
bool
|
bool
|
||||||
XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp);
|
XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp);
|
||||||
|
|
||||||
|
extern JSObject *
|
||||||
|
CloneStaticBlockObject(JSContext *cx, StaticBlockObject &srcBlock,
|
||||||
|
const AutoObjectVector &objects, JSScript *src);
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* ScopeObject_h___ */
|
#endif /* ScopeObject_h___ */
|
||||||
|
@ -129,44 +129,6 @@ XDRState<mode>::codeChars(jschar *chars, size_t nchars)
|
|||||||
return true;
|
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>
|
template<XDRMode mode>
|
||||||
static bool
|
static bool
|
||||||
VersionCheck(XDRState<mode> *xdr)
|
VersionCheck(XDRState<mode> *xdr)
|
||||||
|
@ -57,7 +57,7 @@ namespace js {
|
|||||||
* and saved versions. If deserialization fails, the data should be
|
* and saved versions. If deserialization fails, the data should be
|
||||||
* invalidated if possible.
|
* 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 {
|
class XDRBuffer {
|
||||||
public:
|
public:
|
||||||
@ -287,7 +287,6 @@ class XDRState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool codeChars(jschar *chars, size_t nchars);
|
bool codeChars(jschar *chars, size_t nchars);
|
||||||
bool codeString(JSString **strp);
|
|
||||||
|
|
||||||
bool codeFunction(JSObject **objp);
|
bool codeFunction(JSObject **objp);
|
||||||
bool codeScript(JSScript **scriptp);
|
bool codeScript(JSScript **scriptp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user