--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -185,17 +185,17 @@ js_FillPropertyCache(JSContext *cx, JSOb
*entryp = NULL;
return;
}
/*
* Optimize the cached vword based on our parameters and the current pc's
* opcode format flags.
*/
- op = (JSOp) *pc;
+ op = js_GetOpcode(cx, cx->fp->script, pc);
cs = &js_CodeSpec[op];
do {
/*
* Check for a prototype "plain old method" callee computation. What
* is a plain old method? It's a function-valued property with stub
* getter and setter, so get of a function is idempotent and set is
* transparent.
@@ -314,17 +314,17 @@ js_FullTestPropertyCache(JSContext *cx,
JSAtom *atom;
JSObject *obj, *pobj, *tmp;
JSPropCacheEntry *entry;
uint32 vcap;
JS_ASSERT(uintN((cx->fp->imacpc ? cx->fp->imacpc : pc) - cx->fp->script->code)
< cx->fp->script->length);
- op = (JSOp) *pc;
+ op = js_GetOpcode(cx, cx->fp->script, pc);
cs = &js_CodeSpec[op];
if (op == JSOP_LENGTH) {
atom = cx->runtime->atomState.lengthAtom;
} else {
pcoff = (JOF_TYPE(cs->format) == JOF_SLOTATOM) ? 2 : 0;
GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom);
}
@@ -3073,17 +3073,18 @@ js_Interpret(JSContext *cx)
/* Restore the calling script's interpreter registers. */
script = fp->script;
atoms = FrameAtomBase(cx, fp);
/* Resume execution in the calling frame. */
inlineCallCount--;
if (JS_LIKELY(ok)) {
TRACE_0(LeaveFrame);
- JS_ASSERT(js_CodeSpec[*regs.pc].length == JSOP_CALL_LENGTH);
+ JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length
+ == JSOP_CALL_LENGTH);
len = JSOP_CALL_LENGTH;
DO_NEXT_OP(len);
}
goto error;
}
goto exit;
BEGIN_CASE(JSOP_DEFAULT)
@@ -3398,17 +3399,17 @@ js_Interpret(JSContext *cx)
JSObject *obj_, *pobj_; \
JSProperty *prop_; \
JSScopeProperty *sprop_; \
uint32 sample_ = rt->gcNumber; \
if (pcoff >= 0) \
GET_ATOM_FROM_BYTECODE(script, regs.pc, pcoff, atom_); \
else \
atom_ = rt->atomState.lengthAtom; \
- if (JOF_OPMODE(*regs.pc) == JOF_NAME) { \
+ if (JOF_OPMODE(op) == JOF_NAME) { \
ok = js_FindProperty(cx, ATOM_TO_JSID(atom_), &obj_, &pobj_, \
&prop_); \
} else { \
obj_ = obj; \
ok = js_LookupProperty(cx, obj, ATOM_TO_JSID(atom_), &pobj_, \
&prop_); \
} \
if (!ok) \
@@ -5069,17 +5070,17 @@ js_Interpret(JSContext *cx)
argc = GET_ARGC(regs.pc);
vp = regs.sp - argc - 2;
ok = js_Invoke(cx, argc, vp, 0);
regs.sp = vp + 1;
CHECK_INTERRUPT_HANDLER();
if (!ok)
goto error;
if (!cx->rval2set) {
- op2 = (JSOp) regs.pc[JSOP_SETCALL_LENGTH];
+ op2 = js_GetOpcode(cx, script, regs.pc + JSOP_SETCALL_LENGTH);
if (op2 != JSOP_DELELEM) {
JS_ASSERT(!(js_CodeSpec[op2].format & JOF_DEL));
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_LEFTSIDE_OF_ASS);
goto error;
}
/*
@@ -5131,17 +5132,17 @@ js_Interpret(JSContext *cx)
}
id = ATOM_TO_JSID(atom);
if (js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry) < 0)
goto error;
if (!prop) {
/* Kludge to allow (typeof foo == "undefined") tests. */
endpc = script->code + script->length;
- op2 = (JSOp) regs.pc[JSOP_NAME_LENGTH];
+ op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH);
if (op2 == JSOP_TYPEOF) {
PUSH_OPND(JSVAL_VOID);
len = JSOP_NAME_LENGTH;
DO_NEXT_OP(len);
}
goto atom_not_defined;
}
@@ -6286,17 +6287,17 @@ js_Interpret(JSContext *cx)
* If rval is a hole, do not call OBJ_DEFINE_PROPERTY. In this case,
* obj must be an array, so if the current op is the last element
* initialiser, set the array length to one greater than id.
*/
if (rval == JSVAL_HOLE) {
JS_ASSERT(OBJ_IS_ARRAY(cx, obj));
JS_ASSERT(JSID_IS_INT(id));
JS_ASSERT((jsuint) JSID_TO_INT(id) < ARRAY_INIT_LIMIT);
- if ((JSOp) regs.pc[JSOP_INITELEM_LENGTH] == JSOP_ENDINIT &&
+ if (js_GetOpcode(cx, script, regs.pc + JSOP_INITELEM_LENGTH) == JSOP_ENDINIT &&
!js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) {
goto error;
}
} else {
if (!OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL, JSPROP_ENUMERATE, NULL))
goto error;
}
regs.sp -= 2;
@@ -7035,17 +7036,17 @@ js_Interpret(JSContext *cx)
* Restart the handler search with updated pc and stack depth
* to properly notify the debugger.
*/
goto error;
}
switch (tn->kind) {
case JSTRY_CATCH:
- JS_ASSERT(*regs.pc == JSOP_ENTERBLOCK);
+ JS_ASSERT(js_GetOpcode(cx, fp->script, regs.pc) == JSOP_ENTERBLOCK);
#if JS_HAS_GENERATORS
/* Catch cannot intercept the closing of a generator. */
if (JS_UNLIKELY(cx->exception == JSVAL_ARETURN))
break;
#endif
/*
@@ -7070,17 +7071,17 @@ js_Interpret(JSContext *cx)
case JSTRY_ITER:
/*
* This is similar to JSOP_ENDITER in the interpreter loop,
* except the code now uses the stack slot normally used by
* JSOP_NEXTITER, namely regs.sp[-1] before the regs.sp -= 2
* adjustment and regs.sp[1] after, to save and restore the
* pending exception.
*/
- JS_ASSERT(*regs.pc == JSOP_ENDITER);
+ JS_ASSERT(js_GetOpcode(cx, fp->script, regs.pc) == JSOP_ENDITER);
regs.sp[-1] = cx->exception;
cx->throwing = JS_FALSE;
ok = js_CloseIterator(cx, regs.sp[-2]);
regs.sp -= 2;
if (!ok)
goto error;
cx->throwing = JS_TRUE;
cx->exception = regs.sp[1];
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -67,17 +67,17 @@
#include "jsobj.h"
#include "jsopcode.h"
#include "jsparse.h"
#include "jsscope.h"
#include "jsscript.h"
#include "jsstaticcheck.h"
#include "jsstr.h"
#include "jstracer.h"
-#include "jsdbgapi.h" /* whether or not JS_HAS_OBJ_WATCHPOINT */
+#include "jsdbgapi.h"
#if JS_HAS_GENERATORS
#include "jsiter.h"
#endif
#if JS_HAS_XML_SUPPORT
#include "jsxml.h"
#endif
@@ -1188,19 +1188,20 @@ js_ComputeFilename(JSContext *cx, JSStac
flags = JS_GetScriptFilenameFlags(caller->script);
if ((flags & JSFILENAME_PROTECTED) &&
principals &&
strcmp(principals->codebase, "[System Principal]")) {
*linenop = 0;
return principals->codebase;
}
- if (caller->regs && *caller->regs->pc == JSOP_EVAL) {
- JS_ASSERT(caller->regs->pc[JSOP_EVAL_LENGTH] == JSOP_LINENO);
- *linenop = GET_UINT16(caller->regs->pc + JSOP_EVAL_LENGTH);
+ jsbytecode *pc = caller->regs->pc;
+ if (caller->regs && js_GetOpcode(cx, caller->script, pc) == JSOP_EVAL) {
+ JS_ASSERT(js_GetOpcode(cx, caller->script, pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
+ *linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
} else {
*linenop = js_FramePCToLineNumber(cx, caller);
}
return caller->script->filename;
}
#ifndef EVAL_CACHE_CHAIN_LIMIT
# define EVAL_CACHE_CHAIN_LIMIT 4
@@ -2012,67 +2013,63 @@ js_Object(JSContext *cx, JSObject *obj,
* Given pc pointing after a property accessing bytecode, return true if the
* access is "object-detecting" in the sense used by web scripts, e.g., when
* checking whether document.all is defined.
*/
static JS_REQUIRES_STACK JSBool
Detecting(JSContext *cx, jsbytecode *pc)
{
JSScript *script;
- jsbytecode *endpc;
JSOp op;
JSAtom *atom;
if (!cx->fp)
return JS_FALSE;
script = cx->fp->script;
- for (endpc = script->code + script->length;
- pc < endpc;
- pc += js_CodeSpec[op].length) {
+ for (;; pc += js_CodeSpec[op].length) {
/* General case: a branch or equality op follows the access. */
- op = (JSOp) *pc;
+ op = js_GetOpcode(cx, script, pc);
if (js_CodeSpec[op].format & JOF_DETECTING)
return JS_TRUE;
switch (op) {
case JSOP_NULL:
/*
* Special case #1: handle (document.all == null). Don't sweat
* about JS1.2's revision of the equality operators here.
*/
- if (++pc < endpc)
- return *pc == JSOP_EQ || *pc == JSOP_NE;
- return JS_FALSE;
+ pc++;
+ op = js_GetOpcode(cx, script, pc);
+ return op == JSOP_EQ || op == JSOP_NE;
case JSOP_NAME:
/*
* Special case #2: handle (document.all == undefined). Don't
* worry about someone redefining undefined, which was added by
* Edition 3, so is read/write for backward compatibility.
*/
GET_ATOM_FROM_BYTECODE(script, pc, 0, atom);
- if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
- (pc += js_CodeSpec[op].length) < endpc) {
- op = (JSOp) *pc;
+ if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID]) {
+ pc += js_CodeSpec[op].length;
+ op = js_GetOpcode(cx, script, pc);
return op == JSOP_EQ || op == JSOP_NE ||
op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
}
return JS_FALSE;
default:
/*
* At this point, anything but an extended atom index prefix means
* we're not detecting.
*/
if (!(js_CodeSpec[op].format & JOF_INDEXBASE))
return JS_FALSE;
break;
}
}
- return JS_FALSE;
}
/*
* Infer lookup flags from the currently executing bytecode. This does
* not attempt to infer JSRESOLVE_WITH, because the current bytecode
* does not indicate whether we are in a with statement. Return defaultFlags
* if a currently executing bytecode cannot be determined.
*/
@@ -2084,17 +2081,17 @@ InferFlags(JSContext *cx, uintN defaultF
const JSCodeSpec *cs;
uint32 format;
uintN flags = 0;
fp = js_GetTopStackFrame(cx);
if (!fp || !fp->regs)
return defaultFlags;
pc = fp->regs->pc;
- cs = &js_CodeSpec[*pc];
+ cs = &js_CodeSpec[js_GetOpcode(cx, fp->script, pc)];
format = cs->format;
if (JOF_MODE(format) != JOF_NAME)
flags |= JSRESOLVE_QUALIFIED;
if ((format & (JOF_SET | JOF_FOR)) ||
(fp->flags & JSFRAME_ASSIGNING)) {
flags |= JSRESOLVE_ASSIGNING;
} else {
pc += cs->length;
@@ -3941,18 +3938,21 @@ js_GetCurrentBytecodePC(JSContext* cx)
{
jsbytecode *pc = cx->pcHint;
if (!pc || !JS_ON_TRACE(cx)) {
JSStackFrame* fp = js_GetTopStackFrame(cx);
if (fp && fp->regs) {
pc = fp->regs->pc;
// FIXME: Set pc to imacpc when recording JSOP_CALL inside the
// JSOP_GETELEM imacro (bug 476559).
- if (*pc == JSOP_CALL && fp->imacpc && *fp->imacpc == JSOP_GETELEM)
+ if (*pc == JSOP_CALL &&
+ fp->imacpc &&
+ js_GetOpcode(cx, fp->script, fp->imacpc) == JSOP_GETELEM) {
pc = fp->imacpc;
+ }
} else {
pc = NULL;
}
}
return pc;
}
JSBool
@@ -3990,16 +3990,20 @@ js_GetPropertyHelper(JSContext *cx, JSOb
* object foo with no property named 'bar'.
*/
jsbytecode *pc;
if (JSVAL_IS_VOID(*vp) && ((pc = js_GetCurrentBytecodePC(cx)) != NULL)) {
JSOp op;
uintN flags;
op = (JSOp) *pc;
+ if (op == JSOP_TRAP) {
+ JS_ASSERT_NOT_ON_TRACE(cx);
+ op = JS_GetTrapOpcode(cx, cx->fp->script, pc);
+ }
if (op == JSOP_GETXPROP) {
flags = JSREPORT_ERROR;
} else {
if (!JS_HAS_STRICT_OPTION(cx) ||
(op != JSOP_GETPROP && op != JSOP_GETELEM)) {
return JS_TRUE;
}
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -133,19 +133,17 @@ GetJumpOffset(jsbytecode *pc, jsbytecode
uintN
js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc,
ptrdiff_t pcoff)
{
JSOp op;
uintN span, base;
- op = (JSOp)*pc;
- if (op == JSOP_TRAP)
- op = JS_GetTrapOpcode(cx, script, pc);
+ op = js_GetOpcode(cx, script, pc);
JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN);
/*
* We need to detect index base prefix. It presents when resetbase
* follows the bytecode.
*/
span = js_CodeSpec[op].length;
base = 0;
@@ -5206,19 +5204,17 @@ ReconstructPCStack(JSContext *cx, JSScri
* 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 <= target && target < script->code + script->length);
pcdepth = 0;
for (pc = script->main; pc < target; pc += oplen) {
- op = (JSOp) *pc;
- if (op == JSOP_TRAP)
- op = JS_GetTrapOpcode(cx, script, pc);
+ op = js_GetOpcode(cx, script, pc);
cs = &js_CodeSpec[op];
oplen = cs->length;
if (oplen < 0)
oplen = js_GetVariableBytecodeLength(pc);
/*
* A (C ? T : E) expression requires skipping either T (if target is in
* E) or both T and E (if target is after the whole expression) before
@@ -5228,17 +5224,17 @@ ReconstructPCStack(JSContext *cx, JSScri
*/
sn = js_GetSrcNote(script, pc);
if (sn && SN_TYPE(sn) == SRC_COND) {
ptrdiff_t jmpoff, jmplen;
jmpoff = js_GetSrcNoteOffset(sn, 0);
if (pc + jmpoff < target) {
pc += jmpoff;
- op = (JSOp) *pc;
+ op = js_GetOpcode(cx, script, pc);
JS_ASSERT(op == JSOP_GOTO || op == JSOP_GOTOX);
cs = &js_CodeSpec[op];
oplen = cs->length;
JS_ASSERT(oplen > 0);
jmplen = GetJumpOffset(pc, pc);
if (pc + jmplen < target) {
oplen = (uintN) jmplen;
continue;
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1751,32 +1751,34 @@ uintN
js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp)
{
return js_PCToLineNumber(cx, fp->script, fp->imacpc ? fp->imacpc : fp->regs->pc);
}
uintN
js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
{
+ JSOp op;
JSFunction *fun;
uintN lineno;
ptrdiff_t offset, target;
jssrcnote *sn;
JSSrcNoteType type;
/* Cope with JSStackFrame.pc value prior to entering js_Interpret. */
if (!pc)
return 0;
/*
* Special case: function definition needs no line number note because
* the function's script contains its starting line number.
*/
- if (js_CodeSpec[*pc].format & JOF_INDEXBASE)
- pc += js_CodeSpec[*pc].length;
+ op = js_GetOpcode(cx, script, pc);
+ if (js_CodeSpec[op].format & JOF_INDEXBASE)
+ pc += js_CodeSpec[op].length;
if (*pc == JSOP_DEFFUN) {
GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun);
return fun->u.i.script->lineno;
}
/*
* General case: walk through source notes accumulating their deltas,
* keeping track of line-number notes, until we pass the note for pc's
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -40,16 +40,17 @@
#ifndef jsscript_h___
#define jsscript_h___
/*
* JS script descriptor.
*/
#include "jsatom.h"
#include "jsprvtd.h"
+#include "jsdbgapi.h"
JS_BEGIN_EXTERN_C
/*
* Type of try note associated with each catch or finally block, and also with
* for-in loops.
*/
typedef enum JSTryNoteKind {
@@ -310,16 +311,25 @@ extern uintN
js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
extern jsbytecode *
js_LineNumberToPC(JSScript *script, uintN lineno);
extern JS_FRIEND_API(uintN)
js_GetScriptLineExtent(JSScript *script);
+static JS_INLINE JSOp
+js_GetOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
+{
+ JSOp op = (JSOp) *pc;
+ if (op == JSOP_TRAP)
+ op = JS_GetTrapOpcode(cx, script, pc);
+ return op;
+}
+
/*
* If magic is non-null, js_XDRScript succeeds on magic number mismatch but
* returns false in *magic; it reflects a match via a true *magic out param.
* If magic is null, js_XDRScript returns false on bad magic number errors,
* which it reports.
*
* NB: callers must call js_CallNewScriptHook after successful JSXDR_DECODE
* and subsequent set-up of owning function or script object, if any.