--- a/js/src/builtins.tbl
+++ b/js/src/builtins.tbl
@@ -72,20 +72,16 @@ BUILTIN1(extern, DOUBLE, js_UnboxDoub
BUILTIN1(extern, INT32, js_UnboxInt32, JSVAL, 1, 1)
BUILTIN2(extern, DOUBLE, js_dmod, DOUBLE, DOUBLE, 1, 1)
BUILTIN2(extern, INT32, js_imod, INT32, INT32, 1, 1)
BUILTIN1(extern, INT32, js_DoubleToInt32, DOUBLE, 1, 1)
BUILTIN1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, 1)
BUILTIN2(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, 1, 1)
BUILTIN2(extern, INT32, js_StringToInt32, CONTEXT, STRING, 1, 1)
-BUILTIN3(extern, JSVAL, js_Any_getprop, CONTEXT, OBJECT, STRING, 0, 0)
-BUILTIN4(extern, BOOL, js_Any_setprop, CONTEXT, OBJECT, STRING, JSVAL, 0, 0)
-BUILTIN3(extern, JSVAL, js_Any_getelem, CONTEXT, OBJECT, INT32, 0, 0)
-BUILTIN4(extern, BOOL, js_Any_setelem, CONTEXT, OBJECT, INT32, JSVAL, 0, 0)
BUILTIN2(FRIEND, BOOL, js_CloseIterator, CONTEXT, JSVAL, 0, 0)
BUILTIN2(extern, SIDEEXIT, js_CallTree, INTERPSTATE, FRAGMENT, 0, 0)
BUILTIN2(extern, OBJECT, js_FastNewObject, CONTEXT, OBJECT, 0, 0)
BUILTIN3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SCOPEPROP, 0, 0)
BUILTIN3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING, 0, 0)
BUILTIN3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, INT32, 0, 0)
BUILTIN3(extern, JSVAL, js_CallGetter, CONTEXT, OBJECT, SCOPEPROP, 0, 0)
BUILTIN2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, 1)
--- a/js/src/imacros.c.out
+++ b/js/src/imacros.c.out
@@ -589,16 +589,74 @@ static struct {
/* 2*/ JSOP_CALLBUILTIN, ((JSBUILTIN_CallIteratorNext) & 0xff00) >> 8, ((JSBUILTIN_CallIteratorNext) & 0xff),
/* 5*/ JSOP_CALL, 0, 0,
/* 8*/ JSOP_DUP,
/* 9*/ JSOP_HOLE,
/*10*/ JSOP_STRICTNE,
/*11*/ JSOP_STOP,
},
};
+static struct {
+ jsbytecode getprop[10];
+ jsbytecode getelem[10];
+} getelem_imacros = {
+ {
+/* 0*/ JSOP_SWAP,
+/* 1*/ JSOP_CALLBUILTIN, ((JSBUILTIN_GetProperty) & 0xff00) >> 8, ((JSBUILTIN_GetProperty) & 0xff),
+/* 4*/ JSOP_PICK, 2,
+/* 6*/ JSOP_CALL, 0, 1,
+/* 9*/ JSOP_STOP,
+ },
+ {
+/* 0*/ JSOP_SWAP,
+/* 1*/ JSOP_CALLBUILTIN, ((JSBUILTIN_GetElement) & 0xff00) >> 8, ((JSBUILTIN_GetElement) & 0xff),
+/* 4*/ JSOP_PICK, 2,
+/* 6*/ JSOP_CALL, 0, 1,
+/* 9*/ JSOP_STOP,
+ },
+};
+static struct {
+ jsbytecode setprop[15];
+ jsbytecode setelem[15];
+} setelem_imacros = {
+ {
+/* 0*/ JSOP_DUP,
+/* 1*/ JSOP_PICK, 3,
+/* 3*/ JSOP_CALLBUILTIN, ((JSBUILTIN_SetProperty) & 0xff00) >> 8, ((JSBUILTIN_SetProperty) & 0xff),
+/* 6*/ JSOP_PICK, 4,
+/* 8*/ JSOP_PICK, 4,
+/*10*/ JSOP_CALL, 0, 2,
+/*13*/ JSOP_POP,
+/*14*/ JSOP_STOP,
+ },
+ {
+/* 0*/ JSOP_DUP,
+/* 1*/ JSOP_PICK, 3,
+/* 3*/ JSOP_CALLBUILTIN, ((JSBUILTIN_SetElement) & 0xff00) >> 8, ((JSBUILTIN_SetElement) & 0xff),
+/* 6*/ JSOP_PICK, 4,
+/* 8*/ JSOP_PICK, 4,
+/*10*/ JSOP_CALL, 0, 2,
+/*13*/ JSOP_POP,
+/*14*/ JSOP_STOP,
+ },
+};
+static struct {
+ jsbytecode initelem[15];
+} initelem_imacros = {
+ {
+/* 0*/ JSOP_PICK, 2,
+/* 2*/ JSOP_DUP,
+/* 3*/ JSOP_CALLBUILTIN, ((JSBUILTIN_SetElement) & 0xff00) >> 8, ((JSBUILTIN_SetElement) & 0xff),
+/* 6*/ JSOP_PICK, 4,
+/* 8*/ JSOP_PICK, 4,
+/*10*/ JSOP_CALL, 0, 2,
+/*13*/ JSOP_POP,
+/*14*/ JSOP_STOP,
+ },
+};
uint8 js_opcode2extra[JSOP_LIMIT] = {
0, /* JSOP_NOP */
0, /* JSOP_PUSH */
0, /* JSOP_POPV */
0, /* JSOP_ENTERWITH */
0, /* JSOP_LEAVEWITH */
0, /* JSOP_RETURN */
0, /* JSOP_GOTO */
@@ -645,18 +703,18 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
0, /* JSOP_NAMEINC */
0, /* JSOP_PROPINC */
0, /* JSOP_ELEMINC */
0, /* JSOP_NAMEDEC */
0, /* JSOP_PROPDEC */
0, /* JSOP_ELEMDEC */
0, /* JSOP_GETPROP */
0, /* JSOP_SETPROP */
- 0, /* JSOP_GETELEM */
- 0, /* JSOP_SETELEM */
+ 2, /* JSOP_GETELEM */
+ 2, /* JSOP_SETELEM */
0, /* JSOP_CALLNAME */
0, /* JSOP_CALL */
0, /* JSOP_NAME */
0, /* JSOP_DOUBLE */
0, /* JSOP_STRING */
0, /* JSOP_ZERO */
0, /* JSOP_ONE */
0, /* JSOP_NULL */
@@ -682,17 +740,17 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
0, /* JSOP_GETARG */
0, /* JSOP_SETARG */
0, /* JSOP_GETLOCAL */
0, /* JSOP_SETLOCAL */
0, /* JSOP_UINT16 */
0, /* JSOP_NEWINIT */
0, /* JSOP_ENDINIT */
0, /* JSOP_INITPROP */
- 0, /* JSOP_INITELEM */
+ 2, /* JSOP_INITELEM */
0, /* JSOP_DEFSHARP */
0, /* JSOP_USESHARP */
0, /* JSOP_INCARG */
0, /* JSOP_DECARG */
0, /* JSOP_ARGINC */
0, /* JSOP_ARGDEC */
0, /* JSOP_INCLOCAL */
0, /* JSOP_DECLOCAL */
--- a/js/src/imacros.jsasm
+++ b/js/src/imacros.jsasm
@@ -1,8 +1,9 @@
+# -*- indent-tabs-mode: nil; -*-
# vim: set sw=4 ts=8 et tw=78 ft=asm:
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
@@ -630,8 +631,69 @@ 4: imacop
call 0 # iterobj nextval?
dup # iterobj nextval? nextval?
hole # iterobj nextval? nextval? hole
strictne # iterobj nextval? boolean
stop
.end
.end
+
+.igroup getelem JSOP_GETELEM
+
+ .imacro getprop # obj name
+ swap # name obj
+ callbuiltin (JSBUILTIN_GetProperty) # name fun obj
+ pick 2 # fun obj name
+ call 1 # propval
+ stop
+ .end
+
+ .imacro getelem # obj i
+ swap # i obj
+ callbuiltin (JSBUILTIN_GetElement) # i fun obj
+ pick 2 # fun obj i
+ call 1 # propval
+ stop
+ .end
+
+.end
+
+.igroup setelem JSOP_SETELEM
+
+ .imacro setprop # obj name val
+ dup # obj name val val
+ pick 3 # name val val obj
+ callbuiltin (JSBUILTIN_SetProperty) # name val val fun obj
+ pick 4 # val val fun obj name
+ pick 4 # val fun obj name val
+ call 2 # val junk
+ pop # val
+ stop
+ .end
+
+ .imacro setelem # obj i val
+ dup # obj i val val
+ pick 3 # i val val obj
+ callbuiltin (JSBUILTIN_SetElement) # i val val fun obj
+ pick 4 # val val fun obj i
+ pick 4 # val fun obj i val
+ call 2 # val junk
+ pop # val
+ stop
+ .end
+
+.end
+
+.igroup initelem JSOP_INITELEM
+
+ .imacro initelem # obj i val
+ pick 2 # i val obj
+ dup # i val obj obj
+ callbuiltin (JSBUILTIN_SetElement) # i val obj fun obj
+ pick 4 # val obj fun obj i
+ pick 4 # obj fun obj i val
+ call 2 # obj junk
+ pop # obj
+ stop
+ .end
+
+.end
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -182,72 +182,16 @@ js_StringToInt32(JSContext* cx, JSString
jsdouble d;
JSSTRING_CHARS_AND_END(str, bp, end);
if (!js_strtod(cx, bp, end, &ep, &d) || js_SkipWhiteSpace(ep, end) != end)
return 0;
return js_DoubleToECMAInt32(d);
}
-static inline JSBool
-js_Int32ToId(JSContext* cx, int32 index, jsid* id)
-{
- if (index <= JSVAL_INT_MAX) {
- *id = INT_TO_JSID(index);
- return JS_TRUE;
- }
- JSString* str = js_NumberToString(cx, index);
- if (!str)
- return JS_FALSE;
- return js_ValueToStringId(cx, STRING_TO_JSVAL(str), id);
-}
-
-jsval FASTCALL
-js_Any_getprop(JSContext* cx, JSObject* obj, JSString* idstr)
-{
- jsval v;
- jsid id;
-
- if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id))
- return JSVAL_ERROR_COOKIE;
- if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
- return JSVAL_ERROR_COOKIE;
- return v;
-}
-
-JSBool FASTCALL
-js_Any_setprop(JSContext* cx, JSObject* obj, JSString* idstr, jsval v)
-{
- jsid id;
- if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id))
- return JS_FALSE;
- return OBJ_SET_PROPERTY(cx, obj, id, &v);
-}
-
-jsval FASTCALL
-js_Any_getelem(JSContext* cx, JSObject* obj, int32 index)
-{
- jsval v;
- jsid id;
- if (!js_Int32ToId(cx, index, &id))
- return JSVAL_ERROR_COOKIE;
- if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
- return JSVAL_ERROR_COOKIE;
- return v;
-}
-
-JSBool FASTCALL
-js_Any_setelem(JSContext* cx, JSObject* obj, int32 index, jsval v)
-{
- jsid id;
- if (!js_Int32ToId(cx, index, &id))
- return JSVAL_ERROR_COOKIE;
- return OBJ_SET_PROPERTY(cx, obj, id, &v);
-}
-
SideExit* FASTCALL
js_CallTree(InterpState* state, Fragment* f)
{
union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u;
u.code = f->code();
JS_ASSERT(u.code);
--- a/js/src/jsbuiltins.h
+++ b/js/src/jsbuiltins.h
@@ -317,16 +317,29 @@ struct JSTraceableNative {
#define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args
jsdouble FASTCALL
js_StringToNumber(JSContext* cx, JSString* str);
jsdouble FASTCALL
js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed);
+static JS_INLINE JSBool
+js_Int32ToId(JSContext* cx, int32 index, jsid* id)
+{
+ if (index <= JSVAL_INT_MAX) {
+ *id = INT_TO_JSID(index);
+ return JS_TRUE;
+ }
+ JSString* str = js_NumberToString(cx, index);
+ if (!str)
+ return JS_FALSE;
+ return js_ValueToStringId(cx, STRING_TO_JSVAL(str), id);
+}
+
#else
#define JS_DEFINE_CALLINFO_1(linkage, rt, op, at0, cse, fold)
#define JS_DEFINE_CALLINFO_2(linkage, rt, op, at0, at1, cse, fold)
#define JS_DEFINE_CALLINFO_3(linkage, rt, op, at0, at1, at2, cse, fold)
#define JS_DEFINE_CALLINFO_4(linkage, rt, op, at0, at1, at2, at3, cse, fold)
#define JS_DEFINE_CALLINFO_5(linkage, rt, op, at0, at1, at2, at3, at4, cse, fold)
#define JS_DECLARE_CALLINFO(name)
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -252,16 +252,20 @@ typedef enum JSRuntimeState {
JSRTS_LAUNCHING,
JSRTS_UP,
JSRTS_LANDING
} JSRuntimeState;
typedef enum JSBuiltinFunctionId {
JSBUILTIN_ObjectToIterator,
JSBUILTIN_CallIteratorNext,
+ JSBUILTIN_GetProperty,
+ JSBUILTIN_GetElement,
+ JSBUILTIN_SetProperty,
+ JSBUILTIN_SetElement,
JSBUILTIN_LIMIT
} JSBuiltinFunctionId;
typedef struct JSPropertyTreeEntry {
JSDHashEntryHdr hdr;
JSScopeProperty *child;
} JSPropertyTreeEntry;
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -484,18 +484,17 @@ OPDEF(JSOP_TYPEOFEXPR, 198,"typeofexp
* Block-local scope support.
*/
OPDEF(JSOP_ENTERBLOCK, 199,"enterblock", NULL, 3, 0, -1, 0, JOF_OBJECT)
OPDEF(JSOP_LEAVEBLOCK, 200,"leaveblock", NULL, 3, -1, 0, 0, JOF_UINT16)
/*
* Pick an element from the stack.
*/
-OPDEF(JSOP_PICK, 201,"pick", NULL, 2, 1, 0, 0, JOF_UINT8)
-
+OPDEF(JSOP_PICK, 201,"pick", NULL, 2, 0, 0, 0, JOF_UINT8)
/* Throws a TypeError if the value at the top of the stack is not primitive. */
OPDEF(JSOP_PRIMTOP, 202, "primtop", NULL, 1, 1, 1, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED203, 203,"unused203", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED204, 204,"unused204", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED205, 205,"unused205", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED206, 206,"unused206", NULL, 1, 0, 0, 0, JOF_BYTE)
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -4223,16 +4223,17 @@ TraceRecorder::monitorRecording(JSContex
(cx->fp->imacpc) \
? 0 \
: PTRDIFF(cx->fp->regs->pc, \
cx->fp->script->code, \
jsbytecode), \
!cx->fp->imacpc, stdout);) \
flag = tr->record_##x(); \
if (x == JSOP_ITER || x == JSOP_NEXTITER || x == JSOP_APPLY || \
+ x == JSOP_GETELEM || x == JSOP_SETELEM || x== JSOP_INITELEM || \
JSOP_IS_BINARY(x) || JSOP_IS_UNARY(x) || \
JSOP_IS_EQUALITY(x)) { \
goto imacro; \
} \
break;
# include "jsopcode.tbl"
# undef OPDEF
}
@@ -6804,16 +6805,79 @@ TraceRecorder::record_SetPropMiss(JSProp
JS_ASSERT(scope->object == obj);
JS_ASSERT(scope->shape == PCVCAP_SHAPE(entry->vcap));
JS_ASSERT(SCOPE_HAS_PROPERTY(scope, sprop));
#endif
return record_SetPropHit(entry, sprop);
}
+/* Functions used by JSOP_GETELEM. */
+
+static JSBool
+GetProperty(JSContext *cx, uintN argc, jsval *vp)
+{
+ jsval *argv;
+ jsid id;
+
+ JS_ASSERT(argc == 1);
+ argv = JS_ARGV(cx, vp);
+ JS_ASSERT(JSVAL_IS_STRING(argv[0]));
+ if (!js_ValueToStringId(cx, argv[0], &id))
+ return JS_FALSE;
+ argv[0] = ID_TO_VALUE(id);
+ return OBJ_GET_PROPERTY(cx, JS_THIS_OBJECT(cx, vp), id, &JS_RVAL(cx, vp));
+}
+
+static jsval FASTCALL
+GetProperty_tn(JSContext *cx, JSObject *obj, JSString *name)
+{
+ jsid id;
+ jsval v;
+
+ if (!js_ValueToStringId(cx, STRING_TO_JSVAL(name), &id) ||
+ !OBJ_GET_PROPERTY(cx, obj, id, &v)) {
+ return JSVAL_ERROR_COOKIE;
+ }
+ return v;
+}
+
+static JSBool
+GetElement(JSContext *cx, uintN argc, jsval *vp)
+{
+ jsval *argv;
+ jsid id;
+
+ JS_ASSERT(argc == 1);
+ argv = JS_ARGV(cx, vp);
+ JS_ASSERT(JSVAL_IS_NUMBER(argv[0]));
+ if (!JS_ValueToId(cx, argv[0], &id))
+ return JS_FALSE;
+ argv[0] = ID_TO_VALUE(id);
+ return OBJ_GET_PROPERTY(cx, JS_THIS_OBJECT(cx, vp), id, &JS_RVAL(cx, vp));
+}
+
+static jsval FASTCALL
+GetElement_tn(JSContext* cx, JSObject* obj, int32 index)
+{
+ jsval v;
+ jsid id;
+
+ if (!js_Int32ToId(cx, index, &id))
+ return JSVAL_ERROR_COOKIE;
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+ return JSVAL_ERROR_COOKIE;
+ return v;
+}
+
+JS_DEFINE_TRCINFO_1(GetProperty,
+ (3, (static, JSVAL_FAIL, GetProperty_tn, CONTEXT, THIS, STRING, 0, 0)))
+JS_DEFINE_TRCINFO_1(GetElement,
+ (3, (extern, JSVAL_FAIL, GetElement_tn, CONTEXT, THIS, INT32, 0, 0)))
+
JS_REQUIRES_STACK bool
TraceRecorder::record_JSOP_GETELEM()
{
jsval& idx = stackval(-1);
jsval& lval = stackval(-2);
LIns* obj_ins = get(&lval);
LIns* idx_ins = get(&idx);
@@ -6848,54 +6912,108 @@ TraceRecorder::record_JSOP_GETELEM()
if (js_IdIsIndex(idx, &index) && guardDenseArray(obj, obj_ins, BRANCH_EXIT)) {
v = (index >= ARRAY_DENSE_LENGTH(obj)) ? JSVAL_HOLE : obj->dslots[index];
if (v == JSVAL_HOLE)
ABORT_TRACE("can't see through hole in dense array");
} else {
if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, getProperty), &v))
return false;
}
- LIns* args[] = { idx_ins, obj_ins, cx_ins };
- v_ins = lir->insCall(&js_Any_getprop_ci, args);
- guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), MISMATCH_EXIT);
- unbox_jsval(v, v_ins);
- set(&lval, v_ins);
- return true;
+ return call_imacro(getelem_imacros.getprop);
}
/* At this point we expect a whole number or we bail. */
if (!JSVAL_IS_INT(idx))
ABORT_TRACE("non-string, non-int JSOP_GETELEM index");
if (JSVAL_TO_INT(idx) < 0)
ABORT_TRACE("negative JSOP_GETELEM index");
/* Accessing an object using integer index but not a dense array. */
if (!OBJ_IS_DENSE_ARRAY(cx, obj)) {
idx_ins = makeNumberInt32(idx_ins);
- LIns* args[] = { idx_ins, obj_ins, cx_ins };
if (!js_IndexToId(cx, JSVAL_TO_INT(idx), &id))
return false;
- idx = ID_TO_VALUE(id);
if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, getProperty), &v))
return false;
- LIns* v_ins = lir->insCall(&js_Any_getelem_ci, args);
- guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), MISMATCH_EXIT);
- unbox_jsval(v, v_ins);
- set(&lval, v_ins);
- return true;
+ return call_imacro(getelem_imacros.getelem);
}
jsval* vp;
LIns* addr_ins;
if (!elem(lval, idx, vp, v_ins, addr_ins))
return false;
set(&lval, v_ins);
return true;
}
+/* Functions used by JSOP_SETELEM */
+
+static JSBool
+SetProperty(JSContext *cx, uintN argc, jsval *vp)
+{
+ jsval *argv;
+ jsid id;
+
+ JS_ASSERT(argc == 2);
+ argv = JS_ARGV(cx, vp);
+ JS_ASSERT(JSVAL_IS_STRING(argv[0]));
+ if (!js_ValueToStringId(cx, argv[0], &id))
+ return JS_FALSE;
+ argv[0] = ID_TO_VALUE(id);
+ if (!OBJ_SET_PROPERTY(cx, JS_THIS_OBJECT(cx, vp), id, &argv[1]))
+ return JS_FALSE;
+ JS_SET_RVAL(cx, vp, JSVAL_VOID);
+ return JS_TRUE;
+}
+
+static int32 FASTCALL
+SetProperty_tn(JSContext* cx, JSObject* obj, JSString* idstr, jsval v)
+{
+ jsid id;
+
+ if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id) ||
+ !OBJ_SET_PROPERTY(cx, obj, id, &v)) {
+ return JSVAL_TO_BOOLEAN(JSVAL_VOID);
+ }
+ return JSVAL_TRUE;
+}
+
+static JSBool
+SetElement(JSContext *cx, uintN argc, jsval *vp)
+{
+ jsval *argv;
+ jsid id;
+
+ JS_ASSERT(argc == 2);
+ argv = JS_ARGV(cx, vp);
+ JS_ASSERT(JSVAL_IS_NUMBER(argv[0]));
+ if (!JS_ValueToId(cx, argv[0], &id))
+ return JS_FALSE;
+ argv[0] = ID_TO_VALUE(id);
+ if (!OBJ_SET_PROPERTY(cx, JS_THIS_OBJECT(cx, vp), id, &argv[1]))
+ return JS_FALSE;
+ JS_SET_RVAL(cx, vp, JSVAL_VOID);
+ return JS_TRUE;
+}
+
+static int32 FASTCALL
+SetElement_tn(JSContext* cx, JSObject* obj, int32 index, jsval v)
+{
+ jsid id;
+
+ if (!js_Int32ToId(cx, index, &id) || !OBJ_SET_PROPERTY(cx, obj, id, &v))
+ return JSVAL_TO_BOOLEAN(JSVAL_VOID);
+ return JSVAL_TRUE;
+}
+
+JS_DEFINE_TRCINFO_1(SetProperty,
+ (4, (extern, BOOL_FAIL, SetProperty_tn, CONTEXT, THIS, STRING, JSVAL, 0, 0)))
+JS_DEFINE_TRCINFO_1(SetElement,
+ (4, (extern, BOOL_FAIL, SetElement_tn, CONTEXT, THIS, INT32, JSVAL, 0, 0)))
+
JS_REQUIRES_STACK bool
TraceRecorder::record_JSOP_SETELEM()
{
jsval& v = stackval(-1);
jsval& idx = stackval(-2);
jsval& lval = stackval(-3);
/* no guards for type checks, trace specialized this already */
@@ -6913,45 +7031,46 @@ TraceRecorder::record_JSOP_SETELEM()
if (JSVAL_IS_STRING(idx)) {
if (!js_ValueToStringId(cx, idx, &id))
return false;
// Store the interned string to the stack to save the interpreter from redoing this work.
idx = ID_TO_VALUE(id);
if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, setProperty), NULL))
return false;
- LIns* args[] = { boxed_v_ins, idx_ins, obj_ins, cx_ins };
- LIns* ok_ins = lir->insCall(&js_Any_setprop_ci, args);
- guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT);
- } else if (JSVAL_IS_INT(idx)) {
+ return call_imacro(setelem_imacros.setprop);
+ }
+ if (JSVAL_IS_INT(idx)) {
if (JSVAL_TO_INT(idx) < 0)
ABORT_TRACE("negative JSOP_SETELEM index");
idx_ins = makeNumberInt32(idx_ins);
- LIns* args[] = { boxed_v_ins, idx_ins, obj_ins, cx_ins };
- LIns* res_ins;
- if (guardDenseArray(obj, obj_ins, BRANCH_EXIT)) {
- res_ins = lir->insCall(&js_Array_dense_setelem_ci, args);
- } else {
+
+ if (!guardDenseArray(obj, obj_ins, BRANCH_EXIT)) {
if (!js_IndexToId(cx, JSVAL_TO_INT(idx), &id))
return false;
idx = ID_TO_VALUE(id);
if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, setProperty), NULL))
return false;
- res_ins = lir->insCall(&js_Any_setelem_ci, args);
+ jsbytecode* pc = cx->fp->regs->pc;
+ return call_imacro((*pc == JSOP_INITELEM)
+ ? initelem_imacros.initelem
+ : setelem_imacros.setelem);
}
+
+ LIns* args[] = { boxed_v_ins, idx_ins, obj_ins, cx_ins };
+ LIns* res_ins = lir->insCall(&js_Array_dense_setelem_ci, args);
guard(false, lir->ins_eq0(res_ins), MISMATCH_EXIT);
- } else {
- ABORT_TRACE("non-string, non-int JSOP_SETELEM index");
- }
-
- jsbytecode* pc = cx->fp->regs->pc;
- if (*pc == JSOP_SETELEM && pc[JSOP_SETELEM_LENGTH] != JSOP_POP)
- set(&lval, v_ins);
-
- return true;
+
+ jsbytecode* pc = cx->fp->regs->pc;
+ if (*pc == JSOP_SETELEM && pc[JSOP_SETELEM_LENGTH] != JSOP_POP)
+ set(&lval, v_ins);
+
+ return true;
+ }
+ ABORT_TRACE("non-string, non-int JSOP_SETELEM index");
}
JS_REQUIRES_STACK bool
TraceRecorder::record_JSOP_CALLNAME()
{
JSObject* obj = cx->fp->scopeChain;
if (obj != globalObj) {
jsval* vp;
@@ -8806,17 +8925,21 @@ JS_DEFINE_TRCINFO_1(ObjectToIterator,
JS_DEFINE_TRCINFO_1(CallIteratorNext,
(2, (static, JSVAL_FAIL, CallIteratorNext_tn, CONTEXT, THIS, 0, 0)))
static const struct BuiltinFunctionInfo {
JSTraceableNative *tn;
int nargs;
} builtinFunctionInfo[JSBUILTIN_LIMIT] = {
{ObjectToIterator_trcinfo, 1},
- {CallIteratorNext_trcinfo, 0}
+ {CallIteratorNext_trcinfo, 0},
+ {GetProperty_trcinfo, 1},
+ {GetElement_trcinfo, 1},
+ {SetProperty_trcinfo, 2},
+ {SetElement_trcinfo, 2}
};
JSObject *
js_GetBuiltinFunction(JSContext *cx, uintN index)
{
JSRuntime *rt = cx->runtime;
JSObject *funobj = rt->builtinFunctions[index];
@@ -9022,16 +9145,19 @@ InitIMacroCode()
for (uintN op = JSOP_BITOR; op <= JSOP_MOD; op++)
imacro_code[op] = (jsbytecode*)&binary_imacros - 1;
// NB: above loop mis-set JSOP_ADD's entry, so order here is crucial.
imacro_code[JSOP_ADD] = (jsbytecode*)&add_imacros - 1;
imacro_code[JSOP_ITER] = (jsbytecode*)&iter_imacros - 1;
imacro_code[JSOP_NEXTITER] = (jsbytecode*)&nextiter_imacros - 1;
+ imacro_code[JSOP_GETELEM] = (jsbytecode*)&getelem_imacros - 1;
+ imacro_code[JSOP_SETELEM] = (jsbytecode*)&setelem_imacros - 1;
+ imacro_code[JSOP_INITELEM] = (jsbytecode*)&initelem_imacros - 1;
imacro_code[JSOP_APPLY] = (jsbytecode*)&apply_imacros - 1;
imacro_code[JSOP_NEG] = (jsbytecode*)&unary_imacros - 1;
imacro_code[JSOP_POS] = (jsbytecode*)&unary_imacros - 1;
imacro_code[JSOP_EQ] = (jsbytecode*)&equality_imacros - 1;
imacro_code[JSOP_NE] = (jsbytecode*)&equality_imacros - 1;
}
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -4102,16 +4102,57 @@ function testInterpreterReentry3() {
for (let i=0;i<5;++i) this["y" + i] = function(){};
this.__defineGetter__('e', function (x2) { yield; });
[1 for each (a in this) for (b in {})];
return 1;
}
testInterpreterReentry3.expected = 1;
test(testInterpreterReentry3);
+function testInterpreterReentry4() {
+ var obj = {a:1, b:1, c:1, d:1, get e() 1000 };
+ for (var p in obj)
+ obj[p];
+}
+test(testInterpreterReentry4);
+
+function testInterpreterReentry5() {
+ var arr = [0, 1, 2, 3, 4];
+ arr.__defineGetter__("4", function() 1000);
+ for (var i = 0; i < 5; i++)
+ arr[i];
+ for (var p in arr)
+ arr[p];
+}
+test(testInterpreterReentry5);
+
+/* // These tests should pass but currently crash, pending bug 462027.
+function testInterpreterReentry6() {
+ var obj = {a:1, b:1, c:1, d:1, set e(x) { this._e = x; }};
+ for (var p in obj)
+ obj[p] = "grue";
+ return obj._e;
+}
+testInterpreterReentry6.expected = "grue";
+test(testInterpreterReentry6);
+
+function testInterpreterReentry7() {
+ var arr = [0, 1, 2, 3, 4];
+ arr.__defineSetter__("4", function(x) { this._4 = x; });
+ for (var i = 0; i < 5; i++)
+ arr[i] = "grue";
+ var tmp = arr._4;
+ for (var p in arr)
+ arr[p] = "bleen";
+ return tmp + " " + arr._4;
+}
+testInterpreterReentry7.expected = "grue bleen";
+test(testInterpreterReentry7);
+*/
+
/*****************************************************************************
* *
* _____ _ _ _____ ______ _____ _______ *
* |_ _| \ | |/ ____| ____| __ \__ __| *
* | | | \| | (___ | |__ | |__) | | | *
* | | | . ` |\___ \| __| | _ / | | *
* _| |_| |\ |____) | |____| | \ \ | | *
* |_____|_| \_|_____/|______|_| \_\ |_| *