Commit f568b48e authored by Jacek Caban's avatar Jacek Caban Committed by Alexandre Julliard

jscript: Get dispid and call invoke in a single step when setting a member property.

parent b80da206
...@@ -466,18 +466,11 @@ static HRESULT emit_identifier(compiler_ctx_t *ctx, const WCHAR *identifier) ...@@ -466,18 +466,11 @@ static HRESULT emit_identifier(compiler_ctx_t *ctx, const WCHAR *identifier)
return push_instr_bstr(ctx, OP_ident, identifier); return push_instr_bstr(ctx, OP_ident, identifier);
} }
static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags) static HRESULT emit_member_expression(compiler_ctx_t *ctx, expression_t *expr)
{ {
HRESULT hres = S_OK; HRESULT hres;
switch(expr->type) {
case EXPR_IDENT: {
identifier_expression_t *ident_expr = (identifier_expression_t*)expr;
hres = emit_identifier_ref(ctx, ident_expr->identifier, flags); if(expr->type == EXPR_ARRAY) {
break;
}
case EXPR_ARRAY: {
binary_expression_t *array_expr = (binary_expression_t*)expr; binary_expression_t *array_expr = (binary_expression_t*)expr;
hres = compile_expression(ctx, array_expr->expression1, TRUE); hres = compile_expression(ctx, array_expr->expression1, TRUE);
...@@ -488,18 +481,18 @@ static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *ex ...@@ -488,18 +481,18 @@ static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *ex
if(FAILED(hres)) if(FAILED(hres))
return hres; return hres;
hres = push_instr_uint(ctx, OP_memberid, flags); if(!push_instr(ctx, OP_to_string))
break; return E_OUTOFMEMORY;
} }else {
case EXPR_MEMBER: {
member_expression_t *member_expr = (member_expression_t*)expr; member_expression_t *member_expr = (member_expression_t*)expr;
jsstr_t *jsstr; jsstr_t *jsstr;
assert(expr->type == EXPR_MEMBER);
hres = compile_expression(ctx, member_expr->expression, TRUE); hres = compile_expression(ctx, member_expr->expression, TRUE);
if(FAILED(hres)) if(FAILED(hres))
return hres; return hres;
/* FIXME: Potential optimization */
jsstr = compiler_alloc_string(ctx, member_expr->identifier); jsstr = compiler_alloc_string(ctx, member_expr->identifier);
if(!jsstr) if(!jsstr)
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
...@@ -507,14 +500,25 @@ static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *ex ...@@ -507,14 +500,25 @@ static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *ex
hres = push_instr_str(ctx, OP_str, jsstr); hres = push_instr_str(ctx, OP_str, jsstr);
if(FAILED(hres)) if(FAILED(hres))
return hres; return hres;
hres = push_instr_uint(ctx, OP_memberid, flags);
break;
} }
DEFAULT_UNREACHABLE;
return S_OK;
}
static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags)
{
HRESULT hres;
if(expr->type == EXPR_IDENT) {
identifier_expression_t *ident_expr = (identifier_expression_t*)expr;
return emit_identifier_ref(ctx, ident_expr->identifier, flags);
} }
return hres; hres = emit_member_expression(ctx, expr);
if(FAILED(hres))
return hres;
return push_instr_uint(ctx, OP_memberid, flags);
} }
static HRESULT compile_increment_expression(compiler_ctx_t *ctx, unary_expression_t *expr, jsop_t op, int n) static HRESULT compile_increment_expression(compiler_ctx_t *ctx, unary_expression_t *expr, jsop_t op, int n)
...@@ -734,7 +738,7 @@ static HRESULT compile_delete_expression(compiler_ctx_t *ctx, unary_expression_t ...@@ -734,7 +738,7 @@ static HRESULT compile_delete_expression(compiler_ctx_t *ctx, unary_expression_t
static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_t *expr, jsop_t op) static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_t *expr, jsop_t op)
{ {
BOOL use_throw_path = FALSE; jsop_t assign_op = OP_throw_ref;
unsigned arg_cnt = 0; unsigned arg_cnt = 0;
HRESULT hres; HRESULT hres;
...@@ -770,33 +774,30 @@ static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_ ...@@ -770,33 +774,30 @@ static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_
if(!push_instr(ctx, OP_push_acc)) if(!push_instr(ctx, OP_push_acc))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
} }
}else { assign_op = OP_assign_call;
use_throw_path = TRUE;
} }
}else if(is_memberid_expr(expr->expression1->type)) { }else if(is_memberid_expr(expr->expression1->type)) {
hres = compile_memberid_expression(ctx, expr->expression1, fdexNameEnsure); if(op != OP_LAST || expr->expression1->type == EXPR_IDENT) {
if(FAILED(hres)) hres = compile_memberid_expression(ctx, expr->expression1, fdexNameEnsure);
return hres; if(FAILED(hres))
if(op != OP_LAST && !push_instr(ctx, OP_refval)) return hres;
return E_OUTOFMEMORY; if(op != OP_LAST && !push_instr(ctx, OP_refval))
}else { return E_OUTOFMEMORY;
use_throw_path = TRUE; assign_op = OP_assign;
}else {
hres = emit_member_expression(ctx, expr->expression1);
if(FAILED(hres))
return hres;
assign_op = OP_set_member;
}
} }
if(use_throw_path) { if(assign_op == OP_throw_ref) {
/* Illegal assignment: evaluate and throw */ /* Illegal assignment: evaluate and throw */
hres = compile_expression(ctx, expr->expression1, TRUE); hres = compile_expression(ctx, expr->expression1, TRUE);
if(FAILED(hres)) if(FAILED(hres))
return hres; return hres;
arg_cnt = JS_E_ILLEGAL_ASSIGN;
hres = compile_expression(ctx, expr->expression2, TRUE);
if(FAILED(hres))
return hres;
if(op != OP_LAST && !push_instr(ctx, op))
return E_OUTOFMEMORY;
return push_instr_uint(ctx, OP_throw_ref, JS_E_ILLEGAL_ASSIGN);
} }
hres = compile_expression(ctx, expr->expression2, TRUE); hres = compile_expression(ctx, expr->expression2, TRUE);
...@@ -806,13 +807,7 @@ static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_ ...@@ -806,13 +807,7 @@ static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_
if(op != OP_LAST && !push_instr(ctx, op)) if(op != OP_LAST && !push_instr(ctx, op))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
if(arg_cnt) return push_instr_uint(ctx, assign_op, arg_cnt);
return push_instr_uint(ctx, OP_assign_call, arg_cnt);
if(!push_instr(ctx, OP_assign))
return E_OUTOFMEMORY;
return S_OK;
} }
static HRESULT compile_typeof_expression(compiler_ctx_t *ctx, unary_expression_t *expr) static HRESULT compile_typeof_expression(compiler_ctx_t *ctx, unary_expression_t *expr)
......
...@@ -2203,6 +2203,38 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val) ...@@ -2203,6 +2203,38 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
return hres; return hres;
} }
HRESULT disp_propput_name(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, jsval_t val)
{
jsdisp_t *jsdisp;
HRESULT hres;
jsdisp = iface_to_jsdisp(disp);
if(!jsdisp || jsdisp->ctx != ctx) {
IDispatchEx *dispex;
BSTR str;
DISPID id;
if(!(str = SysAllocString(name)))
return E_OUTOFMEMORY;
hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
if(SUCCEEDED(hres)) {
hres = IDispatchEx_GetDispID(dispex, str, make_grfdex(ctx, fdexNameEnsure|fdexNameCaseSensitive), &id);
IDispatchEx_Release(dispex);
}else {
TRACE("using IDispatch\n");
hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &str, 1, 0, &id);
}
SysFreeString(str);
if(FAILED(hres))
return hres;
return disp_propput(ctx, disp, id, val);
}
return jsdisp_propput_name(jsdisp, name, val);
}
HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
{ {
dispex_prop_t *prop; dispex_prop_t *prop;
......
...@@ -2511,6 +2511,25 @@ static HRESULT interp_rshift2(script_ctx_t *ctx) ...@@ -2511,6 +2511,25 @@ static HRESULT interp_rshift2(script_ctx_t *ctx)
return stack_push(ctx, jsval_number(l >> (r&0x1f))); return stack_push(ctx, jsval_number(l >> (r&0x1f)));
} }
/* ECMA-262 3rd Edition 9.8 */
static HRESULT interp_to_string(script_ctx_t *ctx)
{
jsstr_t *str;
jsval_t v;
HRESULT hres;
v = stack_pop(ctx);
TRACE("%s\n", debugstr_jsval(v));
hres = to_string(ctx, v, &str);
jsval_release(v);
if(FAILED(hres)) {
WARN("failed %08x\n", hres);
return hres;
}
return stack_push(ctx, jsval_string(str));
}
/* ECMA-262 3rd Edition 11.13.1 */ /* ECMA-262 3rd Edition 11.13.1 */
static HRESULT interp_assign(script_ctx_t *ctx) static HRESULT interp_assign(script_ctx_t *ctx)
{ {
...@@ -2537,6 +2556,41 @@ static HRESULT interp_assign(script_ctx_t *ctx) ...@@ -2537,6 +2556,41 @@ static HRESULT interp_assign(script_ctx_t *ctx)
return stack_push(ctx, v); return stack_push(ctx, v);
} }
/* ECMA-262 3rd Edition 11.13.1 */
static HRESULT interp_set_member(script_ctx_t *ctx)
{
jsval_t objv, namev, value;
const WCHAR *name;
IDispatch *obj;
HRESULT hres;
value = stack_pop(ctx);
namev = stack_pop(ctx);
assert(is_string(namev));
objv = stack_pop(ctx);
TRACE("%s.%s = %s\n", debugstr_jsval(objv), debugstr_jsval(namev), debugstr_jsval(value));
hres = to_object(ctx, objv, &obj);
jsval_release(objv);
if(SUCCEEDED(hres) && !(name = jsstr_flatten(get_string(namev)))) {
IDispatch_Release(obj);
hres = E_OUTOFMEMORY;
}
if(SUCCEEDED(hres)) {
hres = disp_propput_name(ctx, obj, name, value);
IDispatch_Release(obj);
jsstr_release(get_string(namev));
}
if(FAILED(hres)) {
WARN("failed %08x\n", hres);
jsval_release(value);
return hres;
}
return stack_push(ctx, value);
}
/* JScript extension */ /* JScript extension */
static HRESULT interp_assign_call(script_ctx_t *ctx) static HRESULT interp_assign_call(script_ctx_t *ctx)
{ {
......
...@@ -90,8 +90,10 @@ ...@@ -90,8 +90,10 @@
X(typeofident,1, 0,0) \ X(typeofident,1, 0,0) \
X(refval, 1, 0,0) \ X(refval, 1, 0,0) \
X(ret, 0, ARG_UINT, 0) \ X(ret, 0, ARG_UINT, 0) \
X(set_member, 1, 0,0) \
X(setret, 1, 0,0) \ X(setret, 1, 0,0) \
X(sub, 1, 0,0) \ X(sub, 1, 0,0) \
X(to_string, 1, 0,0) \
X(undefined, 1, 0,0) \ X(undefined, 1, 0,0) \
X(void, 1, 0,0) \ X(void, 1, 0,0) \
X(xor, 1, 0,0) X(xor, 1, 0,0)
......
...@@ -300,6 +300,7 @@ HRESULT jsdisp_call(jsdisp_t*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_H ...@@ -300,6 +300,7 @@ HRESULT jsdisp_call(jsdisp_t*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_H
HRESULT jsdisp_call_name(jsdisp_t*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT jsdisp_call_name(jsdisp_t*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
HRESULT disp_propget(script_ctx_t*,IDispatch*,DISPID,jsval_t*) DECLSPEC_HIDDEN; HRESULT disp_propget(script_ctx_t*,IDispatch*,DISPID,jsval_t*) DECLSPEC_HIDDEN;
HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,jsval_t) DECLSPEC_HIDDEN; HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,jsval_t) DECLSPEC_HIDDEN;
HRESULT disp_propput_name(script_ctx_t*,IDispatch*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN;
HRESULT jsdisp_propget(jsdisp_t*,DISPID,jsval_t*) DECLSPEC_HIDDEN; HRESULT jsdisp_propget(jsdisp_t*,DISPID,jsval_t*) DECLSPEC_HIDDEN;
HRESULT jsdisp_propput(jsdisp_t*,const WCHAR*,DWORD,jsval_t) DECLSPEC_HIDDEN; HRESULT jsdisp_propput(jsdisp_t*,const WCHAR*,DWORD,jsval_t) DECLSPEC_HIDDEN;
HRESULT jsdisp_propput_name(jsdisp_t*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN; HRESULT jsdisp_propput_name(jsdisp_t*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN;
......
...@@ -1834,6 +1834,12 @@ ok(""+str === "test", "''+str = " + str); ...@@ -1834,6 +1834,12 @@ ok(""+str === "test", "''+str = " + str);
ok((function (){return 1;})() === 1, "(function (){return 1;})() = " + (function (){return 1;})()); ok((function (){return 1;})() === 1, "(function (){return 1;})() = " + (function (){return 1;})());
(function() {
var order = "", o = {};
o[order += "1,", { toString: function() { order += "2,"; } }] = (order += "3");
ok(order === "1,2,3", "array expression order = " + order);
})();
var re = /=(\?|%3F)/g; var re = /=(\?|%3F)/g;
ok(re.source === "=(\\?|%3F)", "re.source = " + re.source); ok(re.source === "=(\\?|%3F)", "re.source = " + re.source);
......
...@@ -111,6 +111,7 @@ DEFINE_EXPECT(testobj_onlydispid_d); ...@@ -111,6 +111,7 @@ DEFINE_EXPECT(testobj_onlydispid_d);
DEFINE_EXPECT(testobj_onlydispid_i); DEFINE_EXPECT(testobj_onlydispid_i);
DEFINE_EXPECT(testobj_notexists_d); DEFINE_EXPECT(testobj_notexists_d);
DEFINE_EXPECT(testobj_newenum); DEFINE_EXPECT(testobj_newenum);
DEFINE_EXPECT(testobj_getidfail_d);
DEFINE_EXPECT(enumvariant_next_0); DEFINE_EXPECT(enumvariant_next_0);
DEFINE_EXPECT(enumvariant_next_1); DEFINE_EXPECT(enumvariant_next_1);
DEFINE_EXPECT(enumvariant_reset); DEFINE_EXPECT(enumvariant_reset);
...@@ -480,6 +481,10 @@ static HRESULT WINAPI testObj_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD ...@@ -480,6 +481,10 @@ static HRESULT WINAPI testObj_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD
test_grfdex(grfdex, fdexNameCaseSensitive); test_grfdex(grfdex, fdexNameCaseSensitive);
return DISP_E_UNKNOWNNAME; return DISP_E_UNKNOWNNAME;
} }
if(!lstrcmpW(bstrName, L"getIDFail")) {
CHECK_EXPECT(testobj_getidfail_d);
return E_FAIL;
}
ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName)); ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName));
return E_NOTIMPL; return E_NOTIMPL;
...@@ -3374,6 +3379,20 @@ static BOOL run_tests(void) ...@@ -3374,6 +3379,20 @@ static BOOL run_tests(void)
CHECK_CALLED(testobj_onlydispid_d); CHECK_CALLED(testobj_onlydispid_d);
CHECK_CALLED(testobj_onlydispid_i); CHECK_CALLED(testobj_onlydispid_i);
SET_EXPECT(testobj_getidfail_d);
hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, L"testObj.notExists = testObj.getIDFail;");
ok(hres == E_FAIL, "parse_script returned %08x\n", hres);
CHECK_CALLED(testobj_getidfail_d);
SET_EXPECT(global_propget_d);
SET_EXPECT(global_propget_i);
SET_EXPECT(testobj_getidfail_d);
hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, L"testObj.getIDFail = testPropGet;");
ok(hres == E_FAIL, "parse_script returned %08x\n", hres);
CHECK_CALLED(global_propget_d);
CHECK_CALLED(global_propget_i);
CHECK_CALLED(testobj_getidfail_d);
SET_EXPECT(global_propargput_d); SET_EXPECT(global_propargput_d);
SET_EXPECT(global_propargput_i); SET_EXPECT(global_propargput_i);
run_script(L"var t=0; propArgPutG(t++, t++) = t++;"); run_script(L"var t=0; propArgPutG(t++, t++) = t++;");
......
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