Add support for fast native that return jsval and wire up push/pop (453734, r=mrbkap).

This commit is contained in:
Andreas Gal 2008-09-18 16:53:09 -07:00
parent 9908bc1345
commit 9d7afa336a
5 changed files with 76 additions and 29 deletions

View File

@ -58,6 +58,8 @@ BUILTIN1(Math_log, F, F, jsdouble, jsdouble, 1, 1)
BUILTIN2(Math_max, F, F, F, jsdouble, jsdouble, jsdouble, 1, 1)
BUILTIN4(Array_dense_setelem, LO, LO, LO, LO, LO, bool, JSContext*, JSObject*, jsint, jsval, 0, 0)
BUILTIN3(Array_p_join, LO, LO, LO, P, JSString*, JSContext*, JSObject*, JSString*, 0, 0)
BUILTIN3(Array_p_push1, LO, LO, LO, LO, jsval, JSContext*, JSObject*, jsval, 0, 0)
BUILTIN2(Array_p_pop, LO, LO, LO, jsval, JSContext*, JSObject*, 0, 0)
BUILTIN4(String_p_substring, LO, LO, LO, LO, P, JSString*, JSContext*, JSString*, jsint, jsint, 1, 1)
BUILTIN3(String_p_substring_1, LO, LO, LO, P, JSString*, JSContext*, JSString*, jsint, 1, 1)
BUILTIN3(ConcatStrings, LO, LO, LO, P, JSString*, JSContext*, JSString*, JSString*, 1, 1)

View File

@ -4972,6 +4972,7 @@ js_Interpret(JSContext *cx)
JS_ASSERT(JSVAL_IS_OBJECT(vp[1]) ||
PRIMITIVE_THIS_TEST(fun, vp[1]));
ok = ((JSFastNative) fun->u.n.native)(cx, argc, vp);
TRACE_0(FastNativeCallComplete);
#ifdef INCLUDE_MOZILLA_DTRACE
if (VALUE_IS_FUNCTION(cx, lval)) {
if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())

View File

