Add Array (generic) join builtin, plus (not yet used) optional this-class guarding for builtins.

This commit is contained in:
Brendan Eich 2008-08-10 14:50:31 -07:00
parent 5bbc609a8b
commit 0099753ff4
5 changed files with 64 additions and 31 deletions

View File

@ -49,6 +49,7 @@ BUILTIN2(Math_pow, F, F, F, jsdouble, jsdouble, jsdouble,
BUILTIN1(Math_sqrt, F, F, jsdouble, jsdouble, 1, 1)
BUILTIN1(Math_floor, F, F, jsdouble, jsdouble, 1, 1)
BUILTIN4(Array_dense_setelem, LO, LO, LO, LO, LO, bool, JSContext*, JSObject*, jsint, jsval, 1, 1)
BUILTIN3(Array_p_join, LO, LO, LO, LO, JSString*, JSContext*, JSObject*, JSString*, 1, 1)
BUILTIN4(String_p_substring, LO, LO, LO, LO, LO, JSString*, JSContext*, JSString*, jsint, jsint, 1, 1)
BUILTIN3(String_p_substring_1, LO, LO, LO, LO, JSString*, JSContext*, JSString*, jsint, 1, 1)
BUILTIN3(FastConcatStrings, LO, LO, LO, LO, JSString*, JSContext*, JSString*, JSString*, 1, 1)

View File

@ -1183,20 +1183,14 @@ out_bad:
return JS_FALSE;
}
enum ArrayToStringOp {
TO_STRING,
TO_LOCALE_STRING,
TO_SOURCE
};
/*
* When op is TO_STRING or TO_LOCALE_STRING sep indicates a separator to use
* or "," when sep is NULL.
* When op is TO_SOURCE sep must be NULL.
*/
static JSBool
array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op,
JSString *sep, jsval *rval)
JSBool
js_array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op,
JSString *sep, jsval *rval)
{
JSBool ok, hole;
jsuint length, index;
@ -1414,7 +1408,7 @@ array_toSource(JSContext *cx, uintN argc, jsval *vp)
!JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) {
return JS_FALSE;
}
return array_join_sub(cx, obj, TO_SOURCE, NULL, vp);
return js_array_join_sub(cx, obj, TO_SOURCE, NULL, vp);
}
#endif
@ -1428,7 +1422,7 @@ array_toString(JSContext *cx, uintN argc, jsval *vp)
!JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) {
return JS_FALSE;
}
return array_join_sub(cx, obj, TO_STRING, NULL, vp);
return js_array_join_sub(cx, obj, TO_STRING, NULL, vp);
}
static JSBool
@ -1446,7 +1440,7 @@ array_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
* Passing comma here as the separator. Need a way to get a
* locale-specific version.
*/
return array_join_sub(cx, obj, TO_LOCALE_STRING, NULL, vp);
return js_array_join_sub(cx, obj, TO_LOCALE_STRING, NULL, vp);
}
static JSBool
@ -1505,8 +1499,8 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector,
/*
* Perl-inspired join, reverse, and sort.
*/
static JSBool
array_join(JSContext *cx, uintN argc, jsval *vp)
JSBool
js_array_join(JSContext *cx, uintN argc, jsval *vp)
{
JSString *str;
JSObject *obj;
@ -1520,7 +1514,7 @@ array_join(JSContext *cx, uintN argc, jsval *vp)
vp[2] = STRING_TO_JSVAL(str);
}
obj = JS_THIS_OBJECT(cx, vp);
return obj && array_join_sub(cx, obj, TO_STRING, str, vp);
return obj && js_array_join_sub(cx, obj, TO_STRING, str, vp);
}
static JSBool
@ -2880,7 +2874,7 @@ static JSFunctionSpec array_methods[] = {
JS_FN(js_toLocaleString_str,array_toLocaleString,0,0),
/* Perl-ish methods. */
JS_FN("join", array_join, 1,JSFUN_GENERIC_NATIVE),
JS_FN("join", js_array_join, 1,JSFUN_GENERIC_NATIVE),
JS_FN("reverse", array_reverse, 0,JSFUN_GENERIC_NATIVE),
JS_FN("sort", array_sort, 1,JSFUN_GENERIC_NATIVE),
JS_FN("push", array_push, 1,JSFUN_GENERIC_NATIVE),

View File

@ -123,6 +123,19 @@ extern JSBool
js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
#endif
extern JSBool
js_array_join(JSContext *cx, uintN argc, jsval *vp);
enum ArrayToStringOp {
TO_STRING,
TO_LOCALE_STRING,
TO_SOURCE
};
extern JSBool
js_array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op,
JSString *sep, jsval *rval);
JS_END_EXTERN_C
#endif /* jsarray_h___ */

View File

@ -195,6 +195,16 @@ js_Array_dense_setelem(JSContext* cx, JSObject* obj, jsint i, jsval v)
return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(i), &v) ? true : false;
}
JSString* FASTCALL
js_Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
{
jsval v;
if (!js_array_join_sub(cx, obj, TO_STRING, str, &v))
return NULL;
JS_ASSERT(JSVAL_IS_STRING(v));
return JSVAL_TO_STRING(v);
}
JSString* FASTCALL
js_String_p_substring(JSContext* cx, JSString* str, jsint begin, jsint end)
{

View File

@ -3246,19 +3246,21 @@ TraceRecorder::record_JSOP_CALL()
const char *prefix;
const char *argtypes;
JSTNErrType errtype;
JSClass *tclasp;
} knownNatives[] = {
{ js_math_sin, F_Math_sin, "", "d", INFALLIBLE, },
{ js_math_cos, F_Math_cos, "", "d", INFALLIBLE, },
{ js_math_pow, F_Math_pow, "", "dd", INFALLIBLE, },
{ js_math_sqrt, F_Math_sqrt, "", "d", INFALLIBLE, },
{ js_math_floor, F_Math_floor, "", "d", INFALLIBLE, },
{ js_str_substring, F_String_p_substring, "TC", "ii", FAIL_NULL, },
{ js_str_substring, F_String_p_substring_1, "TC", "i", FAIL_NULL, },
{ js_str_fromCharCode, F_String_fromCharCode, "C", "i", FAIL_NULL, },
{ js_str_charCodeAt, F_String_p_charCodeAt, "T", "i", FAIL_NEG, },
{ js_str_charAt, F_String_getelem, "TC", "i", FAIL_NULL, },
{ js_math_random, F_Math_random, "R", "", INFALLIBLE, },
{ js_str_concat, F_String_p_concat_1int, "TC", "i", FAIL_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_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 },
};
for (uintN i = 0; i < JS_ARRAY_LENGTH(knownNatives); i++) {
@ -3275,7 +3277,14 @@ TraceRecorder::record_JSOP_CALL()
LIns** argp = &args[argc + prefixc - 1];
char argtype;
LIns* thisval_ins = stack(0 - (argc + 1));
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;
}
#define HANDLE_PREFIX(i) \
argtype = known->prefix[i]; \
@ -3308,11 +3317,17 @@ TraceRecorder::record_JSOP_CALL()
#define HANDLE_ARG(i) \
argtype = known->argtypes[i]; \
if (argtype == 'd' || argtype == 'i') { \
if (!isNumber(stackval(-(i + 1)))) \
jsval& arg = stackval(-(i + 1)); \
if (!isNumber(arg)) \
ABORT_TRACE("arg in position " #i " must be numeric"); \
*argp = get(&stackval(-(i + 1))); \
*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"); \
*argp = get(&arg); \
} else { \
JS_NOT_REACHED("unknown arg type"); \
} \