зеркало из https://github.com/mozilla/gecko-dev.git
bug=420399 r=brendan a1.9=blocking1.9 eliminating the pc stack in the interpreter
This commit is contained in:
Родитель
570c37620c
Коммит
a69ef8533a
|
@ -843,91 +843,116 @@ js_ComputeThis(JSContext *cx, JSBool lazy, jsval *argv)
|
|||
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
|
||||
static JSBool
|
||||
NoSuchMethod(JSContext *cx, uintN argc, jsval *vp, uint32 flags)
|
||||
JSClass js_NoSuchMethodClass = {
|
||||
"NoSuchMethod",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_NoSuchMethod),
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
JSObject*
|
||||
js_InitNoSuchMethodClass(JSContext *cx, JSObject* obj)
|
||||
{
|
||||
JSStackFrame *fp;
|
||||
JSObject *thisp, *argsobj;
|
||||
JSAtom *atom;
|
||||
jsval roots[3];
|
||||
JSObject *proto;
|
||||
|
||||
proto = JS_InitClass(cx, obj, NULL, &js_NoSuchMethodClass, NULL, 0, NULL,
|
||||
NULL, NULL, NULL);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
OBJ_SET_PROTO(cx, proto, NULL);
|
||||
return proto;
|
||||
}
|
||||
|
||||
/*
|
||||
* When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of
|
||||
* the base object, we search for the __noSuchMethod__ method in the base.
|
||||
* If it exists, we store the method and the property's id into an object of
|
||||
* NoSuchMethod class and store this object into the callee's stack slot.
|
||||
* Later, js_Invoke will recognise such an object and transfer control to
|
||||
* NoSuchMethod that invokes the method like:
|
||||
*
|
||||
* this.__noSuchMethod__(id, args)
|
||||
*
|
||||
* where id is the name of the method that this invocation attempted to
|
||||
* call by name, and args is an Array containing this invocation's actual
|
||||
* parameters.
|
||||
*/
|
||||
JSBool
|
||||
js_OnUnknownMethod(JSContext *cx, jsval *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
JSTempValueRooter tvr;
|
||||
jsid id;
|
||||
JSBool ok;
|
||||
jsbytecode *pc;
|
||||
|
||||
/*
|
||||
* NB: vp[1] aka |this| may be null still, requiring
|
||||
* js_ComputeGlobalThis.
|
||||
*/
|
||||
JS_ASSERT(JSVAL_IS_PRIMITIVE(vp[0]));
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(vp[1]));
|
||||
fp = cx->fp;
|
||||
|
||||
/* From here on, control must flow through label out: to return. */
|
||||
memset(roots, 0, sizeof roots);
|
||||
JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr);
|
||||
|
||||
thisp = JSVAL_TO_OBJECT(vp[1]);
|
||||
if (!thisp) {
|
||||
thisp = js_ComputeGlobalThis(cx, JS_FALSE, vp + 2);
|
||||
if (!thisp) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
fp->thisp = thisp;
|
||||
}
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
|
||||
obj = JSVAL_TO_OBJECT(vp[1]);
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
|
||||
|
||||
/* From here on, control must flow through label out:. */
|
||||
id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
if (OBJECT_IS_XML(cx, thisp)) {
|
||||
if (OBJECT_IS_XML(cx, obj)) {
|
||||
JSXMLObjectOps *ops;
|
||||
|
||||
ops = (JSXMLObjectOps *) thisp->map->ops;
|
||||
thisp = ops->getMethod(cx, thisp, id, &roots[2]);
|
||||
if (!thisp) {
|
||||
ops = (JSXMLObjectOps *) obj->map->ops;
|
||||
obj = ops->getMethod(cx, obj, id, &tvr.u.value);
|
||||
if (!obj) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
vp[1] = OBJECT_TO_JSVAL(thisp);
|
||||
vp[1] = OBJECT_TO_JSVAL(obj);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ok = OBJ_GET_PROPERTY(cx, thisp, id, &roots[2]);
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &tvr.u.value);
|
||||
if (!ok)
|
||||
goto out;
|
||||
}
|
||||
if (JSVAL_IS_PRIMITIVE(roots[2]))
|
||||
goto not_function;
|
||||
|
||||
pc = (jsbytecode *) vp[-(intN)fp->script->depth];
|
||||
switch ((JSOp) *pc) {
|
||||
case JSOP_NAME:
|
||||
case JSOP_GETPROP:
|
||||
case JSOP_CALLPROP:
|
||||
GET_ATOM_FROM_BYTECODE(fp->script, pc, 0, atom);
|
||||
roots[0] = ATOM_KEY(atom);
|
||||
argsobj = js_NewArrayObject(cx, argc, vp + 2);
|
||||
if (!argsobj) {
|
||||
if (JSVAL_IS_PRIMITIVE(tvr.u.value)) {
|
||||
vp[0] = tvr.u.value;
|
||||
} else {
|
||||
obj = js_NewObject(cx, &js_NoSuchMethodClass, NULL, NULL);
|
||||
if (!obj) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
roots[1] = OBJECT_TO_JSVAL(argsobj);
|
||||
ok = js_InternalInvoke(cx, thisp, roots[2], flags | JSINVOKE_INTERNAL,
|
||||
2, roots, &vp[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto not_function;
|
||||
STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, tvr.u.value);
|
||||
STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE + 1, vp[0]);
|
||||
vp[0] = OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
ok = JS_TRUE;
|
||||
|
||||
out:
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
return ok;
|
||||
}
|
||||
|
||||
not_function:
|
||||
js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
static JSBool
|
||||
NoSuchMethod(JSContext *cx, uintN argc, jsval *vp, uint32 flags)
|
||||
{
|
||||
JSObject *obj, *thisp, *argsobj;
|
||||
jsval fval, idval, args[2];
|
||||
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[0]));
|
||||
obj = JSVAL_TO_OBJECT(vp[0]);
|
||||
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_NoSuchMethodClass);
|
||||
fval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
|
||||
idval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE + 1);
|
||||
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
|
||||
thisp = JSVAL_TO_OBJECT(vp[1]);
|
||||
|
||||
args[0] = idval;
|
||||
argsobj = js_NewArrayObject(cx, argc, vp + 2);
|
||||
if (!argsobj)
|
||||
return JS_FALSE;
|
||||
args[1] = OBJECT_TO_JSVAL(argsobj);
|
||||
return js_InternalInvoke(cx, thisp, fval, flags | JSINVOKE_INTERNAL,
|
||||
2, args, &vp[0]);
|
||||
}
|
||||
|
||||
#endif /* JS_HAS_NO_SUCH_METHOD */
|
||||
|
@ -987,31 +1012,20 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags)
|
|||
mark = JS_ARENA_MARK(&cx->stackPool);
|
||||
v = *vp;
|
||||
|
||||
/*
|
||||
* A callee must be an object reference, unless its 'this' parameter
|
||||
* implements the __noSuchMethod__ method, in which case that method will
|
||||
* be called like so:
|
||||
*
|
||||
* this.__noSuchMethod__(id, args)
|
||||
*
|
||||
* where id is the name of the method that this invocation attempted to
|
||||
* call by name, and args is an Array containing this invocation's actual
|
||||
* parameters.
|
||||
*/
|
||||
if (JSVAL_IS_PRIMITIVE(v)) {
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
if (cx->fp && cx->fp->script && !(flags & JSINVOKE_INTERNAL)) {
|
||||
ok = NoSuchMethod(cx, argc, vp, flags);
|
||||
goto out2;
|
||||
}
|
||||
#endif
|
||||
if (JSVAL_IS_PRIMITIVE(v))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
funobj = JSVAL_TO_OBJECT(v);
|
||||
parent = OBJ_GET_PARENT(cx, funobj);
|
||||
clasp = OBJ_GET_CLASS(cx, funobj);
|
||||
if (clasp != &js_FunctionClass) {
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
if (clasp == &js_NoSuchMethodClass) {
|
||||
ok = NoSuchMethod(cx, argc, vp, flags);
|
||||
goto out2;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Function is inlined, all other classes use object ops. */
|
||||
ops = funobj->map->ops;
|
||||
|
||||
|
@ -2153,8 +2167,6 @@ js_DumpOpMeters()
|
|||
* to a function that may invoke the interpreter. RESTORE_SP must be called
|
||||
* only after return from js_Invoke, because only js_Invoke changes fp->sp.
|
||||
*/
|
||||
#define PUSH(v) (*sp++ = (v))
|
||||
#define POP() (*--sp)
|
||||
#define SAVE_SP(fp) \
|
||||
(JS_ASSERT((fp)->script || !(fp)->spbase || (sp) == (fp)->spbase), \
|
||||
(fp)->sp = sp)
|
||||
|
@ -2171,22 +2183,17 @@ js_DumpOpMeters()
|
|||
#define RESTORE_SP_AND_PC(fp) (RESTORE_SP(fp), pc = (fp)->pc)
|
||||
#define ASSERT_SAVED_SP_AND_PC(fp) JS_ASSERT((fp)->sp == sp && (fp)->pc == pc);
|
||||
|
||||
/*
|
||||
* Push the generating bytecode's pc onto the parallel pc stack that runs
|
||||
* depth slots below the operands.
|
||||
*
|
||||
* NB: PUSH_OPND uses sp, depth, and pc from its lexical environment. See
|
||||
* js_Interpret for these local variables' declarations and uses.
|
||||
*/
|
||||
#define PUSH_OPND(v) (sp[-depth] = (jsval)pc, PUSH(v))
|
||||
#define STORE_OPND(n,v) (sp[(n)-depth] = (jsval)pc, sp[n] = (v))
|
||||
#define PUSH(v) (*sp++ = (v))
|
||||
#define PUSH_OPND(v) PUSH(v)
|
||||
#define STORE_OPND(n,v) (sp[n] = (v))
|
||||
#define POP() (*--sp)
|
||||
#define POP_OPND() POP()
|
||||
#define FETCH_OPND(n) (sp[n])
|
||||
|
||||
/*
|
||||
* Push the jsdouble d using sp, depth, and pc from the lexical environment.
|
||||
* Try to convert d to a jsint that fits in a jsval, otherwise GC-alloc space
|
||||
* for it and push a reference.
|
||||
* Push the jsdouble d using sp from the lexical environment. Try to convert d
|
||||
* to a jsint that fits in a jsval, otherwise GC-alloc space for it and push a
|
||||
* reference.
|
||||
*/
|
||||
#define STORE_NUMBER(cx, n, d) \
|
||||
JS_BEGIN_MACRO \
|
||||
|
@ -2416,7 +2423,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
|||
JSVersion currentVersion, originalVersion;
|
||||
JSBool ok, cond;
|
||||
JSTrapHandler interruptHandler;
|
||||
jsint depth, len;
|
||||
jsint len;
|
||||
jsval *sp;
|
||||
void *mark;
|
||||
jsbytecode *endpc, *pc2;
|
||||
|
@ -2589,28 +2596,26 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
|||
|
||||
/* From this point the control must flow through the label exit.
|
||||
*
|
||||
* Allocate operand and pc stack slots for the script's worst-case depth,
|
||||
* unless we're resuming a generator.
|
||||
* Allocate operand stack slots for the script's worst-case depth, unless
|
||||
* we're resuming a generator.
|
||||
*/
|
||||
depth = (jsint) script->depth;
|
||||
if (JS_LIKELY(!fp->spbase)) {
|
||||
ASSERT_NOT_THROWING(cx);
|
||||
JS_ASSERT(!fp->sp);
|
||||
sp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark);
|
||||
sp = js_AllocRawStack(cx, script->depth, &mark);
|
||||
if (!sp) {
|
||||
mark = NULL;
|
||||
ok = JS_FALSE;
|
||||
goto exit;
|
||||
}
|
||||
JS_ASSERT(mark);
|
||||
sp += depth; /* skip pc stack slots */
|
||||
fp->spbase = sp;
|
||||
SAVE_SP(fp);
|
||||
} else {
|
||||
JS_ASSERT(fp->flags & JSFRAME_GENERATOR);
|
||||
mark = NULL;
|
||||
RESTORE_SP(fp);
|
||||
JS_ASSERT(JS_UPTRDIFF(sp, fp->spbase) <= depth * sizeof(jsval));
|
||||
JS_ASSERT((size_t) (sp - fp->spbase) <= script->depth);
|
||||
JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0);
|
||||
JS_PROPERTY_CACHE(cx).disabled += js_CountWithBlocks(cx, fp);
|
||||
|
||||
|
@ -2765,10 +2770,6 @@ interrupt:
|
|||
END_CASE(JSOP_POPN)
|
||||
|
||||
BEGIN_CASE(JSOP_SWAP)
|
||||
vp = sp - depth; /* swap generating pc's for the decompiler */
|
||||
ltmp = vp[-1];
|
||||
vp[-1] = vp[-2];
|
||||
sp[-2] = ltmp;
|
||||
rtmp = sp[-1];
|
||||
sp[-1] = sp[-2];
|
||||
sp[-2] = rtmp;
|
||||
|
@ -2894,13 +2895,9 @@ interrupt:
|
|||
|
||||
/* Restore the calling script's interpreter registers. */
|
||||
script = fp->script;
|
||||
depth = (jsint) script->depth;
|
||||
atoms = script->atomMap.vector;
|
||||
pc = fp->pc;
|
||||
|
||||
/* Store the generating pc for the return value. */
|
||||
vp[-depth] = (jsval)pc;
|
||||
|
||||
/* Resume execution in the calling frame. */
|
||||
inlineCallCount--;
|
||||
if (JS_LIKELY(ok)) {
|
||||
|
@ -3135,7 +3132,7 @@ interrupt:
|
|||
|
||||
case JSOP_FORLOCAL:
|
||||
slot = GET_UINT16(pc);
|
||||
JS_ASSERT(slot < (uintN)depth);
|
||||
JS_ASSERT(slot < script->depth);
|
||||
vp = &fp->spbase[slot];
|
||||
GC_POKE(cx, *vp);
|
||||
*vp = rval;
|
||||
|
@ -3191,20 +3188,14 @@ interrupt:
|
|||
|
||||
BEGIN_CASE(JSOP_DUP)
|
||||
JS_ASSERT(sp > fp->spbase);
|
||||
vp = sp - 1; /* address top of stack */
|
||||
rval = *vp;
|
||||
vp -= depth; /* address generating pc */
|
||||
vp[1] = *vp;
|
||||
rval = FETCH_OPND(-1);
|
||||
PUSH(rval);
|
||||
END_CASE(JSOP_DUP)
|
||||
|
||||
BEGIN_CASE(JSOP_DUP2)
|
||||
JS_ASSERT(sp - 2 >= fp->spbase);
|
||||
vp = sp - 1; /* address top of stack */
|
||||
lval = vp[-1];
|
||||
rval = *vp;
|
||||
vp -= depth; /* address generating pc */
|
||||
vp[1] = vp[2] = *vp;
|
||||
lval = FETCH_OPND(-2);
|
||||
rval = FETCH_OPND(-1);
|
||||
PUSH(lval);
|
||||
PUSH(rval);
|
||||
END_CASE(JSOP_DUP2)
|
||||
|
@ -3548,7 +3539,6 @@ interrupt:
|
|||
END_CASE(JSOP_STRICTNE)
|
||||
|
||||
BEGIN_CASE(JSOP_CASE)
|
||||
pc2 = (jsbytecode *) sp[-2-depth];
|
||||
STRICT_EQUALITY_OP(==);
|
||||
(void) POP();
|
||||
if (cond) {
|
||||
|
@ -3556,12 +3546,10 @@ interrupt:
|
|||
CHECK_BRANCH(len);
|
||||
DO_NEXT_OP(len);
|
||||
}
|
||||
sp[-depth] = (jsval)pc2;
|
||||
PUSH(lval);
|
||||
END_CASE(JSOP_CASE)
|
||||
|
||||
BEGIN_CASE(JSOP_CASEX)
|
||||
pc2 = (jsbytecode *) sp[-2-depth];
|
||||
STRICT_EQUALITY_OP(==);
|
||||
(void) POP();
|
||||
if (cond) {
|
||||
|
@ -3569,7 +3557,6 @@ interrupt:
|
|||
CHECK_BRANCH(len);
|
||||
DO_NEXT_OP(len);
|
||||
}
|
||||
sp[-depth] = (jsval)pc2;
|
||||
PUSH(lval);
|
||||
END_CASE(JSOP_CASEX)
|
||||
|
||||
|
@ -3779,7 +3766,6 @@ interrupt:
|
|||
goto error;
|
||||
sp[-1] = rval;
|
||||
}
|
||||
sp[-1-depth] = (jsval)pc;
|
||||
END_CASE(JSOP_POS)
|
||||
|
||||
BEGIN_CASE(JSOP_NEW)
|
||||
|
@ -3792,7 +3778,6 @@ interrupt:
|
|||
if (!js_InvokeConstructor(cx, vp, argc))
|
||||
goto error;
|
||||
sp = vp + 1;
|
||||
vp[-depth] = (jsval)pc;
|
||||
LOAD_INTERRUPT_HANDLER(cx);
|
||||
END_CASE(JSOP_NEW)
|
||||
|
||||
|
@ -3837,8 +3822,7 @@ interrupt:
|
|||
END_CASE(JSOP_TYPEOF)
|
||||
|
||||
BEGIN_CASE(JSOP_VOID)
|
||||
(void) POP_OPND();
|
||||
PUSH_OPND(JSVAL_VOID);
|
||||
STORE_OPND(-1, JSVAL_VOID);
|
||||
END_CASE(JSOP_VOID)
|
||||
|
||||
BEGIN_CASE(JSOP_INCELEM)
|
||||
|
@ -4110,7 +4094,7 @@ interrupt:
|
|||
BEGIN_CASE(JSOP_GETLOCALPROP)
|
||||
i = UINT16_LEN;
|
||||
slot = GET_UINT16(pc);
|
||||
JS_ASSERT(slot < (uintN)depth);
|
||||
JS_ASSERT(slot < script->depth);
|
||||
PUSH_OPND(fp->spbase[slot]);
|
||||
len = JSOP_GETLOCALPROP_LENGTH;
|
||||
goto do_getprop_body;
|
||||
|
@ -4243,7 +4227,7 @@ interrupt:
|
|||
JS_UNLOCK_OBJ(cx, obj2);
|
||||
STORE_OPND(-1, rval);
|
||||
PUSH_OPND(lval);
|
||||
goto end_callname;
|
||||
goto end_callprop;
|
||||
}
|
||||
} else {
|
||||
entry = NULL;
|
||||
|
@ -4284,7 +4268,7 @@ interrupt:
|
|||
STORE_OPND(-2, rval);
|
||||
}
|
||||
|
||||
end_callname:
|
||||
end_callprop:
|
||||
/* Wrap primitive lval in object clothing if necessary. */
|
||||
if (JSVAL_IS_PRIMITIVE(lval)) {
|
||||
/* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=412571 */
|
||||
|
@ -4296,6 +4280,15 @@ interrupt:
|
|||
goto error;
|
||||
}
|
||||
}
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
if (JS_UNLIKELY(rval == JSVAL_VOID)) {
|
||||
LOAD_ATOM(0);
|
||||
sp[-2] = ATOM_KEY(atom);
|
||||
SAVE_SP_AND_PC(fp);
|
||||
if (!js_OnUnknownMethod(cx, sp - 2))
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
END_CASE(JSOP_CALLPROP)
|
||||
|
||||
|
@ -4522,10 +4515,10 @@ interrupt:
|
|||
if (JSVAL_IS_INT(rval)) {
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
|
||||
jsuint length;
|
||||
|
||||
|
||||
length = ARRAY_DENSE_LENGTH(obj);
|
||||
i = JSVAL_TO_INT(rval);
|
||||
if ((jsuint)i < length &&
|
||||
if ((jsuint)i < length &&
|
||||
i < obj->fslots[JSSLOT_ARRAY_LENGTH]) {
|
||||
rval = obj->dslots[i];
|
||||
if (rval != JSVAL_HOLE)
|
||||
|
@ -4551,8 +4544,19 @@ interrupt:
|
|||
* CALLPROP does. See bug 362910.
|
||||
*/
|
||||
ELEMENT_OP(-1, OBJ_GET_PROPERTY(cx, obj, id, &rval));
|
||||
STORE_OPND(-2, rval);
|
||||
STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
if (JS_UNLIKELY(rval == JSVAL_VOID)) {
|
||||
sp[-2] = sp[-1];
|
||||
sp[-1] = OBJECT_TO_JSVAL(obj);
|
||||
SAVE_SP_AND_PC(fp);
|
||||
if (!js_OnUnknownMethod(cx, sp - 2))
|
||||
goto error;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
STORE_OPND(-2, rval);
|
||||
STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
|
||||
}
|
||||
END_CASE(JSOP_CALLELEM)
|
||||
|
||||
BEGIN_CASE(JSOP_SETELEM)
|
||||
|
@ -4618,9 +4622,8 @@ interrupt:
|
|||
sizeof(jsval));
|
||||
nvars = fun->u.i.nvars;
|
||||
script = fun->u.i.script;
|
||||
depth = (jsint) script->depth;
|
||||
atoms = script->atomMap.vector;
|
||||
nslots = nframeslots + nvars + 2 * depth;
|
||||
nslots = nframeslots + nvars + script->depth;
|
||||
|
||||
/* Allocate missing expected args adjacent to actuals. */
|
||||
missing = (fun->nargs > argc) ? fun->nargs - argc : 0;
|
||||
|
@ -4710,7 +4713,6 @@ interrupt:
|
|||
sp = newsp;
|
||||
while (nvars--)
|
||||
PUSH(JSVAL_VOID);
|
||||
sp += depth;
|
||||
newifp->frame.spbase = sp;
|
||||
SAVE_SP(&newifp->frame);
|
||||
|
||||
|
@ -4763,7 +4765,6 @@ interrupt:
|
|||
RESTORE_SP(fp);
|
||||
JS_ASSERT(fp->pc == pc);
|
||||
script = fp->script;
|
||||
depth = (jsint) script->depth;
|
||||
atoms = script->atomMap.vector;
|
||||
js_FreeRawStack(cx, newmark);
|
||||
goto error;
|
||||
|
@ -4791,15 +4792,10 @@ interrupt:
|
|||
* this frame's operand stack, take the slow path.
|
||||
*/
|
||||
nargs = fun->u.n.minargs - argc;
|
||||
if (sp + nargs > fp->spbase + depth)
|
||||
if (sp + nargs > fp->spbase + script->depth)
|
||||
goto do_invoke;
|
||||
do {
|
||||
/*
|
||||
* Use PUSH_OPND to set the proper pc values for
|
||||
* the extra arguments. The decompiler relies on
|
||||
* this.
|
||||
*/
|
||||
PUSH_OPND(JSVAL_VOID);
|
||||
PUSH(JSVAL_VOID);
|
||||
} while (--nargs != 0);
|
||||
SAVE_SP(fp);
|
||||
}
|
||||
|
@ -4819,7 +4815,6 @@ interrupt:
|
|||
if (!ok)
|
||||
goto error;
|
||||
sp = vp + 1;
|
||||
vp[-depth] = (jsval)pc;
|
||||
goto end_call;
|
||||
}
|
||||
}
|
||||
|
@ -4836,7 +4831,6 @@ interrupt:
|
|||
}
|
||||
#endif
|
||||
sp = vp + 1;
|
||||
vp[-depth] = (jsval)pc;
|
||||
LOAD_INTERRUPT_HANDLER(cx);
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
@ -4876,7 +4870,6 @@ interrupt:
|
|||
vp = sp - argc - 2;
|
||||
ok = js_Invoke(cx, argc, vp, 0);
|
||||
sp = vp + 1;
|
||||
vp[-depth] = (jsval)pc;
|
||||
LOAD_INTERRUPT_HANDLER(cx);
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
@ -6218,7 +6211,7 @@ interrupt:
|
|||
*/
|
||||
JS_ASSERT(sp - fp->spbase >= 2);
|
||||
slot = GET_UINT16(pc);
|
||||
JS_ASSERT(slot + 1 < (uintN)depth);
|
||||
JS_ASSERT(slot + 1 < script->depth);
|
||||
fp->spbase[slot] = POP_OPND();
|
||||
END_CASE(JSOP_SETLOCALPOP)
|
||||
|
||||
|
@ -6528,7 +6521,7 @@ interrupt:
|
|||
LOAD_OBJECT(0);
|
||||
JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
|
||||
vp = sp + OBJ_BLOCK_COUNT(cx, obj);
|
||||
JS_ASSERT(vp <= fp->spbase + depth);
|
||||
JS_ASSERT(vp <= fp->spbase + script->depth);
|
||||
while (sp < vp) {
|
||||
STORE_OPND(0, JSVAL_VOID);
|
||||
sp++;
|
||||
|
@ -6565,7 +6558,7 @@ interrupt:
|
|||
? fp->blockChain
|
||||
: fp->scopeChain);
|
||||
|
||||
JS_ASSERT(fp->spbase <= blocksp && blocksp <= fp->spbase + depth);
|
||||
JS_ASSERT((size_t) (blocksp - fp->spbase) <= script->depth);
|
||||
#endif
|
||||
if (fp->blockChain) {
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, fp->blockChain) == &js_BlockClass);
|
||||
|
@ -6599,7 +6592,7 @@ interrupt:
|
|||
BEGIN_CASE(JSOP_GETLOCAL)
|
||||
BEGIN_CASE(JSOP_CALLLOCAL)
|
||||
slot = GET_UINT16(pc);
|
||||
JS_ASSERT(slot < (uintN)depth);
|
||||
JS_ASSERT(slot < script->depth);
|
||||
PUSH_OPND(fp->spbase[slot]);
|
||||
if (op == JSOP_CALLLOCAL)
|
||||
PUSH_OPND(JSVAL_NULL);
|
||||
|
@ -6607,7 +6600,7 @@ interrupt:
|
|||
|
||||
BEGIN_CASE(JSOP_SETLOCAL)
|
||||
slot = GET_UINT16(pc);
|
||||
JS_ASSERT(slot < (uintN)depth);
|
||||
JS_ASSERT(slot < script->depth);
|
||||
vp = &fp->spbase[slot];
|
||||
GC_POKE(cx, *vp);
|
||||
*vp = FETCH_OPND(-1);
|
||||
|
@ -6616,7 +6609,7 @@ interrupt:
|
|||
/* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
|
||||
#define FAST_LOCAL_INCREMENT_OP(PRE,OPEQ,MINMAX) \
|
||||
slot = GET_UINT16(pc); \
|
||||
JS_ASSERT(slot < (uintN)depth); \
|
||||
JS_ASSERT(slot < script->depth); \
|
||||
vp = fp->spbase + slot; \
|
||||
rval = *vp; \
|
||||
if (!JSVAL_IS_INT(rval) || rval == INT_TO_JSVAL(JSVAL_INT_##MINMAX)) \
|
||||
|
@ -6690,7 +6683,7 @@ interrupt:
|
|||
|
||||
BEGIN_CASE(JSOP_ARRAYPUSH)
|
||||
slot = GET_UINT16(pc);
|
||||
JS_ASSERT(slot < (uintN)depth);
|
||||
JS_ASSERT(slot < script->depth);
|
||||
lval = fp->spbase[slot];
|
||||
obj = JSVAL_TO_OBJECT(lval);
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass);
|
||||
|
|
|
@ -60,6 +60,9 @@ JS_BEGIN_EXTERN_C
|
|||
* with well-known slots, if possible.
|
||||
*/
|
||||
struct JSStackFrame {
|
||||
jsval *sp; /* stack pointer */
|
||||
jsbytecode *pc; /* program counter */
|
||||
jsval *spbase; /* operand stack base */
|
||||
JSObject *callobj; /* lazily created Call object */
|
||||
JSObject *argsobj; /* lazily created arguments object */
|
||||
JSObject *varobj; /* variables object, where vars go */
|
||||
|
@ -75,9 +78,6 @@ struct JSStackFrame {
|
|||
JSStackFrame *down; /* previous frame */
|
||||
void *annotation; /* used by Java security */
|
||||
JSObject *scopeChain; /* scope chain */
|
||||
jsbytecode *pc; /* program counter */
|
||||
jsval *sp; /* stack pointer */
|
||||
jsval *spbase; /* operand stack base */
|
||||
uintN sharpDepth; /* array/object initializer depth */
|
||||
JSObject *sharpArray; /* scope for #n= initializer vars */
|
||||
uint32 flags; /* frame flags -- see below */
|
||||
|
@ -492,6 +492,9 @@ js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp);
|
|||
extern JSBool
|
||||
js_ImportProperty(JSContext *cx, JSObject *obj, jsid id);
|
||||
|
||||
extern JSBool
|
||||
js_OnUnknownMethod(JSContext *cx, jsval *vp);
|
||||
|
||||
/*
|
||||
* JS_OPMETER helper functions.
|
||||
*/
|
||||
|
|
|
@ -4763,21 +4763,34 @@ js_DecompileFunction(JSPrinter *jp)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#undef LOCAL_ASSERT_RV
|
||||
/*
|
||||
* Find the depth of the operand stack when the interpreter reaches the given
|
||||
* pc in script. When pcstack is not null, it must be an array with space for
|
||||
* at least script->depth elements. On return the array will contain pointers
|
||||
* to opcodes that populated the interpreter's current operand stack.
|
||||
*
|
||||
* This function cannot raise an exception or error. However, due to a risk of
|
||||
* potential bugs when modeling the stack, the function returns -1 if it
|
||||
* detects an inconsistency in the model. Such an inconsistency triggers an
|
||||
* assert in a debug build.
|
||||
*/
|
||||
static intN
|
||||
ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
jsbytecode **pcstack);
|
||||
|
||||
char *
|
||||
js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
||||
JSString *fallback)
|
||||
{
|
||||
JSStackFrame *fp, *down;
|
||||
JSStackFrame *fp;
|
||||
jsbytecode *pc, *begin, *end;
|
||||
jsval *sp, *spbase, *base, *limit;
|
||||
intN depth, pcdepth;
|
||||
JSScript *script;
|
||||
JSOp op;
|
||||
const JSCodeSpec *cs;
|
||||
jssrcnote *sn;
|
||||
ptrdiff_t len, oplen;
|
||||
ptrdiff_t len;
|
||||
intN pcdepth;
|
||||
jsval *sp;
|
||||
JSPrinter *jp;
|
||||
char *name;
|
||||
|
||||
|
@ -4790,113 +4803,73 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||
if (!fp)
|
||||
goto do_fallback;
|
||||
|
||||
/* Try to find sp's generating pc depth slots under it on the stack. */
|
||||
pc = fp->pc;
|
||||
sp = fp->sp;
|
||||
spbase = fp->spbase;
|
||||
if ((uintN)(sp - spbase) > fp->script->depth) {
|
||||
/*
|
||||
* Preparing to make an internal invocation, using an argv stack
|
||||
* segment pushed just above fp's operand stack space. Such an argv
|
||||
* stack has no generating pc "basement", so we must fall back.
|
||||
*/
|
||||
if (!pc)
|
||||
goto do_fallback;
|
||||
script = fp->script;
|
||||
if (pc < script->main || script->code + script->length <= pc) {
|
||||
JS_NOT_REACHED("bug");
|
||||
goto do_fallback;
|
||||
}
|
||||
|
||||
if (spindex == JSDVG_SEARCH_STACK) {
|
||||
if (!pc) {
|
||||
/*
|
||||
* Current frame is native: look under it for a scripted call
|
||||
* in which a decompilable bytecode string that generated the
|
||||
* value as an actual argument might exist.
|
||||
*/
|
||||
JS_ASSERT(!fp->script && !(fp->fun && FUN_INTERPRETED(fp->fun)));
|
||||
down = fp->down;
|
||||
if (!down)
|
||||
goto do_fallback;
|
||||
script = down->script;
|
||||
spbase = down->spbase;
|
||||
base = fp->argv;
|
||||
limit = base + fp->argc;
|
||||
if (spindex != JSDVG_IGNORE_STACK) {
|
||||
jsbytecode **pcstack;
|
||||
|
||||
/*
|
||||
* Prepare computing pcstack containing pointers to opcodes that
|
||||
* populated interpreter's stack with its current content.
|
||||
*/
|
||||
pcstack = (jsbytecode **)
|
||||
JS_malloc(cx, script->depth * sizeof *pcstack);
|
||||
if (!pcstack)
|
||||
return NULL;
|
||||
pcdepth = ReconstructPCStack(cx, script, fp->pc, pcstack);
|
||||
if (pcdepth < 0)
|
||||
goto release_pcstack;
|
||||
|
||||
if (spindex != JSDVG_SEARCH_STACK) {
|
||||
JS_ASSERT(spindex < 0);
|
||||
pcdepth += spindex;
|
||||
if (pcdepth < 0)
|
||||
goto release_pcstack;
|
||||
pc = pcstack[pcdepth];
|
||||
} else {
|
||||
/*
|
||||
* This should be a script activation, either a top-level
|
||||
* script or a scripted function. But be paranoid about calls
|
||||
* to js_DecompileValueGenerator from code that hasn't fully
|
||||
* initialized a (default-all-zeroes) frame.
|
||||
* We search from fp->sp to base to find the most recently
|
||||
* calculated value matching v under assumption that it is
|
||||
* it that caused exception, see bug 328664.
|
||||
*/
|
||||
script = fp->script;
|
||||
spbase = base = fp->spbase;
|
||||
limit = fp->sp;
|
||||
}
|
||||
JS_ASSERT((size_t) (fp->sp - fp->spbase) <= fp->script->depth);
|
||||
sp = fp->sp;
|
||||
do {
|
||||
if (sp == fp->spbase) {
|
||||
pcdepth = -1;
|
||||
goto release_pcstack;
|
||||
}
|
||||
} while (*--sp != v);
|
||||
|
||||
/*
|
||||
* Pure paranoia about default-zeroed frames being active while
|
||||
* js_DecompileValueGenerator is called. It can't hurt much now;
|
||||
* error reporting performance is not an issue.
|
||||
*/
|
||||
if (!script || !base || !limit)
|
||||
goto do_fallback;
|
||||
|
||||
/*
|
||||
* Try to find operand-generating pc depth slots below sp.
|
||||
*
|
||||
* In the native case, we know the arguments have generating pc's
|
||||
* under them, on account of fp->down->script being non-null: all
|
||||
* compiled scripts get depth slots for generating pc's allocated
|
||||
* upon activation, at the top of js_Interpret.
|
||||
*
|
||||
* In the script or scripted function case, the same reasoning
|
||||
* applies to fp rather than to fp->down.
|
||||
*
|
||||
* We search from limit to base to find the most recently calculated
|
||||
* value matching v under assumption that it is it that caused
|
||||
* exception, see bug 328664.
|
||||
*/
|
||||
for (sp = limit;;) {
|
||||
if (sp <= base)
|
||||
goto do_fallback;
|
||||
--sp;
|
||||
if (*sp == v) {
|
||||
depth = (intN)script->depth;
|
||||
sp -= depth;
|
||||
pc = (jsbytecode *) *sp;
|
||||
break;
|
||||
if (sp >= fp->spbase + pcdepth) {
|
||||
/*
|
||||
* This happens when the value comes from a temporary slot
|
||||
* that the interpreter uses for GC roots. Assume that it is
|
||||
* fp->pc that caused the exception.
|
||||
*/
|
||||
pc = fp->pc;
|
||||
} else {
|
||||
pc = pcstack[sp - fp->spbase];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* At this point, pc may or may not be null, i.e., we could be in
|
||||
* a script activation, or we could be in a native frame that was
|
||||
* called by another native function. Check pc and script.
|
||||
*/
|
||||
if (!pc)
|
||||
goto do_fallback;
|
||||
script = fp->script;
|
||||
if (!script)
|
||||
goto do_fallback;
|
||||
|
||||
if (spindex != JSDVG_IGNORE_STACK) {
|
||||
JS_ASSERT(spindex < 0);
|
||||
depth = (intN)script->depth;
|
||||
#if !JS_HAS_NO_SUCH_METHOD
|
||||
JS_ASSERT(-depth <= spindex);
|
||||
#endif
|
||||
sp = fp->sp + spindex;
|
||||
if ((jsuword) (sp - fp->spbase) < (jsuword) depth)
|
||||
pc = (jsbytecode *) *(sp - depth);
|
||||
}
|
||||
release_pcstack:
|
||||
JS_free(cx, pcstack);
|
||||
if (pcdepth < 0)
|
||||
goto do_fallback;
|
||||
}
|
||||
|
||||
/*
|
||||
* Again, be paranoid, this time about possibly loading an invalid pc
|
||||
* from fp->sp[spindex - script->depth)].
|
||||
* We know the address of the opcode that triggered the diagnostic. Find
|
||||
* the decompilation limits for the opcode and its stack depth.
|
||||
*/
|
||||
if (JS_UPTRDIFF(pc, script->code) >= (jsuword)script->length) {
|
||||
pc = fp->pc;
|
||||
if (!pc)
|
||||
goto do_fallback;
|
||||
}
|
||||
op = (JSOp) *pc;
|
||||
if (op == JSOP_TRAP)
|
||||
op = JS_GetTrapOpcode(cx, script, pc);
|
||||
|
@ -4952,16 +4925,57 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||
if (len <= 0)
|
||||
goto do_fallback;
|
||||
|
||||
pcdepth = ReconstructPCStack(cx, script, begin, NULL);
|
||||
if (pcdepth < 0)
|
||||
goto do_fallback;
|
||||
|
||||
name = NULL;
|
||||
jp = JS_NEW_PRINTER(cx, "js_DecompileValueGenerator", fp->fun, 0, JS_FALSE);
|
||||
if (jp) {
|
||||
jp->dvgfence = end;
|
||||
if (js_DecompileCode(jp, script, begin, (uintN)len, (uintN)pcdepth)) {
|
||||
name = (jp->sprinter.base) ? jp->sprinter.base : (char *) "";
|
||||
name = JS_strdup(cx, name);
|
||||
}
|
||||
js_DestroyPrinter(jp);
|
||||
}
|
||||
return name;
|
||||
|
||||
do_fallback:
|
||||
if (!fallback) {
|
||||
fallback = js_ValueToSource(cx, v);
|
||||
if (!fallback)
|
||||
return NULL;
|
||||
}
|
||||
return js_DeflateString(cx, JSSTRING_CHARS(fallback),
|
||||
JSSTRING_LENGTH(fallback));
|
||||
}
|
||||
|
||||
static intN
|
||||
ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
jsbytecode **pcstack)
|
||||
{
|
||||
intN pcdepth, nuses, ndefs;
|
||||
jsbytecode *begin;
|
||||
JSOp op;
|
||||
const JSCodeSpec *cs;
|
||||
ptrdiff_t oplen;
|
||||
jssrcnote *sn;
|
||||
uint32 type;
|
||||
|
||||
#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, -1);
|
||||
|
||||
/*
|
||||
* Walk forward from script->main and compute starting stack depth.
|
||||
* Walk forward from script->main and compute the stack depth and stack of
|
||||
* operand-generating opcode PCs in pcstack.
|
||||
*
|
||||
* FIXME: Code to compute oplen copied from js_Disassemble1 and reduced.
|
||||
* FIXME: Optimize to use last empty-stack sequence point.
|
||||
*/
|
||||
LOCAL_ASSERT(script->main <= pc && pc < script->code + script->length);
|
||||
pcdepth = 0;
|
||||
begin = pc;
|
||||
for (pc = script->main; pc < begin; pc += oplen) {
|
||||
uint32 type;
|
||||
intN nuses, ndefs;
|
||||
|
||||
op = (JSOp) *pc;
|
||||
if (op == JSOP_TRAP)
|
||||
op = JS_GetTrapOpcode(cx, script, pc);
|
||||
|
@ -4970,6 +4984,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||
|
||||
if (op == JSOP_POPN) {
|
||||
pcdepth -= GET_UINT16(pc);
|
||||
LOCAL_ASSERT(pcdepth >= 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -5002,6 +5017,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||
* since we have moved beyond the IFEQ now.
|
||||
*/
|
||||
--pcdepth;
|
||||
LOCAL_ASSERT(pcdepth >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5068,7 +5084,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||
nuses = GET_UINT16(pc);
|
||||
}
|
||||
pcdepth -= nuses;
|
||||
JS_ASSERT(pcdepth >= 0);
|
||||
LOCAL_ASSERT(pcdepth >= 0);
|
||||
|
||||
ndefs = cs->ndefs;
|
||||
if (op == JSOP_FINALLY) {
|
||||
|
@ -5083,27 +5099,65 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||
JS_ASSERT(OBJ_BLOCK_DEPTH(cx, obj) == pcdepth);
|
||||
ndefs = OBJ_BLOCK_COUNT(cx, obj);
|
||||
}
|
||||
|
||||
LOCAL_ASSERT(pcdepth + ndefs <= script->depth);
|
||||
if (pcstack) {
|
||||
intN i;
|
||||
jsbytecode *pc2;
|
||||
|
||||
/*
|
||||
* Fill the slots that the opcode defines withs its pc unless it
|
||||
* just reshuffle the stack. In the latter case we want to
|
||||
* preserve the opcode that generated the original value.
|
||||
*/
|
||||
switch (op) {
|
||||
default:
|
||||
for (i = 0; i != ndefs; ++i)
|
||||
pcstack[pcdepth + i] = pc;
|
||||
break;
|
||||
|
||||
case JSOP_CASE:
|
||||
case JSOP_CASEX:
|
||||
/* Keep the switch value. */
|
||||
JS_ASSERT(ndefs == 1);
|
||||
break;
|
||||
|
||||
case JSOP_DUP:
|
||||
JS_ASSERT(ndefs == 2);
|
||||
pcstack[pcdepth + 1] = pcstack[pcdepth];
|
||||
break;
|
||||
|
||||
case JSOP_DUP2:
|
||||
JS_ASSERT(ndefs == 4);
|
||||
pcstack[pcdepth + 2] = pcstack[pcdepth];
|
||||
pcstack[pcdepth + 3] = pcstack[pcdepth + 1];
|
||||
break;
|
||||
|
||||
case JSOP_SWAP:
|
||||
JS_ASSERT(ndefs == 2);
|
||||
pc2 = pcstack[pcdepth];
|
||||
pcstack[pcdepth] = pcstack[pcdepth + 1];
|
||||
pcstack[pcdepth + 1] = pc2;
|
||||
break;
|
||||
|
||||
case JSOP_LEAVEBLOCKEXPR:
|
||||
/*
|
||||
* The decompiler wants [leaveblockexpr], not [enterblock], to
|
||||
* be left on pcstack after a simulated let expression.
|
||||
*/
|
||||
JS_ASSERT(ndefs == 0);
|
||||
LOCAL_ASSERT(pcdepth >= 1);
|
||||
LOCAL_ASSERT(*pcstack[pcdepth - 1] == JSOP_ENTERBLOCK);
|
||||
pcstack[pcdepth - 1] = pc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcdepth += ndefs;
|
||||
}
|
||||
LOCAL_ASSERT(pc == begin);
|
||||
return pcdepth;
|
||||
|
||||
name = NULL;
|
||||
jp = JS_NEW_PRINTER(cx, "js_DecompileValueGenerator", fp->fun, 0, JS_FALSE);
|
||||
if (jp) {
|
||||
jp->dvgfence = end;
|
||||
if (js_DecompileCode(jp, script, begin, (uintN)len, (uintN)pcdepth)) {
|
||||
name = (jp->sprinter.base) ? jp->sprinter.base : (char *) "";
|
||||
name = JS_strdup(cx, name);
|
||||
}
|
||||
js_DestroyPrinter(jp);
|
||||
}
|
||||
return name;
|
||||
|
||||
do_fallback:
|
||||
if (!fallback) {
|
||||
fallback = js_ValueToSource(cx, v);
|
||||
if (!fallback)
|
||||
return NULL;
|
||||
}
|
||||
return js_DeflateString(cx, JSSTRING_CHARS(fallback),
|
||||
JSSTRING_LENGTH(fallback));
|
||||
#undef LOCAL_ASSERT
|
||||
}
|
||||
|
||||
#undef LOCAL_ASSERT_RV
|
||||
|
|
|
@ -272,7 +272,7 @@ OPDEF(JSOP_UNUSED117, 117,"unused117", NULL, 1, 0, 0, 0, JOF_BYTE)
|
|||
* lval if false; and DEFAULT is POP lval and GOTO.
|
||||
*/
|
||||
OPDEF(JSOP_CONDSWITCH,118,"condswitch", NULL, 1, 0, 0, 0, JOF_BYTE|JOF_PARENHEAD)
|
||||
OPDEF(JSOP_CASE, 119,"case", NULL, 3, 1, 0, 0, JOF_JUMP)
|
||||
OPDEF(JSOP_CASE, 119,"case", NULL, 3, 2, 1, 0, JOF_JUMP)
|
||||
OPDEF(JSOP_DEFAULT, 120,"default", NULL, 3, 1, 0, 0, JOF_JUMP)
|
||||
|
||||
/*
|
||||
|
@ -355,7 +355,7 @@ OPDEF(JSOP_IFNEX, 141,"ifnex", NULL, 5, 1, 0, 0, JOF_JUMPX|
|
|||
OPDEF(JSOP_ORX, 142,"orx", NULL, 5, 1, 0, 5, JOF_JUMPX|JOF_DETECTING)
|
||||
OPDEF(JSOP_ANDX, 143,"andx", NULL, 5, 1, 0, 6, JOF_JUMPX|JOF_DETECTING)
|
||||
OPDEF(JSOP_GOSUBX, 144,"gosubx", NULL, 5, 0, 0, 0, JOF_JUMPX)
|
||||
OPDEF(JSOP_CASEX, 145,"casex", NULL, 5, 1, 0, 0, JOF_JUMPX)
|
||||
OPDEF(JSOP_CASEX, 145,"casex", NULL, 5, 2, 1, 0, JOF_JUMPX)
|
||||
OPDEF(JSOP_DEFAULTX, 146,"defaultx", NULL, 5, 1, 0, 0, JOF_JUMPX)
|
||||
OPDEF(JSOP_TABLESWITCHX, 147,"tableswitchx",NULL, -1, 1, 0, 0, JOF_TABLESWITCHX|JOF_DETECTING|JOF_PARENHEAD)
|
||||
OPDEF(JSOP_LOOKUPSWITCHX, 148,"lookupswitchx",NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCHX|JOF_DETECTING|JOF_PARENHEAD)
|
||||
|
|
|
@ -66,6 +66,12 @@
|
|||
# define GENERATOR_INIT js_InitNullClass
|
||||
#endif
|
||||
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
# define NO_SUCH_METHOD_INIT js_InitNoSuchMethodClass
|
||||
#else
|
||||
# define NO_SUCH_METHOD_INIT js_InitNullClass
|
||||
#endif
|
||||
|
||||
#if JS_HAS_FILE_OBJECT
|
||||
# define FILE_INIT js_InitFileClass
|
||||
#else
|
||||
|
@ -109,6 +115,7 @@ JS_PROTO(UnusedProto28, 28, js_InitNullClass)
|
|||
JS_PROTO(File, 29, FILE_INIT)
|
||||
JS_PROTO(Block, 30, js_InitBlockClass)
|
||||
JS_PROTO(XMLFilter, 31, XMLFILTER_INIT)
|
||||
JS_PROTO(NoSuchMethod, 32, NO_SUCH_METHOD_INIT)
|
||||
|
||||
#undef SCRIPT_INIT
|
||||
#undef XML_INIT
|
||||
|
@ -118,3 +125,4 @@ JS_PROTO(XMLFilter, 31, XMLFILTER_INIT)
|
|||
#undef ATTRIBUTE_INIT
|
||||
#undef GENERATOR_INIT
|
||||
#undef FILE_INIT
|
||||
#undef NO_SUCH_METHOD_INIT
|
||||
|
|
Загрузка…
Ссылка в новой задаче