Commit a184ace4 authored by Gabriel Ivăncescu's avatar Gabriel Ivăncescu Committed by Alexandre Julliard

jscript: Correctly implement context for indirect eval calls in ES5+ modes.

parent 9b766959
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment