mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 08:54:05 +00:00
jscript: Correctly implement context for indirect eval calls in ES5+ modes.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
parent
9b7669592d
commit
a184ace43d
|
@ -720,16 +720,20 @@ static HRESULT compile_new_expression(compiler_ctx_t *ctx, call_expression_t *ex
|
|||
|
||||
static HRESULT compile_call_expression(compiler_ctx_t *ctx, call_expression_t *expr, BOOL emit_ret)
|
||||
{
|
||||
unsigned arg_cnt = 0, extra_args;
|
||||
unsigned arg_cnt = 0, extra_args = 0;
|
||||
HRESULT hres = S_OK;
|
||||
argument_t *arg;
|
||||
unsigned instr;
|
||||
jsop_t op;
|
||||
HRESULT hres;
|
||||
|
||||
if(is_memberid_expr(expr->expression->type)) {
|
||||
op = OP_call_member;
|
||||
extra_args = 2;
|
||||
hres = compile_memberid_expression(ctx, expr->expression, 0);
|
||||
if(expr->expression->type == EXPR_IDENT && !wcscmp(((identifier_expression_t*)expr->expression)->identifier, L"eval"))
|
||||
op = OP_call_eval;
|
||||
else {
|
||||
op = OP_call_member;
|
||||
extra_args = 2;
|
||||
hres = compile_memberid_expression(ctx, expr->expression, 0);
|
||||
}
|
||||
}else {
|
||||
op = OP_call;
|
||||
extra_args = 1;
|
||||
|
|
|
@ -1459,6 +1459,40 @@ static HRESULT interp_call_member(script_ctx_t *ctx)
|
|||
argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
|
||||
}
|
||||
|
||||
/* ECMA-262 5th Edition 15.1.2.1.1 */
|
||||
static HRESULT interp_call_eval(script_ctx_t *ctx)
|
||||
{
|
||||
const unsigned argn = get_op_uint(ctx, 0);
|
||||
const int do_ret = get_op_int(ctx, 1);
|
||||
HRESULT hres = S_OK;
|
||||
exprval_t exprval;
|
||||
jsdisp_t *jsdisp;
|
||||
BSTR identifier;
|
||||
jsval_t v;
|
||||
|
||||
TRACE("%d %d\n", argn, do_ret);
|
||||
|
||||
identifier = SysAllocString(L"eval");
|
||||
hres = identifier_eval(ctx, identifier, &exprval);
|
||||
SysFreeString(identifier);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
clear_acc(ctx);
|
||||
hres = exprval_propget(ctx, &exprval, &v);
|
||||
if(SUCCEEDED(hres)) {
|
||||
if(is_object_instance(v) && (jsdisp = to_jsdisp(get_object(v))) && jsdisp->ctx == ctx && is_builtin_eval_func(jsdisp))
|
||||
hres = builtin_eval(ctx, ctx->call_ctx, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
|
||||
argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
|
||||
else
|
||||
hres = exprval_call(ctx, &exprval, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
|
||||
argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL);
|
||||
jsval_release(v);
|
||||
}
|
||||
exprval_release(&exprval);
|
||||
return hres;
|
||||
}
|
||||
|
||||
/* ECMA-262 3rd Edition 11.1.1 */
|
||||
static HRESULT interp_this(script_ctx_t *ctx)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
X(bool, 1, ARG_INT, 0) \
|
||||
X(bneg, 1, 0,0) \
|
||||
X(call, 1, ARG_UINT, ARG_UINT) \
|
||||
X(call_eval, 1, ARG_UINT, ARG_UINT) \
|
||||
X(call_member,1, ARG_UINT, ARG_UINT) \
|
||||
X(carray, 1, ARG_UINT, 0) \
|
||||
X(carray_set, 1, ARG_UINT, 0) \
|
||||
|
|
|
@ -1140,6 +1140,12 @@ static HRESULT FunctionProt_value(script_ctx_t *ctx, jsval_t vthis, WORD flags,
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
BOOL is_builtin_eval_func(jsdisp_t *jsdisp)
|
||||
{
|
||||
return is_class(jsdisp, JSCLASS_FUNCTION) && function_from_jsdisp(jsdisp)->vtbl == &NativeFunctionVtbl &&
|
||||
((NativeFunction*)function_from_jsdisp(jsdisp))->proc == JSGlobal_eval;
|
||||
}
|
||||
|
||||
HRESULT init_function_constr(script_ctx_t *ctx, jsdisp_t *object_prototype)
|
||||
{
|
||||
NativeFunction *prot, *constr;
|
||||
|
|
|
@ -130,10 +130,9 @@ static HRESULT JSGlobal_escape(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns
|
|||
}
|
||||
|
||||
/* ECMA-262 3rd Edition 15.1.2.1 */
|
||||
HRESULT JSGlobal_eval(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
|
||||
HRESULT builtin_eval(script_ctx_t *ctx, call_frame_t *frame, WORD flags, unsigned argc, jsval_t *argv,
|
||||
jsval_t *r)
|
||||
{
|
||||
call_frame_t *frame = ctx->call_ctx;
|
||||
DWORD exec_flags = EXEC_EVAL;
|
||||
bytecode_t *code;
|
||||
const WCHAR *src;
|
||||
|
@ -174,6 +173,12 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned arg
|
|||
return hres;
|
||||
}
|
||||
|
||||
HRESULT JSGlobal_eval(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
|
||||
jsval_t *r)
|
||||
{
|
||||
return builtin_eval(ctx, ctx->version < SCRIPTLANGUAGEVERSION_ES5 ? ctx->call_ctx : NULL, flags, argc, argv, r);
|
||||
}
|
||||
|
||||
static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
|
||||
jsval_t *r)
|
||||
{
|
||||
|
|
|
@ -464,6 +464,8 @@ BOOL bool_obj_value(jsdisp_t*) DECLSPEC_HIDDEN;
|
|||
unsigned array_get_length(jsdisp_t*) DECLSPEC_HIDDEN;
|
||||
HRESULT localize_number(script_ctx_t*,DOUBLE,BOOL,jsstr_t**) DECLSPEC_HIDDEN;
|
||||
|
||||
BOOL is_builtin_eval_func(jsdisp_t*) DECLSPEC_HIDDEN;
|
||||
HRESULT builtin_eval(script_ctx_t*,struct _call_frame_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||
HRESULT JSGlobal_eval(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||
HRESULT Object_get_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||
HRESULT Object_set_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -2446,6 +2446,49 @@ ok(bool.toLocaleString() === bool.toString(), "bool.toLocaleString() = " + bool.
|
|||
tmp = Object.prototype.valueOf.call(nullDisp);
|
||||
ok(tmp === nullDisp, "nullDisp.valueOf != nullDisp");
|
||||
|
||||
(function(global) {
|
||||
var i, context, code = "this.foobar = 1234";
|
||||
|
||||
var direct = [
|
||||
function() { eval(code); },
|
||||
function() { (eval)(code); },
|
||||
function() { (function(eval) { eval(code); }).call(this, eval); },
|
||||
function() { eval("eval(" + code + ")"); }
|
||||
];
|
||||
|
||||
for(i = 0; i < direct.length; i++) {
|
||||
context = {};
|
||||
direct[i].call(context);
|
||||
ok(context.foobar === 1234, "direct[" + i + "] context foobar = " + context.foobar);
|
||||
}
|
||||
|
||||
var indirect = [
|
||||
function() { (true, eval)(code); },
|
||||
function() { (eval, eval)(code); },
|
||||
function() { (true ? eval : false)(code); },
|
||||
function() { [eval][0](code); },
|
||||
function() { eval.call(this, code); },
|
||||
function() { var f; (f = eval)(code); },
|
||||
function() { var f = eval; f(code); },
|
||||
function() { (function(f) { f(code); }).call(this, eval); },
|
||||
function() { (function(f) { return f; }).call(this, eval)(code); },
|
||||
function() { (function() { arguments[0](code) }).call(this, eval); },
|
||||
function() { eval("eval")(code); }
|
||||
];
|
||||
|
||||
for(i = 0; i < indirect.length; i++) {
|
||||
context = {};
|
||||
ok(!("foobar" in global), "indirect[" + i + "] has global foobar before call");
|
||||
indirect[i].call(context);
|
||||
ok(context.foobar === 1234, "indirect[" + i + "] context foobar = " + context.foobar);
|
||||
ok(!("foobar" in global), "indirect[" + i + "] has global foobar");
|
||||
}
|
||||
|
||||
context = {};
|
||||
(function(eval) { eval(code); })(function() { context.barfoo = 4321; });
|
||||
ok(context.barfoo === 4321, "context.barfoo = " + context.barfoo);
|
||||
})(this);
|
||||
|
||||
ok(ActiveXObject instanceof Function, "ActiveXObject is not instance of Function");
|
||||
ok(ActiveXObject.prototype instanceof Object, "ActiveXObject.prototype is not instance of Object");
|
||||
|
||||
|
|
|
@ -756,6 +756,57 @@ sync_test("JS objs", function() {
|
|||
test_parses("if(false) { o.if; }", v >= 9);
|
||||
});
|
||||
|
||||
sync_test("eval", function() {
|
||||
var i, context, code = "this.foobar = 1234", v = document.documentMode;
|
||||
|
||||
var direct = [
|
||||
function() { eval(code); },
|
||||
function() { (eval)(code); },
|
||||
function() { (function(eval) { eval(code); }).call(this, eval); },
|
||||
function() { eval("eval(" + code + ")"); }
|
||||
];
|
||||
|
||||
for(i = 0; i < direct.length; i++) {
|
||||
context = {};
|
||||
direct[i].call(context);
|
||||
ok(context.foobar === 1234, "direct[" + i + "] context foobar = " + context.foobar);
|
||||
}
|
||||
|
||||
var indirect = [
|
||||
function() { (true, eval)(code); },
|
||||
function() { (eval, eval)(code); },
|
||||
function() { (true ? eval : false)(code); },
|
||||
function() { [eval][0](code); },
|
||||
function() { eval.call(this, code); },
|
||||
function() { var f; (f = eval)(code); },
|
||||
function() { var f = eval; f(code); },
|
||||
function() { (function(f) { f(code); }).call(this, eval); },
|
||||
function() { (function(f) { return f; }).call(this, eval)(code); },
|
||||
function() { (function() { arguments[0](code) }).call(this, eval); },
|
||||
function() { window.eval(code); },
|
||||
function() { window["eval"](code); },
|
||||
function() { eval("eval")(code); }
|
||||
];
|
||||
|
||||
for(i = 0; i < indirect.length; i++) {
|
||||
context = {};
|
||||
ok(!("foobar" in window), "indirect[" + i + "] has global foobar before call");
|
||||
indirect[i].call(context);
|
||||
if(v < 9) {
|
||||
ok(context.foobar === 1234, "indirect[" + i + "] context foobar = " + context.foobar);
|
||||
ok(!("foobar" in window), "indirect[" + i + "] has global foobar");
|
||||
}else {
|
||||
ok(!("foobar" in context), "indirect[" + i + "] has foobar");
|
||||
ok(window.foobar === 1234, "indirect[" + i + "] global foobar = " + context.foobar);
|
||||
delete window.foobar;
|
||||
}
|
||||
}
|
||||
|
||||
context = {};
|
||||
(function(eval) { eval(code); })(function() { context.barfoo = 4321; });
|
||||
ok(context.barfoo === 4321, "context.barfoo = " + context.barfoo);
|
||||
});
|
||||
|
||||
sync_test("for..in", function() {
|
||||
var v = document.documentMode, found = 0, r;
|
||||
|
||||
|
|
Loading…
Reference in a new issue