This commit is contained in:
Andreas Gal 2008-08-12 20:19:05 -07:00
commit 3fd013cd9b
9 changed files with 231 additions and 80 deletions

View File

@ -57,6 +57,10 @@ BUILTIN3(String_getelem, LO, LO, LO, LO, JSString*, JSContext*, JSString*
BUILTIN2(String_fromCharCode, LO, LO, LO, JSString*, JSContext*, jsint, 1, 1)
BUILTIN2(String_p_charCodeAt, LO, LO, LO, jsint, JSString*, jsint, 1, 1)
BUILTIN3(String_p_concat_1int, LO, LO, LO, LO, JSString*, JSContest*, JSString*, jsint, 1, 1)
BUILTIN3(String_p_match, LO, LO, LO, LO, JSObject*, JSContext*, JSString*, JSObject*, 1, 1)
BUILTIN4(String_p_replace_fun, LO, LO, LO, LO, LO, JSString*, JSContext*, JSString*, JSObject*, JSObject*, 1, 1)
BUILTIN4(String_p_replace_str, LO, LO, LO, LO, LO, JSString*, JSContext*, JSString*, JSObject*, JSString*, 1, 1)
BUILTIN5(String_p_replace_str3, LO, LO, LO, LO, LO, LO, JSString*, JSContext*, JSString*, JSString*, JSString*, JSString*, 1, 1)
BUILTIN1(Math_random, LO, F, jsdouble, JSRuntime*, 1, 1)
BUILTIN2(EqualStrings, LO, LO, LO, bool, JSString*, JSString*, 1, 1)
BUILTIN2(CompareStrings, LO, LO, LO, bool, JSString*, JSString*, 1, 1)
@ -69,6 +73,7 @@ BUILTIN2(CloseIterator, LO, LO, LO, bool, JSContext*, jsval, 1,
BUILTIN2(CallTree, LO, LO, LO, nanojit::GuardRecord*, avmplus::InterpState*, nanojit::Fragment*, 0, 0)
BUILTIN2(FastNewObject, LO, LO, LO, JSObject*, JSContext*, JSObject*, 1, 1)
BUILTIN3(AddProperty, LO, LO, LO, LO, bool, JSContext*, JSObject*, JSScopeProperty*, 1, 1)
BUILTIN3(CallGetter, LO, LO, LO, LO, jsval, JSContext*, JSObject*, JSScopeProperty*, 1, 1)
BUILTIN2(TypeOfObject, LO, LO, LO, JSString*, JSContext*, JSObject*, 1, 1)
BUILTIN2(TypeOfBoolean, LO, LO, LO, JSString*, JSContext*, jsint, 1, 1)
BUILTIN2(NumberToString, LO, F, LO, JSString*, JSContext*, jsdouble, 1, 1)

View File

@ -266,6 +266,55 @@ js_String_p_concat_1int(JSContext* cx, JSString* str, jsint i)
return js_ConcatStrings(cx, str, istr);
}
JSObject* FASTCALL
js_String_p_match(JSContext* cx, JSString* str, JSObject* regexp)
{
jsval vp[4] = { JSVAL_NULL, STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) };
if (!js_str_match(cx, 1, vp))
return (JSObject*) JSVAL_TO_BOOLEAN(JSVAL_VOID);
JS_ASSERT(JSVAL_IS_NULL(vp[0]) ||
(!JSVAL_IS_PRIMITIVE(vp[0]) && OBJ_IS_ARRAY(cx, JSVAL_TO_OBJECT(vp[0]))));
return JSVAL_TO_OBJECT(vp[0]);
}
JSString* FASTCALL
js_String_p_replace_fun(JSContext* cx, JSString* str, JSObject* regexp, JSObject* lambda)
{
jsval vp[4] = {
JSVAL_NULL, STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp), OBJECT_TO_JSVAL(lambda)
};
if (!js_StringReplaceHelper(cx, 2, lambda, NULL, vp))
return NULL;
JS_ASSERT(JSVAL_IS_STRING(vp[0]));
return JSVAL_TO_STRING(vp[0]);
}
JSString* FASTCALL
js_String_p_replace_str(JSContext* cx, JSString* str, JSObject* regexp, JSString* repstr)
{
jsval vp[4] = {
JSVAL_NULL, STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp), STRING_TO_JSVAL(repstr)
};
if (!js_StringReplaceHelper(cx, 2, NULL, repstr, vp))
return NULL;
JS_ASSERT(JSVAL_IS_STRING(vp[0]));
return JSVAL_TO_STRING(vp[0]);
}
JSString* FASTCALL
js_String_p_replace_str3(JSContext* cx, JSString* str, JSString* patstr, JSString* repstr,
JSString* flagstr)
{
jsval vp[5] = {
JSVAL_NULL, STRING_TO_JSVAL(str), STRING_TO_JSVAL(patstr), STRING_TO_JSVAL(repstr),
STRING_TO_JSVAL(flagstr)
};
if (!js_StringReplaceHelper(cx, 3, NULL, repstr, vp))
return NULL;
JS_ASSERT(JSVAL_IS_STRING(vp[0]));
return JSVAL_TO_STRING(vp[0]);
}
jsdouble FASTCALL
js_StringToNumber(JSContext* cx, JSString* str)
{
@ -444,6 +493,16 @@ js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
return false;
}
jsval FASTCALL
js_CallGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
{
JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop));
jsval v;
if (!SPROP_GET(cx, sprop, obj, obj, &v))
return JSVAL_ERROR_COOKIE;
return v;
}
JSString* FASTCALL
js_TypeOfObject(JSContext* cx, JSObject* obj)
{
@ -504,8 +563,10 @@ js_BooleanToNumber(JSContext* cx, jsint unboxed)
{ (intptr_t)&js_##op, (at0 << 4) | (at1 << 2) | atr, cse, fold NAME(op) },
#define BUILTIN3(op, at0, at1, at2, atr, tr, t0, t1, t2, cse, fold) \
{ (intptr_t)&js_##op, (at0 << 6) | (at1 << 4) | (at2 << 2) | atr, cse, fold NAME(op) },
#define BUILTIN4(op, at0, at1, at2, at3, atr, tr, t0, t1, t2, t3, cse, fold) \
#define BUILTIN4(op, at0, at1, at2, at3, atr, tr, t0, t1, t2, t3, cse, fold) \
{ (intptr_t)&js_##op, (at0 << 8) | (at1 << 6) | (at2 << 4) | (at3 << 2) | atr, cse, fold NAME(op) },
#define BUILTIN5(op, at0, at1, at2, at3, at4, atr, tr, t0, t1, t2, t3, t4, cse, fold) \
{ (intptr_t)&js_##op, (at0 << 10) | (at1 << 8) | (at2 << 6) | (at3 << 4) | (at4 << 2) | atr, cse, fold NAME(op) },
struct CallInfo builtins[] = {
#include "builtins.tbl"

View File

@ -1905,7 +1905,7 @@ file_list(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSFILE_CHECK_NATIVE("list");
if (argc==1) {
if (JSVAL_IS_REGEXP(cx, argv[0])) {
if (VALUE_IS_REGEXP(cx, argv[0])) {
re = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
}else
if (VALUE_IS_FUNCTION(cx, argv[0])) {

View File

@ -3592,15 +3592,6 @@ out:
/************************************************************************/
enum regexp_tinyid {
REGEXP_SOURCE = -1,
REGEXP_GLOBAL = -2,
REGEXP_IGNORE_CASE = -3,
REGEXP_LAST_INDEX = -4,
REGEXP_MULTILINE = -5,
REGEXP_STICKY = -6
};
#define REGEXP_PROP_ATTRS (JSPROP_PERMANENT | JSPROP_SHARED)
#define RO_REGEXP_PROP_ATTRS (REGEXP_PROP_ATTRS | JSPROP_READONLY)

View File

@ -141,12 +141,21 @@ js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res);
extern void
js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res);
#define JSVAL_IS_REGEXP(cx, v) \
#define VALUE_IS_REGEXP(cx, v) \
(JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) && \
OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_RegExpClass)
extern JSClass js_RegExpClass;
enum regexp_tinyid {
REGEXP_SOURCE = -1,
REGEXP_GLOBAL = -2,
REGEXP_IGNORE_CASE = -3,
REGEXP_LAST_INDEX = -4,
REGEXP_MULTILINE = -5,
REGEXP_STICKY = -6
};
extern JSObject *
js_InitRegExpClass(JSContext *cx, JSObject *obj);

View File

@ -1167,7 +1167,7 @@ match_or_replace(JSContext *cx,
NORMALIZE_THIS(cx, vp, str);
data->str = str;
if (argc != 0 && JSVAL_IS_REGEXP(cx, vp[2])) {
if (argc != 0 && VALUE_IS_REGEXP(cx, vp[2])) {
reobj = JSVAL_TO_OBJECT(vp[2]);
re = (JSRegExp *) JS_GetPrivate(cx, reobj);
} else {
@ -1230,8 +1230,8 @@ match_or_replace(JSContext *cx,
test = JS_TRUE;
} else {
/*
* MODE_MATCH implies str_match is being called from a script or a
* scripted function. If the caller cares only about testing null
* MODE_MATCH implies js_str_match is being called from a script or
* a scripted function. If the caller cares only about testing null
* vs. non-null return value, optimize away the array object that
* would normally be returned in *vp.
*/
@ -1306,8 +1306,8 @@ match_glob(JSContext *cx, jsint count, GlobData *data)
return OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(count), &v);
}
static JSBool
str_match(JSContext *cx, uintN argc, jsval *vp)
JSBool
js_str_match(JSContext *cx, uintN argc, jsval *vp)
{
JSTempValueRooter tvr;
MatchData mdata;
@ -1425,7 +1425,7 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
* Save the regExpStatics from the current regexp, since they may be
* clobbered by a RegExp usage in the lambda function. Note that all
* members of JSRegExpStatics are JSSubStrings, so not GC roots, save
* input, which is rooted otherwise via vp[1] in str_replace.
* input, which is rooted otherwise via vp[1] in js_str_replace.
*/
JSRegExpStatics save = cx->regExpStatics;
JSBool freeMoreParens = JS_FALSE;
@ -1605,15 +1605,11 @@ replace_glob(JSContext *cx, jsint count, GlobData *data)
return JS_TRUE;
}
static JSBool
str_replace(JSContext *cx, uintN argc, jsval *vp)
JSBool
js_str_replace(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *lambda;
JSString *repstr, *str;
ReplaceData rdata;
JSBool ok;
jschar *chars;
size_t leftlen, rightlen, length;
JSString *repstr;
if (argc >= 2 && JS_TypeOfValue(cx, vp[3]) == JSTYPE_FUNCTION) {
lambda = JSVAL_TO_OBJECT(vp[3]);
@ -1625,6 +1621,19 @@ str_replace(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
}
return js_StringReplaceHelper(cx, argc, lambda, repstr, vp);
}
JSBool
js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda,
JSString *repstr, jsval *vp)
{
ReplaceData rdata;
JSBool ok;
size_t leftlen, rightlen, length;
jschar *chars;
JSString *str;
/*
* For ECMA Edition 3, the first argument is to be converted to a string
* to match in a "flat" sense (without regular expression metachars having
@ -1838,7 +1847,7 @@ str_split(JSContext *cx, uintN argc, jsval *vp)
v = STRING_TO_JSVAL(str);
ok = OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(0), &v);
} else {
if (JSVAL_IS_REGEXP(cx, vp[2])) {
if (VALUE_IS_REGEXP(cx, vp[2])) {
re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(vp[2]));
sep = &tmp;
@ -2251,9 +2260,9 @@ static JSFunctionSpec string_methods[] = {
JS_FN("localeCompare", str_localeCompare, 1,GENERIC_PRIMITIVE),
/* Perl-ish methods (search is actually Python-esque). */
JS_FN("match", str_match, 1,GENERIC_PRIMITIVE),
JS_FN("match", js_str_match, 1,GENERIC_PRIMITIVE),
JS_FN("search", str_search, 1,GENERIC_PRIMITIVE),
JS_FN("replace", str_replace, 2,GENERIC_PRIMITIVE),
JS_FN("replace", js_str_replace, 2,GENERIC_PRIMITIVE),
JS_FN("split", str_split, 2,GENERIC_PRIMITIVE),
#if JS_HAS_PERL_SUBSTR
JS_FN("substr", str_substr, 2,GENERIC_PRIMITIVE),

View File

@ -608,10 +608,21 @@ js_GetStringBytes(JSContext *cx, JSString *str);
extern void
js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str);
JSBool
/* Export a few natives and a helper to other files in SpiderMonkey. */
extern JSBool
js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
extern JSBool
js_str_match(JSContext *cx, uintN argc, jsval *vp);
extern JSBool
js_str_replace(JSContext *cx, uintN argc, jsval *vp);
extern JSBool
js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda,
JSString *repstr, jsval *vp);
/*
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
* least 6 bytes long. Return the number of UTF-8 bytes of data written.

View File

@ -60,6 +60,7 @@
#include "jsiter.h"
#include "jsobj.h"
#include "jsopcode.h"
#include "jsregexp.h"
#include "jsscope.h"
#include "jsscript.h"
#include "jstracer.h"
@ -2369,21 +2370,19 @@ TraceRecorder::test_property_cache_direct_slot(JSObject* obj, LIns* obj_ins, uin
return true;
}
/* Handle only gets and sets on the directly addressed object. */
if (obj2 != obj)
ABORT_TRACE("PC hit on prototype chain");
/* Insist if setting on obj being the directly addressed object. */
uint32 setflags = (js_CodeSpec[*cx->fp->regs->pc].format & (JOF_SET | JOF_INCDEC));
if (setflags && obj2 != obj)
ABORT_TRACE("JOF_SET opcode hit prototype chain");
/* Don't trace getter or setter calls, our caller wants a direct slot. */
if (PCVAL_IS_SPROP(pcval)) {
JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval);
if (js_CodeSpec[*cx->fp->regs->pc].format & JOF_SET) {
if (!SPROP_HAS_STUB_SETTER(sprop))
ABORT_TRACE("non-stub setter");
} else {
if (!SPROP_HAS_STUB_GETTER(sprop))
ABORT_TRACE("non-stub getter");
}
if (setflags && !SPROP_HAS_STUB_SETTER(sprop))
ABORT_TRACE("non-stub setter");
if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop))
ABORT_TRACE("non-stub getter");
if (!SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)))
ABORT_TRACE("no valid slot");
slot = sprop->slot;
@ -2462,7 +2461,7 @@ TraceRecorder::box_jsval(jsval v, LIns*& v_ins)
if (isNumber(v)) {
LIns* args[] = { v_ins, cx_ins };
v_ins = lir->insCall(F_BoxDouble, args);
guard(false, lir->ins2(LIR_eq, v_ins, lir->insImmPtr((void*)JSVAL_ERROR_COOKIE)),
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONSTPTR(JSVAL_ERROR_COOKIE)),
OOM_EXIT);
return true;
}
@ -3197,8 +3196,8 @@ TraceRecorder::record_JSOP_GETELEM()
LIns* args[] = { get(&r), get(&l), cx_ins };
LIns* v_ins = lir->insCall(F_Any_getelem, args);
guard(false, lir->ins2(LIR_eq, v_ins, lir->insImmPtr((void*)JSVAL_ERROR_COOKIE)),
MISMATCH_EXIT);
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONSTPTR(JSVAL_ERROR_COOKIE)),
MISMATCH_EXIT);
if (!unbox_jsval(v, v_ins))
ABORT_TRACE("JSOP_GETELEM");
set(&l, v_ins);
@ -3404,23 +3403,27 @@ TraceRecorder::record_JSOP_CALL()
JSTNErrType errtype;
JSClass *tclasp;
} knownNatives[] = {
{ js_math_sin, F_Math_sin, "", "d", INFALLIBLE, NULL },
{ js_math_cos, F_Math_cos, "", "d", INFALLIBLE, NULL },
{ js_math_pow, F_Math_pow, "", "dd", INFALLIBLE, NULL },
{ js_math_sqrt, F_Math_sqrt, "", "d", INFALLIBLE, NULL },
{ js_math_floor, F_Math_floor, "", "d", INFALLIBLE, NULL },
{ js_str_substring, F_String_p_substring, "TC", "ii", FAIL_NULL, NULL },
{ js_str_substring, F_String_p_substring_1, "TC", "i", FAIL_NULL, NULL },
{ js_str_fromCharCode, F_String_fromCharCode, "C", "i", FAIL_NULL, NULL },
{ js_str_charCodeAt, F_String_p_charCodeAt, "T", "i", FAIL_NEG, NULL },
{ js_str_charAt, F_String_getelem, "TC", "i", FAIL_NULL, NULL },
{ js_math_random, F_Math_random, "R", "", INFALLIBLE, NULL },
{ js_str_concat, F_String_p_concat_1int, "TC", "i", FAIL_NULL, NULL },
{ js_array_join, F_Array_p_join, "TC", "s", FAIL_NULL, NULL },
{ js_obj_hasOwnProperty, F_Object_p_hasOwnProperty,
"TC", "s", FAIL_VOID, NULL },
{ js_math_sin, F_Math_sin, "", "d", INFALLIBLE, NULL },
{ js_math_cos, F_Math_cos, "", "d", INFALLIBLE, NULL },
{ js_math_pow, F_Math_pow, "", "dd", INFALLIBLE, NULL },
{ js_math_sqrt, F_Math_sqrt, "", "d", INFALLIBLE, NULL },
{ js_math_floor, F_Math_floor, "", "d", INFALLIBLE, NULL },
{ js_str_substring, F_String_p_substring, "TC", "ii", FAIL_NULL, NULL },
{ js_str_substring, F_String_p_substring_1, "TC", "i", FAIL_NULL, NULL },
{ js_str_fromCharCode, F_String_fromCharCode, "C", "i", FAIL_NULL, NULL },
{ js_str_charCodeAt, F_String_p_charCodeAt, "T", "i", FAIL_NEG, NULL },
{ js_str_charAt, F_String_getelem, "TC", "i", FAIL_NULL, NULL },
{ js_str_match, F_String_p_match, "TC", "r", FAIL_VOID, NULL },
{ js_str_replace, F_String_p_replace_str3,"TC","sss", FAIL_NULL, NULL },
{ js_str_replace, F_String_p_replace_str, "TC", "sr", FAIL_NULL, NULL },
{ js_str_replace, F_String_p_replace_fun, "TC", "fr", FAIL_NULL, NULL },
{ js_math_random, F_Math_random, "R", "", INFALLIBLE, NULL },
{ js_str_concat, F_String_p_concat_1int, "TC", "i", FAIL_NULL, NULL },
{ js_array_join, F_Array_p_join, "TC", "s", FAIL_NULL, NULL },
{ js_obj_hasOwnProperty, F_Object_p_hasOwnProperty,
"TC", "s", FAIL_VOID, NULL },
{ js_obj_propertyIsEnumerable, F_Object_p_propertyIsEnumerable,
"TC", "s", FAIL_NEG, NULL },
"TC", "s", FAIL_NEG, NULL },
};
for (uintN i = 0; i < JS_ARRAY_LENGTH(knownNatives); i++) {
@ -3430,7 +3433,7 @@ TraceRecorder::record_JSOP_CALL()
uintN knownargc = strlen(known->argtypes);
if (argc != knownargc)
continue; // might have another specialization for this argc
continue;
intN prefixc = strlen(known->prefix);
LIns* args[5];
@ -3439,14 +3442,14 @@ TraceRecorder::record_JSOP_CALL()
jsval& thisval = stackval(0 - (argc + 1));
LIns* thisval_ins = get(&thisval);
if (known->tclasp) {
if (JSVAL_IS_PRIMITIVE(thisval))
ABORT_TRACE("known native with class guard called on primitive this");
if (!guardClass(JSVAL_TO_OBJECT(thisval), thisval_ins, known->tclasp))
return false;
if (known->tclasp &&
!JSVAL_IS_PRIMITIVE(thisval) &&
!guardClass(JSVAL_TO_OBJECT(thisval), thisval_ins, known->tclasp)) {
continue; /* might have another specialization for |this| */
}
#define HANDLE_PREFIX(i) \
JS_BEGIN_MACRO \
argtype = known->prefix[i]; \
if (argtype == 'C') { \
*argp = cx_ins; \
@ -3457,7 +3460,8 @@ TraceRecorder::record_JSOP_CALL()
} else { \
JS_NOT_REACHED("unknown prefix arg type"); \
} \
argp--;
argp--; \
JS_END_MACRO
switch (prefixc) {
case 2:
@ -3475,23 +3479,32 @@ TraceRecorder::record_JSOP_CALL()
#undef HANDLE_PREFIX
#define HANDLE_ARG(i) \
JS_BEGIN_MACRO \
jsval& arg = stackval(-(i + 1)); \
argtype = known->argtypes[i]; \
if (argtype == 'd' || argtype == 'i') { \
jsval& arg = stackval(-(i + 1)); \
if (!isNumber(arg)) \
ABORT_TRACE("arg in position " #i " must be numeric"); \
continue; /* might have another specialization for arg */ \
*argp = get(&arg); \
if (argtype == 'i') \
*argp = f2i(*argp); \
} else if (argtype == 's') { \
jsval& arg = stackval(-(i + 1)); \
if (!JSVAL_IS_STRING(arg)) \
ABORT_TRACE("arg in position " #i " must be a string"); \
continue; /* might have another specialization for arg */ \
*argp = get(&arg); \
} else if (argtype == 'r') { \
if (!VALUE_IS_REGEXP(cx, arg)) \
continue; /* might have another specialization for arg */ \
*argp = get(&arg); \
} else if (argtype == 'f') { \
if (!VALUE_IS_FUNCTION(cx, arg)) \
continue; /* might have another specialization for arg */ \
*argp = get(&arg); \
} else { \
JS_NOT_REACHED("unknown arg type"); \
continue; /* might have another specialization for arg */ \
} \
argp--;
argp--; \
JS_END_MACRO
switch (strlen(known->argtypes)) {
case 4:
@ -3515,16 +3528,22 @@ TraceRecorder::record_JSOP_CALL()
#undef HANDLE_ARG
LIns* res_ins = lir->insCall(known->builtin, args);
if (known->errtype == FAIL_NULL) {
switch (known->errtype) {
case FAIL_NULL:
guard(false, lir->ins_eq0(res_ins), OOM_EXIT);
} else if (known->errtype == FAIL_NEG) {
break;
case FAIL_NEG:
{
res_ins = lir->ins1(LIR_i2f, res_ins);
jsdpun u;
u.d = 0.0;
guard(false, lir->ins2(LIR_flt, res_ins, lir->insImmq(u.u64)), OOM_EXIT);
} else if (known->errtype == FAIL_VOID) {
break;
}
case FAIL_VOID:
guard(false, lir->ins2i(LIR_eq, res_ins, 2), OOM_EXIT);
break;
default:;
}
set(&fval, res_ins);
return true;
@ -3543,7 +3562,8 @@ TraceRecorder::name(jsval*& vp)
LIns* obj_ins = lir->insLoadi(lir->insLoadi(cx_ins, offsetof(JSContext, fp)),
offsetof(JSStackFrame, scopeChain));
/* Can't use getProp here, because we don't want unboxing. */
/* Can't use prop here, because we don't want unboxing from global slots. */
uint32 slot;
if (!test_property_cache_direct_slot(obj, obj_ins, slot))
return false;
@ -3569,18 +3589,61 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
ABORT_TRACE("prop op aliases global");
guard(false, lir->ins2(LIR_eq, obj_ins, lir->insImmPtr((void*)globalObj)), MISMATCH_EXIT);
if (!test_property_cache_direct_slot(obj, obj_ins, slot))
/*
* Property cache ensures that we are dealing with an existing property,
* and guards the shape for us.
*/
JSObject* obj2;
jsuword pcval;
if (!test_property_cache(obj, obj_ins, obj2, pcval))
return false;
/* Check for non-existent property reference, which results in undefined. */
if (slot == SPROP_INVALID_SLOT) {
const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
JS_ASSERT(cs.ndefs == 1);
const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
if (PCVAL_IS_NULL(pcval)) {
v_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
JS_ASSERT(cs.ndefs == 1);
stack(-cs.nuses, v_ins);
return true;
}
/* Insist if setting on obj being the directly addressed object. */
uint32 setflags = (cs.format & (JOF_SET | JOF_INCDEC));
if (setflags && obj2 != obj)
ABORT_TRACE("JOF_SET opcode hit prototype chain");
/* Don't trace getter or setter calls, our caller wants a direct slot. */
if (PCVAL_IS_SPROP(pcval)) {
JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval);
if (setflags && !SPROP_HAS_STUB_SETTER(sprop))
ABORT_TRACE("non-stub setter");
if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop)) {
// FIXME 450335: generalize this away from regexp built-in getters.
if (setflags == 0 &&
sprop->getter == js_RegExpClass.getProperty &&
sprop->shortid < 0) {
LIns* args[] = { INS_CONSTPTR(sprop), obj_ins, cx_ins };
v_ins = lir->insCall(F_CallGetter, args);
if (!unbox_jsval((sprop->shortid == REGEXP_SOURCE) ? JSVAL_STRING : JSVAL_FALSE,
v_ins)) {
ABORT_TRACE("unboxing");
}
JS_ASSERT(cs.ndefs == 1);
stack(-cs.nuses, v_ins);
return true;
}
ABORT_TRACE("non-stub getter");
}
if (!SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)))
ABORT_TRACE("no valid slot");
slot = sprop->slot;
} else {
if (!PCVAL_IS_SLOT(pcval))
ABORT_TRACE("PCE is not a slot");
slot = PCVAL_TO_SLOT(pcval);
}
LIns* dslots_ins = NULL;
v_ins = stobj_get_slot(obj_ins, slot, dslots_ins);
if (!unbox_jsval(STOBJ_GET_SLOT(obj, slot), v_ins))

View File

@ -39,6 +39,7 @@
#define BUILTIN2(op, at0, at1, atr, tr, t0, t1, cse, fold) F_##op,
#define BUILTIN3(op, at0, at1, at2, atr, tr, t0, t1, t2, cse, fold) F_##op,
#define BUILTIN4(op, at0, at1, at2, at3, atr, tr, t0, t1, t2, t3, cse, fold) F_##op,
#define BUILTIN5(op, at0, at1, at2, at3, at4, atr, tr, t0, t1, t2, t3, t4, cse, fold) F_##op,
INTERP_FOPCODE_LIST_BEGIN
#include "builtins.tbl"
@ -48,3 +49,4 @@ INTERP_FOPCODE_LIST_END
#undef BUILTIN2
#undef BUILTIN3
#undef BUILTIN4
#undef BUILTIN5