@ -4013,15 +4013,6 @@ TraceRecorder::record_JSOP_NEG()
return false;
}
enum JSTNErrType { INFALLIBLE, FAIL_NULL, FAIL_NEG, FAIL_VOID };
struct JSTraceableNative {
JSFastNative native;
int builtin;
const char *prefix;
const char *argtypes;
JSTNErrType errtype;
};
JSBool
js_Array(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
@ -4710,6 +4701,8 @@ TraceRecorder::record_JSOP_CALL()
static JSTraceableNative knownNatives[] = {
{ js_array_join, F_Array_p_join, "TC", "s", FAIL_NULL },
{ js_array_push, F_Array_p_push1, "TC", "v", FAIL_JSVAL },
{ js_array_pop, F_Array_p_pop, "TC", "", FAIL_JSVAL },
{ js_math_sin, F_Math_sin, "", "d", INFALLIBLE },
{ js_math_cos, F_Math_cos, "", "d", INFALLIBLE },
{ js_math_pow, F_Math_pow, "", "dd", INFALLIBLE },
@ -4749,7 +4742,8 @@ TraceRecorder::record_JSOP_CALL()
LIns* arg1_ins = NULL;
jsval arg1 = JSVAL_VOID;
if ((JSFastNative)fun->u.n.native == js_fun_apply) {
JSFastNative native = (JSFastNative)fun->u.n.native;
if (native == js_fun_apply) {
if (argc != 2)
ABORT_TRACE("can't trace Function.prototype.apply with other than 2 args");
@ -4909,6 +4903,9 @@ TraceRecorder::record_JSOP_CALL()
} else if (argtype == 'f') { \
if (!VALUE_IS_FUNCTION(cx, arg)) \
continue; /* might have another specialization for arg */ \
} else if (argtype == 'v') { \
if (!box_jsval(arg, *argp)) \
return false; \
} else { \
continue; /* might have another specialization for arg */ \
} \
@ -4940,25 +4937,12 @@ TraceRecorder::record_JSOP_CALL()
JS_ASSERT(args[0] != (LIns *)0xcdcdcdcd);
#endif
LIns* res_ins = lir->insCall(known->builtin, args);
switch (known->errtype) {
case FAIL_NULL:
guard(false, lir->ins_eq0(res_ins), OOM_EXIT);
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);
break;
}
case FAIL_VOID:
guard(false, lir->ins2i(LIR_eq, res_ins, JSVAL_TO_BOOLEAN(JSVAL_VOID)), OOM_EXIT);
break;
default:;
}
set(&fval, res_ins);
rval_ins = lir->insCall(known->builtin, args);
/* The return value will be processed by FastNativeCallComplete since we have to
know the actual return value type for calls that return jsval (like Array_p_pop). */
pendingTraceableNative = known;
return true;
}
@ -4966,6 +4950,41 @@ TraceRecorder::record_JSOP_CALL()
ABORT_TRACE("unknown native");
}
bool
TraceRecorder::record_FastNativeCallComplete()
{
JSStackFrame* fp = cx->fp;
jsbytecode *pc = fp->regs->pc;
uintN argc = GET_ARGC(pc);
jsval& fval = stackval(0 - (argc + 2));
JS_ASSERT(&fval >= StackBase(fp));
switch (pendingTraceableNative->errtype) {
case FAIL_NULL:
guard(false, lir->ins_eq0(rval_ins), OOM_EXIT);
break;
case FAIL_NEG:
{
rval_ins = lir->ins1(LIR_i2f, rval_ins);
jsdpun u;
u.d = 0.0;
guard(false, lir->ins2(LIR_flt, rval_ins, lir->insImmq(u.u64)), OOM_EXIT);
break;
}
case FAIL_VOID:
guard(false, lir->ins2i(LIR_eq, rval_ins, JSVAL_TO_BOOLEAN(JSVAL_VOID)), OOM_EXIT);
break;
case FAIL_JSVAL:
guard(false, lir->ins2i(LIR_eq, rval_ins, JSVAL_ERROR_COOKIE), OOM_EXIT);
if (!unbox_jsval(fval, rval_ins))
return false;
break;
default:;
}
set(&fval, rval_ins);
return true;
}
bool
TraceRecorder::name(jsval*& vp)
{

View File

@ -203,6 +203,15 @@ public:
extern struct nanojit::CallInfo builtins[];
enum JSTNErrType { INFALLIBLE, FAIL_NULL, FAIL_NEG, FAIL_VOID, FAIL_JSVAL };
struct JSTraceableNative {
JSFastNative native;
int builtin;
const char *prefix;
const char *argtypes;
JSTNErrType errtype;
};
class TraceRecorder {
JSContext* cx;
JSTraceMonitor* traceMonitor;
@ -238,6 +247,7 @@ class TraceRecorder {
nanojit::Fragment* whichTreeToTrash;
Queue<jsbytecode*> inlinedLoopEdges;
Queue<jsbytecode*> cfgMerges;
JSTraceableNative* pendingTraceableNative;
bool isGlobal(jsval* p) const;
ptrdiff_t nativeGlobalOffset(jsval* p) const;
@ -359,6 +369,7 @@ public:
bool record_LeaveFrame();
bool record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop);
bool record_SetPropMiss(JSPropCacheEntry* entry);
bool record_FastNativeCallComplete();
void deepAbort() { deepAborted = true; }
bool wasDeepAborted() { return deepAborted; }
@ -399,6 +410,7 @@ public:
JS_END_MACRO
#define RECORD(x) RECORD_ARGS(x, ())
#define TRACE_0(x) TRACE_ARGS(x, ())
#define TRACE_1(x,a) TRACE_ARGS(x, (a))
#define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b))

View File

@ -1433,6 +1433,19 @@ function testMoreArgcThanNargs()
testMoreArgcThanNargs.expected = 4*10;
test(testMoreArgcThanNargs);
function testArrayPushPop() {
var a = [], sum1 = 0, sum2 = 0;
for (var i = 0; i < 10; ++i)
sum1 += a.push(i);
for (var i = 0; i < 10; ++i)
sum2 += a.pop();
a.push(sum1);
a.push(sum2);
return a.join(",");
}
testArrayPushPop.expected = "55,45";
test(testArrayPushPop);
/* Keep these at the end so that we can see the summary after the trace-debug spew. */
print("\npassed:", passes.length && passes.join(","));
print("\nFAILED:", fails.length && fails.join(","));