mirror of
https://github.com/reactos/reactos.git
synced 2024-12-31 19:42:51 +00:00
[JSCRIPT] Sync with Wine Staging 1.9.16. CORE-11866
svn path=/trunk/; revision=72346
This commit is contained in:
parent
6873f2c1ae
commit
4dd5cd6d92
16 changed files with 1221 additions and 409 deletions
|
@ -178,7 +178,7 @@ static HRESULT concat_obj(jsdisp_t *array, IDispatch *obj, DWORD *len)
|
|||
jsdisp_t *jsobj;
|
||||
HRESULT hres;
|
||||
|
||||
jsobj = iface_to_jsdisp((IUnknown*)obj);
|
||||
jsobj = iface_to_jsdisp(obj);
|
||||
if(jsobj) {
|
||||
if(is_class(jsobj, JSCLASS_ARRAY)) {
|
||||
hres = concat_array(array, (ArrayInstance*)jsobj, len);
|
||||
|
@ -688,7 +688,7 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigne
|
|||
return E_FAIL;
|
||||
}
|
||||
|
||||
cmp_func = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
|
||||
cmp_func = iface_to_jsdisp(get_object(argv[0]));
|
||||
if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) {
|
||||
WARN("cmp_func is not a function\n");
|
||||
if(cmp_func)
|
||||
|
|
|
@ -46,12 +46,13 @@ typedef struct {
|
|||
unsigned labels_size;
|
||||
unsigned labels_cnt;
|
||||
|
||||
local_ref_t *locals_buf;
|
||||
unsigned locals_buf_size;
|
||||
unsigned locals_cnt;
|
||||
|
||||
statement_ctx_t *stat_ctx;
|
||||
function_code_t *func;
|
||||
|
||||
variable_declaration_t *var_head;
|
||||
variable_declaration_t *var_tail;
|
||||
|
||||
function_expression_t *func_head;
|
||||
function_expression_t *func_tail;
|
||||
} compiler_ctx_t;
|
||||
|
@ -399,6 +400,40 @@ static inline BOOL is_memberid_expr(expression_type_t type)
|
|||
return type == EXPR_IDENT || type == EXPR_MEMBER || type == EXPR_ARRAY;
|
||||
}
|
||||
|
||||
static BOOL bind_local(compiler_ctx_t *ctx, const WCHAR *identifier, int *ret_ref)
|
||||
{
|
||||
statement_ctx_t *iter;
|
||||
local_ref_t *ref;
|
||||
|
||||
for(iter = ctx->stat_ctx; iter; iter = iter->next) {
|
||||
if(iter->using_scope)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ref = lookup_local(ctx->func, identifier);
|
||||
if(!ref)
|
||||
return FALSE;
|
||||
|
||||
*ret_ref = ref->ref;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static HRESULT emit_identifier_ref(compiler_ctx_t *ctx, const WCHAR *identifier, unsigned flags)
|
||||
{
|
||||
int local_ref;
|
||||
if(bind_local(ctx, identifier, &local_ref))
|
||||
return push_instr_int(ctx, OP_local_ref, local_ref);
|
||||
return push_instr_bstr_uint(ctx, OP_identid, identifier, flags);
|
||||
}
|
||||
|
||||
static HRESULT emit_identifier(compiler_ctx_t *ctx, const WCHAR *identifier)
|
||||
{
|
||||
int local_ref;
|
||||
if(bind_local(ctx, identifier, &local_ref))
|
||||
return push_instr_int(ctx, OP_local, local_ref);
|
||||
return push_instr_bstr(ctx, OP_ident, identifier);
|
||||
}
|
||||
|
||||
static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags)
|
||||
{
|
||||
HRESULT hres = S_OK;
|
||||
|
@ -407,7 +442,7 @@ static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *ex
|
|||
case EXPR_IDENT: {
|
||||
identifier_expression_t *ident_expr = (identifier_expression_t*)expr;
|
||||
|
||||
hres = push_instr_bstr_uint(ctx, OP_identid, ident_expr->identifier, flags);
|
||||
hres = emit_identifier_ref(ctx, ident_expr->identifier, flags);
|
||||
break;
|
||||
}
|
||||
case EXPR_ARRAY: {
|
||||
|
@ -866,9 +901,7 @@ static HRESULT compile_object_literal(compiler_ctx_t *ctx, property_value_expres
|
|||
|
||||
static HRESULT compile_function_expression(compiler_ctx_t *ctx, function_expression_t *expr, BOOL emit_ret)
|
||||
{
|
||||
unsigned func_id = ctx->func->func_cnt++;
|
||||
ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr);
|
||||
return emit_ret ? push_instr_uint(ctx, OP_func, func_id) : S_OK;
|
||||
return emit_ret ? push_instr_uint(ctx, OP_func, expr->func_id) : S_OK;
|
||||
}
|
||||
|
||||
static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr, BOOL emit_ret)
|
||||
|
@ -961,7 +994,7 @@ static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr, BOOL
|
|||
hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_gteq);
|
||||
break;
|
||||
case EXPR_IDENT:
|
||||
hres = push_instr_bstr(ctx, OP_ident, ((identifier_expression_t*)expr)->identifier);
|
||||
hres = emit_identifier(ctx, ((identifier_expression_t*)expr)->identifier);
|
||||
break;
|
||||
case EXPR_IN:
|
||||
hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_in);
|
||||
|
@ -1084,25 +1117,22 @@ static HRESULT compile_variable_list(compiler_ctx_t *ctx, variable_declaration_t
|
|||
|
||||
assert(list != NULL);
|
||||
|
||||
if(ctx->var_tail)
|
||||
ctx->var_tail->global_next = list;
|
||||
else
|
||||
ctx->var_head = list;
|
||||
|
||||
for(iter = list; iter; iter = iter->next) {
|
||||
ctx->func->var_cnt++;
|
||||
iter->global_next = iter->next;
|
||||
if(!iter->next)
|
||||
ctx->var_tail = iter;
|
||||
|
||||
if(!iter->expr)
|
||||
continue;
|
||||
|
||||
hres = emit_identifier_ref(ctx, iter->identifier, 0);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = compile_expression(ctx, iter->expr, TRUE);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = push_instr_bstr(ctx, OP_var_set, iter->identifier);
|
||||
if(!push_instr(ctx, OP_assign))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
hres = push_instr_uint(ctx, OP_pop, 1);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
@ -1300,7 +1330,7 @@ static HRESULT compile_forin_statement(compiler_ctx_t *ctx, forin_statement_t *s
|
|||
return hres;
|
||||
|
||||
if(stat->variable) {
|
||||
hres = push_instr_bstr_uint(ctx, OP_identid, stat->variable->identifier, fdexNameEnsure);
|
||||
hres = emit_identifier_ref(ctx, stat->variable->identifier, fdexNameEnsure);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}else if(is_memberid_expr(stat->expr->type)) {
|
||||
|
@ -1774,6 +1804,393 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx,
|
|||
return hres;
|
||||
}
|
||||
|
||||
static int local_cmp(const void *key, const void *ref)
|
||||
{
|
||||
return strcmpW((const WCHAR*)key, ((const local_ref_t*)ref)->name);
|
||||
}
|
||||
|
||||
static inline local_ref_t *find_local(compiler_ctx_t *ctx, const WCHAR *name)
|
||||
{
|
||||
return bsearch(name, ctx->locals_buf, ctx->locals_cnt, sizeof(*ctx->locals_buf), local_cmp);
|
||||
}
|
||||
|
||||
static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if(!ctx->locals_buf_size) {
|
||||
ctx->locals_buf = heap_alloc(4 * sizeof(*ctx->locals_buf));
|
||||
if(!ctx->locals_buf)
|
||||
return FALSE;
|
||||
ctx->locals_buf_size = 4;
|
||||
}else if(ctx->locals_buf_size == ctx->locals_cnt) {
|
||||
local_ref_t *new_buf = heap_realloc(ctx->locals_buf, ctx->locals_buf_size * 2 * sizeof(*ctx->locals_buf));
|
||||
if(!new_buf)
|
||||
return FALSE;
|
||||
ctx->locals_buf = new_buf;
|
||||
ctx->locals_buf_size *= 2;
|
||||
}
|
||||
|
||||
for(i = 0; i < ctx->locals_cnt; i++) {
|
||||
if(strcmpW(ctx->locals_buf[i].name, name) > 0) {
|
||||
memmove(ctx->locals_buf + i+1, ctx->locals_buf + i, (ctx->locals_cnt - i) * sizeof(*ctx->locals_buf));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->locals_buf[i].name = name;
|
||||
ctx->locals_buf[i].ref = ref;
|
||||
ctx->locals_cnt++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name)
|
||||
{
|
||||
BSTR ident;
|
||||
|
||||
if(find_local(ctx, name))
|
||||
return TRUE;
|
||||
|
||||
ident = compiler_alloc_bstr(ctx, name);
|
||||
if(!ident)
|
||||
return FALSE;
|
||||
|
||||
return alloc_local(ctx, ident, ctx->func->var_cnt++);
|
||||
}
|
||||
|
||||
static BOOL visit_function_expression(compiler_ctx_t *ctx, function_expression_t *expr)
|
||||
{
|
||||
expr->func_id = ctx->func->func_cnt++;
|
||||
ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr);
|
||||
|
||||
return !expr->identifier || expr->event_target || alloc_variable(ctx, expr->identifier);
|
||||
}
|
||||
|
||||
static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr)
|
||||
{
|
||||
HRESULT hres = S_OK;
|
||||
|
||||
switch(expr->type) {
|
||||
case EXPR_ADD:
|
||||
case EXPR_AND:
|
||||
case EXPR_ARRAY:
|
||||
case EXPR_ASSIGN:
|
||||
case EXPR_ASSIGNADD:
|
||||
case EXPR_ASSIGNAND:
|
||||
case EXPR_ASSIGNSUB:
|
||||
case EXPR_ASSIGNMUL:
|
||||
case EXPR_ASSIGNDIV:
|
||||
case EXPR_ASSIGNMOD:
|
||||
case EXPR_ASSIGNOR:
|
||||
case EXPR_ASSIGNLSHIFT:
|
||||
case EXPR_ASSIGNRSHIFT:
|
||||
case EXPR_ASSIGNRRSHIFT:
|
||||
case EXPR_ASSIGNXOR:
|
||||
case EXPR_BAND:
|
||||
case EXPR_BOR:
|
||||
case EXPR_COMMA:
|
||||
case EXPR_DIV:
|
||||
case EXPR_EQ:
|
||||
case EXPR_EQEQ:
|
||||
case EXPR_GREATER:
|
||||
case EXPR_GREATEREQ:
|
||||
case EXPR_IN:
|
||||
case EXPR_INSTANCEOF:
|
||||
case EXPR_LESS:
|
||||
case EXPR_LESSEQ:
|
||||
case EXPR_LSHIFT:
|
||||
case EXPR_MOD:
|
||||
case EXPR_MUL:
|
||||
case EXPR_NOTEQ:
|
||||
case EXPR_NOTEQEQ:
|
||||
case EXPR_OR:
|
||||
case EXPR_RSHIFT:
|
||||
case EXPR_RRSHIFT:
|
||||
case EXPR_SUB:
|
||||
case EXPR_BXOR: {
|
||||
binary_expression_t *binary_expr = (binary_expression_t*)expr;
|
||||
|
||||
hres = visit_expression(ctx, binary_expr->expression1);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = visit_expression(ctx, binary_expr->expression2);
|
||||
break;
|
||||
}
|
||||
case EXPR_BITNEG:
|
||||
case EXPR_DELETE:
|
||||
case EXPR_LOGNEG:
|
||||
case EXPR_MINUS:
|
||||
case EXPR_PLUS:
|
||||
case EXPR_POSTDEC:
|
||||
case EXPR_POSTINC:
|
||||
case EXPR_PREDEC:
|
||||
case EXPR_PREINC:
|
||||
case EXPR_TYPEOF:
|
||||
case EXPR_VOID:
|
||||
hres = visit_expression(ctx, ((unary_expression_t*)expr)->expression);
|
||||
break;
|
||||
case EXPR_IDENT:
|
||||
case EXPR_LITERAL:
|
||||
case EXPR_THIS:
|
||||
break;
|
||||
case EXPR_ARRAYLIT: {
|
||||
array_literal_expression_t *array_expr = (array_literal_expression_t*)expr;
|
||||
array_element_t *iter;
|
||||
|
||||
for(iter = array_expr->element_list; iter; iter = iter->next) {
|
||||
hres = visit_expression(ctx, iter->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXPR_CALL:
|
||||
case EXPR_NEW: {
|
||||
call_expression_t *call_expr = (call_expression_t*)expr;
|
||||
argument_t *arg;
|
||||
|
||||
hres = visit_expression(ctx, call_expr->expression);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
for(arg = call_expr->argument_list; arg; arg = arg->next) {
|
||||
hres = visit_expression(ctx, arg->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXPR_COND: {
|
||||
conditional_expression_t *cond_expr = (conditional_expression_t*)expr;
|
||||
|
||||
hres = visit_expression(ctx, cond_expr->expression);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = visit_expression(ctx, cond_expr->true_expression);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = visit_expression(ctx, cond_expr->false_expression);
|
||||
break;
|
||||
}
|
||||
case EXPR_FUNC:
|
||||
visit_function_expression(ctx, (function_expression_t*)expr);
|
||||
break;
|
||||
case EXPR_MEMBER:
|
||||
hres = visit_expression(ctx, ((member_expression_t*)expr)->expression);
|
||||
break;
|
||||
case EXPR_PROPVAL: {
|
||||
prop_val_t *iter;
|
||||
for(iter = ((property_value_expression_t*)expr)->property_list; iter; iter = iter->next) {
|
||||
hres = visit_expression(ctx, iter->value);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
break;
|
||||
}
|
||||
DEFAULT_UNREACHABLE;
|
||||
}
|
||||
|
||||
return hres;
|
||||
}
|
||||
|
||||
static HRESULT visit_variable_list(compiler_ctx_t *ctx, variable_declaration_t *list)
|
||||
{
|
||||
variable_declaration_t *iter;
|
||||
HRESULT hres;
|
||||
|
||||
for(iter = list; iter; iter = iter->next) {
|
||||
if(!alloc_variable(ctx, iter->identifier))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if(iter->expr) {
|
||||
hres = visit_expression(ctx, iter->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT visit_statement(compiler_ctx_t*,statement_t*);
|
||||
|
||||
static HRESULT visit_block_statement(compiler_ctx_t *ctx, statement_t *iter)
|
||||
{
|
||||
HRESULT hres;
|
||||
|
||||
while(iter) {
|
||||
hres = visit_statement(ctx, iter);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
|
||||
{
|
||||
HRESULT hres = S_OK;
|
||||
|
||||
switch(stat->type) {
|
||||
case STAT_BLOCK:
|
||||
hres = visit_block_statement(ctx, ((block_statement_t*)stat)->stat_list);
|
||||
break;
|
||||
case STAT_BREAK:
|
||||
case STAT_CONTINUE:
|
||||
case STAT_EMPTY:
|
||||
break;
|
||||
case STAT_EXPR:
|
||||
case STAT_RETURN:
|
||||
case STAT_THROW: {
|
||||
expression_statement_t *expr_stat = (expression_statement_t*)stat;
|
||||
if(expr_stat->expr)
|
||||
hres = visit_expression(ctx, expr_stat->expr);
|
||||
break;
|
||||
}
|
||||
case STAT_FOR: {
|
||||
for_statement_t *for_stat = (for_statement_t*)stat;
|
||||
|
||||
if(for_stat->variable_list)
|
||||
hres = visit_variable_list(ctx, for_stat->variable_list);
|
||||
else if(for_stat->begin_expr)
|
||||
hres = visit_expression(ctx, for_stat->begin_expr);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
|
||||
if(for_stat->expr) {
|
||||
hres = visit_expression(ctx, for_stat->expr);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}
|
||||
|
||||
hres = visit_statement(ctx, for_stat->statement);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
|
||||
if(for_stat->end_expr)
|
||||
hres = visit_expression(ctx, for_stat->end_expr);
|
||||
break;
|
||||
}
|
||||
case STAT_FORIN: {
|
||||
forin_statement_t *forin_stat = (forin_statement_t*)stat;
|
||||
|
||||
if(forin_stat->variable) {
|
||||
hres = visit_variable_list(ctx, forin_stat->variable);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}
|
||||
|
||||
hres = visit_expression(ctx, forin_stat->in_expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(forin_stat->expr) {
|
||||
hres = visit_expression(ctx, forin_stat->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
hres = visit_statement(ctx, forin_stat->statement);
|
||||
break;
|
||||
}
|
||||
case STAT_IF: {
|
||||
if_statement_t *if_stat = (if_statement_t*)stat;
|
||||
|
||||
hres = visit_expression(ctx, if_stat->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = visit_statement(ctx, if_stat->if_stat);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(if_stat->else_stat)
|
||||
hres = visit_statement(ctx, if_stat->else_stat);
|
||||
break;
|
||||
}
|
||||
case STAT_LABEL:
|
||||
hres = visit_statement(ctx, ((labelled_statement_t*)stat)->statement);
|
||||
break;
|
||||
case STAT_SWITCH: {
|
||||
switch_statement_t *switch_stat = (switch_statement_t*)stat;
|
||||
statement_t *stat_iter;
|
||||
case_clausule_t *iter;
|
||||
|
||||
hres = visit_expression(ctx, switch_stat->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
for(iter = switch_stat->case_list; iter; iter = iter->next) {
|
||||
if(!iter->expr)
|
||||
continue;
|
||||
hres = visit_expression(ctx, iter->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
for(iter = switch_stat->case_list; iter; iter = iter->next) {
|
||||
while(iter->next && iter->next->stat == iter->stat)
|
||||
iter = iter->next;
|
||||
for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter);
|
||||
stat_iter = stat_iter->next) {
|
||||
hres = visit_statement(ctx, stat_iter);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STAT_TRY: {
|
||||
try_statement_t *try_stat = (try_statement_t*)stat;
|
||||
|
||||
hres = visit_statement(ctx, try_stat->try_statement);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(try_stat->catch_block) {
|
||||
hres = visit_statement(ctx, try_stat->catch_block->statement);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
if(try_stat->finally_statement)
|
||||
hres = visit_statement(ctx, try_stat->finally_statement);
|
||||
break;
|
||||
}
|
||||
case STAT_VAR:
|
||||
hres = visit_variable_list(ctx, ((var_statement_t*)stat)->variable_list);
|
||||
break;
|
||||
case STAT_WHILE: {
|
||||
while_statement_t *while_stat = (while_statement_t*)stat;
|
||||
|
||||
hres = visit_expression(ctx, while_stat->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = visit_statement(ctx, while_stat->statement);
|
||||
break;
|
||||
}
|
||||
case STAT_WITH: {
|
||||
with_statement_t *with_stat = (with_statement_t*)stat;
|
||||
|
||||
hres = visit_expression(ctx, with_stat->expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = visit_statement(ctx, with_stat->statement);
|
||||
break;
|
||||
}
|
||||
DEFAULT_UNREACHABLE;
|
||||
}
|
||||
|
||||
return hres;
|
||||
}
|
||||
|
||||
static void resolve_labels(compiler_ctx_t *ctx, unsigned off)
|
||||
{
|
||||
instr_t *instr;
|
||||
|
@ -1838,35 +2255,20 @@ static HRESULT init_code(compiler_ctx_t *compiler, const WCHAR *source)
|
|||
static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, function_expression_t *func_expr,
|
||||
BOOL from_eval, function_code_t *func)
|
||||
{
|
||||
variable_declaration_t *var_iter;
|
||||
function_expression_t *iter;
|
||||
unsigned off, i;
|
||||
unsigned off, i, j;
|
||||
HRESULT hres;
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
ctx->var_head = ctx->var_tail = NULL;
|
||||
ctx->func_head = ctx->func_tail = NULL;
|
||||
ctx->from_eval = from_eval;
|
||||
|
||||
off = ctx->code_off;
|
||||
ctx->func = func;
|
||||
hres = compile_block_statement(ctx, source->statement);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
resolve_labels(ctx, off);
|
||||
|
||||
hres = push_instr_uint(ctx, OP_ret, !from_eval);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(TRACE_ON(jscript_disas))
|
||||
dump_code(ctx, off);
|
||||
|
||||
func->instr_off = off;
|
||||
ctx->locals_cnt = 0;
|
||||
|
||||
if(func_expr) {
|
||||
parameter_t *param_iter;
|
||||
|
||||
if(func_expr->identifier) {
|
||||
func->name = compiler_alloc_bstr(ctx, func_expr->identifier);
|
||||
if(!func->name)
|
||||
|
@ -1878,10 +2280,6 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
|
|||
if(!func->event_target)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if(func_expr) {
|
||||
parameter_t *param_iter;
|
||||
|
||||
func->source = func_expr->src_str;
|
||||
func->source_len = func_expr->src_len;
|
||||
|
@ -1900,27 +2298,69 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
|
|||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < func->param_cnt; i++) {
|
||||
if(!find_local(ctx, func->params[i]) && !alloc_local(ctx, func->params[i], -i-1))
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
hres = visit_block_statement(ctx, source->statement);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
func->locals = compiler_alloc(ctx->code, ctx->locals_cnt * sizeof(*func->locals));
|
||||
if(!func->locals)
|
||||
return E_OUTOFMEMORY;
|
||||
func->locals_cnt = ctx->locals_cnt;
|
||||
memcpy(func->locals, ctx->locals_buf, func->locals_cnt * sizeof(*func->locals));
|
||||
|
||||
func->variables = compiler_alloc(ctx->code, func->var_cnt * sizeof(*func->variables));
|
||||
if(!func->variables)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
for(var_iter = ctx->var_head, i=0; var_iter; var_iter = var_iter->global_next, i++) {
|
||||
func->variables[i] = compiler_alloc_bstr(ctx, var_iter->identifier);
|
||||
if(!func->variables[i])
|
||||
return E_OUTOFMEMORY;
|
||||
for(i = 0, j = 0; i < func->locals_cnt; i++) {
|
||||
if(func->locals[i].ref < 0)
|
||||
continue; /* skip arguments */
|
||||
func->variables[func->locals[i].ref].name = func->locals[i].name;
|
||||
func->variables[func->locals[i].ref].func_id = -1;
|
||||
j++;
|
||||
}
|
||||
|
||||
assert(i == func->var_cnt);
|
||||
assert(j == func->var_cnt);
|
||||
|
||||
func->funcs = compiler_alloc(ctx->code, func->func_cnt * sizeof(*func->funcs));
|
||||
if(!func->funcs)
|
||||
return E_OUTOFMEMORY;
|
||||
memset(func->funcs, 0, func->func_cnt * sizeof(*func->funcs));
|
||||
|
||||
off = ctx->code_off;
|
||||
hres = compile_block_statement(ctx, source->statement);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
resolve_labels(ctx, off);
|
||||
|
||||
hres = push_instr_uint(ctx, OP_ret, !from_eval);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(TRACE_ON(jscript_disas))
|
||||
dump_code(ctx, off);
|
||||
|
||||
func->instr_off = off;
|
||||
|
||||
for(iter = ctx->func_head, i=0; iter; iter = iter->next, i++) {
|
||||
hres = compile_function(ctx, iter->source_elements, iter, FALSE, func->funcs+i);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
TRACE("[%d] func %s\n", i, debugstr_w(func->funcs[i].name));
|
||||
if(func->funcs[i].name && !func->funcs[i].event_target) {
|
||||
local_ref_t *local_ref = lookup_local(func, func->funcs[i].name);
|
||||
func->funcs[i].local_ref = local_ref->ref;
|
||||
TRACE("found ref %s %d for %s\n", debugstr_w(local_ref->name), local_ref->ref, debugstr_w(func->funcs[i].name));
|
||||
if(local_ref->ref >= 0)
|
||||
func->variables[local_ref->ref].func_id = i;
|
||||
}
|
||||
}
|
||||
|
||||
assert(i == func->func_cnt);
|
||||
|
@ -2030,6 +2470,7 @@ HRESULT compile_script(script_ctx_t *ctx, const WCHAR *code, const WCHAR *args,
|
|||
|
||||
hres = compile_function(&compiler, compiler.parser->source, NULL, from_eval, &compiler.code->global_code);
|
||||
parser_release(compiler.parser);
|
||||
heap_free(compiler.locals_buf);
|
||||
if(FAILED(hres)) {
|
||||
release_bytecode(compiler.code);
|
||||
return hres;
|
||||
|
|
|
@ -18,13 +18,6 @@
|
|||
|
||||
#include "jscript.h"
|
||||
|
||||
/*
|
||||
* This IID is used to get jsdisp_t objecto from interface.
|
||||
* We might consider using private interface instead.
|
||||
*/
|
||||
static const IID IID_IDispatchJS =
|
||||
{0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}};
|
||||
|
||||
#define FDEX_VERSION_MASK 0xf0000000
|
||||
#define GOLDEN_RATIO 0x9E3779B9U
|
||||
|
||||
|
@ -491,10 +484,8 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServi
|
|||
TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
|
||||
|
||||
hres = jsval_copy(val, &prop->u.val);
|
||||
if(FAILED(hres)) {
|
||||
prop->u.val = jsval_undefined();
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
if(This->builtin_info->on_put)
|
||||
This->builtin_info->on_put(This, prop->name);
|
||||
|
@ -558,11 +549,6 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid,
|
|||
}else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
|
||||
TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
|
||||
*ppv = &This->IDispatchEx_iface;
|
||||
}else if(IsEqualGUID(&IID_IDispatchJS, riid)) {
|
||||
TRACE("(%p)->(IID_IDispatchJS %p)\n", This, ppv);
|
||||
jsdisp_addref(This);
|
||||
*ppv = This;
|
||||
return S_OK;
|
||||
}else {
|
||||
WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
|
||||
*ppv = NULL;
|
||||
|
@ -584,6 +570,7 @@ static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
|
|||
{
|
||||
jsdisp_t *This = impl_from_IDispatchEx(iface);
|
||||
ULONG ref = --This->ref;
|
||||
TRACE("(%p) ref=%d\n", This, ref);
|
||||
if(!ref)
|
||||
jsdisp_free(This);
|
||||
return ref;
|
||||
|
@ -1007,7 +994,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built
|
|||
}
|
||||
|
||||
if(is_object_instance(val))
|
||||
prot = iface_to_jsdisp((IUnknown*)get_object(val));
|
||||
prot = iface_to_jsdisp(get_object(val));
|
||||
jsval_release(val);
|
||||
}
|
||||
|
||||
|
@ -1018,16 +1005,11 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built
|
|||
return hres;
|
||||
}
|
||||
|
||||
jsdisp_t *iface_to_jsdisp(IUnknown *iface)
|
||||
jsdisp_t *iface_to_jsdisp(IDispatch *iface)
|
||||
{
|
||||
jsdisp_t *ret;
|
||||
HRESULT hres;
|
||||
|
||||
hres = IUnknown_QueryInterface(iface, &IID_IDispatchJS, (void**)&ret);
|
||||
if(FAILED(hres))
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
return iface->lpVtbl == (const IDispatchVtbl*)&DispatchExVtbl
|
||||
? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx*)iface))
|
||||
: NULL;
|
||||
}
|
||||
|
||||
HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
|
||||
|
@ -1107,7 +1089,7 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns
|
|||
unsigned i;
|
||||
HRESULT hres;
|
||||
|
||||
jsdisp = iface_to_jsdisp((IUnknown*)disp);
|
||||
jsdisp = iface_to_jsdisp(disp);
|
||||
if(jsdisp) {
|
||||
if(flags & DISPATCH_PROPERTYPUT) {
|
||||
FIXME("disp_call(propput) on builtin object\n");
|
||||
|
@ -1200,7 +1182,7 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W
|
|||
|
||||
assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
|
||||
|
||||
jsdisp = iface_to_jsdisp((IUnknown*)disp);
|
||||
jsdisp = iface_to_jsdisp(disp);
|
||||
if(jsdisp) {
|
||||
hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
|
||||
jsdisp_release(jsdisp);
|
||||
|
@ -1339,7 +1321,7 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
|
|||
jsdisp_t *jsdisp;
|
||||
HRESULT hres;
|
||||
|
||||
jsdisp = iface_to_jsdisp((IUnknown*)disp);
|
||||
jsdisp = iface_to_jsdisp(disp);
|
||||
if(jsdisp) {
|
||||
dispex_prop_t *prop;
|
||||
|
||||
|
@ -1444,7 +1426,7 @@ HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val
|
|||
VARIANT var;
|
||||
HRESULT hres;
|
||||
|
||||
jsdisp = iface_to_jsdisp((IUnknown*)disp);
|
||||
jsdisp = iface_to_jsdisp(disp);
|
||||
if(jsdisp) {
|
||||
hres = jsdisp_propget(jsdisp, id, val);
|
||||
jsdisp_release(jsdisp);
|
||||
|
@ -1495,7 +1477,7 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret)
|
|||
jsdisp_t *jsdisp;
|
||||
HRESULT hres;
|
||||
|
||||
jsdisp = iface_to_jsdisp((IUnknown*)disp);
|
||||
jsdisp = iface_to_jsdisp(disp);
|
||||
if(jsdisp) {
|
||||
dispex_prop_t *prop;
|
||||
|
||||
|
@ -1531,7 +1513,7 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL
|
|||
BSTR bstr;
|
||||
HRESULT hres;
|
||||
|
||||
jsdisp = iface_to_jsdisp((IUnknown*)disp);
|
||||
jsdisp = iface_to_jsdisp(disp);
|
||||
if(jsdisp) {
|
||||
dispex_prop_t *prop;
|
||||
const WCHAR *ptr;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -50,6 +50,8 @@
|
|||
X(int, 1, ARG_INT, 0) \
|
||||
X(jmp, 0, ARG_ADDR, 0) \
|
||||
X(jmp_z, 0, ARG_ADDR, 0) \
|
||||
X(local, 1, ARG_INT, 0) \
|
||||
X(local_ref, 1, ARG_INT, ARG_UINT) \
|
||||
X(lshift, 1, 0,0) \
|
||||
X(lt, 1, 0,0) \
|
||||
X(lteq, 1, 0,0) \
|
||||
|
@ -91,7 +93,6 @@
|
|||
X(setret, 1, 0,0) \
|
||||
X(sub, 1, 0,0) \
|
||||
X(undefined, 1, 0,0) \
|
||||
X(var_set, 1, ARG_BSTR, 0) \
|
||||
X(void, 1, 0,0) \
|
||||
X(xor, 1, 0,0)
|
||||
|
||||
|
@ -128,8 +129,14 @@ typedef struct {
|
|||
} u;
|
||||
} instr_t;
|
||||
|
||||
typedef struct {
|
||||
BSTR name;
|
||||
int ref;
|
||||
} local_ref_t;
|
||||
|
||||
typedef struct _function_code_t {
|
||||
BSTR name;
|
||||
int local_ref;
|
||||
BSTR event_target;
|
||||
unsigned instr_off;
|
||||
|
||||
|
@ -140,12 +147,20 @@ typedef struct _function_code_t {
|
|||
struct _function_code_t *funcs;
|
||||
|
||||
unsigned var_cnt;
|
||||
BSTR *variables;
|
||||
struct {
|
||||
BSTR name;
|
||||
int func_id; /* -1 if not a function */
|
||||
} *variables;
|
||||
|
||||
unsigned param_cnt;
|
||||
BSTR *params;
|
||||
|
||||
unsigned locals_cnt;
|
||||
local_ref_t *locals;
|
||||
} function_code_t;
|
||||
|
||||
local_ref_t *lookup_local(const function_code_t*,const WCHAR*) DECLSPEC_HIDDEN;
|
||||
|
||||
typedef struct _bytecode_t {
|
||||
LONG ref;
|
||||
|
||||
|
@ -180,6 +195,7 @@ typedef struct _scope_chain_t {
|
|||
LONG ref;
|
||||
jsdisp_t *jsobj;
|
||||
IDispatch *obj;
|
||||
struct _call_frame_t *frame;
|
||||
struct _scope_chain_t *next;
|
||||
} scope_chain_t;
|
||||
|
||||
|
@ -210,6 +226,12 @@ typedef struct _call_frame_t {
|
|||
jsdisp_t *arguments_obj;
|
||||
DWORD flags;
|
||||
|
||||
unsigned argc;
|
||||
unsigned pop_locals;
|
||||
unsigned arguments_off;
|
||||
unsigned variables_off;
|
||||
unsigned pop_variables;
|
||||
|
||||
bytecode_t *bytecode;
|
||||
function_code_t *function;
|
||||
|
||||
|
@ -219,8 +241,11 @@ typedef struct _call_frame_t {
|
|||
#define EXEC_GLOBAL 0x0001
|
||||
#define EXEC_CONSTRUCTOR 0x0002
|
||||
#define EXEC_RETURN_TO_INTERP 0x0004
|
||||
#define EXEC_EVAL 0x0008
|
||||
|
||||
HRESULT exec_source(script_ctx_t*,DWORD,bytecode_t*,function_code_t*,scope_chain_t*,IDispatch*,
|
||||
jsdisp_t*,jsdisp_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||
jsdisp_t*,jsdisp_t*,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT create_source_function(script_ctx_t*,bytecode_t*,function_code_t*,scope_chain_t*,jsdisp_t**) DECLSPEC_HIDDEN;
|
||||
HRESULT setup_arguments_object(script_ctx_t*,call_frame_t*) DECLSPEC_HIDDEN;
|
||||
void detach_arguments_object(jsdisp_t*) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -32,7 +32,9 @@ typedef struct {
|
|||
typedef struct {
|
||||
jsdisp_t jsdisp;
|
||||
FunctionInstance *function;
|
||||
jsdisp_t *var_obj;
|
||||
jsval_t *buf;
|
||||
call_frame_t *frame;
|
||||
unsigned argc;
|
||||
} ArgumentsInstance;
|
||||
|
||||
static inline FunctionInstance *function_from_jsdisp(jsdisp_t *jsdisp)
|
||||
|
@ -50,6 +52,11 @@ static inline FunctionInstance *function_this(vdisp_t *jsthis)
|
|||
return is_vclass(jsthis, JSCLASS_FUNCTION) ? function_from_vdisp(jsthis) : NULL;
|
||||
}
|
||||
|
||||
static inline ArgumentsInstance *arguments_from_jsdisp(jsdisp_t *jsdisp)
|
||||
{
|
||||
return CONTAINING_RECORD(jsdisp, ArgumentsInstance, jsdisp);
|
||||
}
|
||||
|
||||
static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
|
||||
|
||||
static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
|
||||
|
@ -58,21 +65,6 @@ static const WCHAR applyW[] = {'a','p','p','l','y',0};
|
|||
static const WCHAR callW[] = {'c','a','l','l',0};
|
||||
static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
|
||||
|
||||
static HRESULT init_parameters(jsdisp_t *var_disp, FunctionInstance *function, unsigned argc, jsval_t *argv)
|
||||
{
|
||||
DWORD i=0;
|
||||
HRESULT hres;
|
||||
|
||||
for(i=0; i < function->func_code->param_cnt; i++) {
|
||||
hres = jsdisp_propput_name(var_disp, function->func_code->params[i],
|
||||
i < argc ? argv[i] : jsval_undefined());
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
|
||||
jsval_t *r)
|
||||
{
|
||||
|
@ -84,35 +76,69 @@ static void Arguments_destructor(jsdisp_t *jsdisp)
|
|||
{
|
||||
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
||||
|
||||
TRACE("(%p)\n", arguments);
|
||||
|
||||
if(arguments->buf) {
|
||||
unsigned i;
|
||||
for(i = 0; i < arguments->argc; i++)
|
||||
jsval_release(arguments->buf[i]);
|
||||
heap_free(arguments->buf);
|
||||
}
|
||||
|
||||
jsdisp_release(&arguments->function->dispex);
|
||||
jsdisp_release(arguments->var_obj);
|
||||
heap_free(arguments);
|
||||
}
|
||||
|
||||
static unsigned Arguments_idx_length(jsdisp_t *jsdisp)
|
||||
{
|
||||
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
||||
return arguments->function->length;
|
||||
return arguments->argc;
|
||||
}
|
||||
|
||||
static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *res)
|
||||
static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx)
|
||||
{
|
||||
if(arguments->buf)
|
||||
return arguments->buf + idx;
|
||||
if(arguments->frame->base_scope->frame || idx >= arguments->frame->function->param_cnt)
|
||||
return arguments->jsdisp.ctx->stack + arguments->frame->arguments_off + idx;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r)
|
||||
{
|
||||
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
||||
jsval_t *ref;
|
||||
|
||||
TRACE("%p[%u]\n", arguments, idx);
|
||||
|
||||
if((ref = get_argument_ref(arguments, idx)))
|
||||
return jsval_copy(*ref, r);
|
||||
|
||||
/* FIXME: Accessing by name won't work for duplicated argument names */
|
||||
return jsdisp_propget_name(arguments->var_obj, arguments->function->func_code->params[idx], res);
|
||||
return jsdisp_propget_name(arguments->frame->base_scope->jsobj, arguments->function->func_code->params[idx], r);
|
||||
}
|
||||
|
||||
static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val)
|
||||
{
|
||||
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
||||
jsval_t *ref;
|
||||
HRESULT hres;
|
||||
|
||||
TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val));
|
||||
|
||||
if((ref = get_argument_ref(arguments, idx))) {
|
||||
jsval_t copy;
|
||||
hres = jsval_copy(val, ©);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
jsval_release(*ref);
|
||||
*ref = copy;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* FIXME: Accessing by name won't work for duplicated argument names */
|
||||
return jsdisp_propput_name(arguments->var_obj, arguments->function->func_code->params[idx], val);
|
||||
return jsdisp_propput_name(arguments->frame->base_scope->jsobj, arguments->function->func_code->params[idx], val);
|
||||
}
|
||||
|
||||
static const builtin_info_t Arguments_info = {
|
||||
|
@ -126,11 +152,9 @@ static const builtin_info_t Arguments_info = {
|
|||
Arguments_idx_put
|
||||
};
|
||||
|
||||
static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, jsdisp_t *var_obj,
|
||||
unsigned argc, jsval_t *argv, jsdisp_t **ret)
|
||||
HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame)
|
||||
{
|
||||
ArgumentsInstance *args;
|
||||
unsigned i;
|
||||
HRESULT hres;
|
||||
|
||||
static const WCHAR caleeW[] = {'c','a','l','l','e','e',0};
|
||||
|
@ -145,60 +169,64 @@ static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, jsdi
|
|||
return hres;
|
||||
}
|
||||
|
||||
jsdisp_addref(&calee->dispex);
|
||||
args->function = calee;
|
||||
args->var_obj = jsdisp_addref(var_obj);
|
||||
args->function = function_from_jsdisp(jsdisp_addref(frame->function_instance));
|
||||
args->argc = frame->argc;
|
||||
args->frame = frame;
|
||||
|
||||
/* Store unnamed arguments directly in arguments object */
|
||||
for(i = calee->length; i < argc; i++) {
|
||||
WCHAR buf[12];
|
||||
|
||||
static const WCHAR formatW[] = {'%','d',0};
|
||||
|
||||
sprintfW(buf, formatW, i);
|
||||
hres = jsdisp_propput_dontenum(&args->jsdisp, buf, argv[i]);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hres)) {
|
||||
hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(argc));
|
||||
if(SUCCEEDED(hres))
|
||||
hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&calee->dispex)));
|
||||
}
|
||||
hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(args->argc));
|
||||
if(SUCCEEDED(hres))
|
||||
hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&args->function->dispex)));
|
||||
if(SUCCEEDED(hres))
|
||||
hres = jsdisp_propput(frame->base_scope->jsobj, argumentsW, PROPF_DONTDELETE, jsval_obj(&args->jsdisp));
|
||||
if(FAILED(hres)) {
|
||||
jsdisp_release(&args->jsdisp);
|
||||
return hres;
|
||||
}
|
||||
|
||||
*ret = &args->jsdisp;
|
||||
frame->arguments_obj = &args->jsdisp;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv, jsdisp_t **ret)
|
||||
void detach_arguments_object(jsdisp_t *args_disp)
|
||||
{
|
||||
jsdisp_t *var_disp;
|
||||
ArgumentsInstance *arguments = arguments_from_jsdisp(args_disp);
|
||||
call_frame_t *frame = arguments->frame;
|
||||
const BOOL on_stack = frame->base_scope->frame == frame;
|
||||
HRESULT hres;
|
||||
|
||||
hres = create_dispex(ctx, NULL, NULL, &var_disp);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
/* Reset arguments value to cut the reference cycle. Note that since all activation contexts have
|
||||
* their own arguments property, it's impossible to use prototype's one during name lookup */
|
||||
jsdisp_propput_name(frame->base_scope->jsobj, argumentsW, jsval_undefined());
|
||||
arguments->frame = NULL;
|
||||
|
||||
hres = init_parameters(var_disp, function, argc, argv);
|
||||
if(FAILED(hres)) {
|
||||
jsdisp_release(var_disp);
|
||||
return hres;
|
||||
/* Don't bother coppying arguments if call frame holds the last reference. */
|
||||
if(arguments->jsdisp.ref > 1) {
|
||||
arguments->buf = heap_alloc(arguments->argc * sizeof(*arguments->buf));
|
||||
if(arguments->buf) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < arguments->argc ; i++) {
|
||||
if(on_stack || i >= frame->function->param_cnt)
|
||||
hres = jsval_copy(arguments->jsdisp.ctx->stack[frame->arguments_off + i], arguments->buf+i);
|
||||
else
|
||||
hres = jsdisp_propget_name(frame->base_scope->jsobj, frame->function->params[i], arguments->buf+i);
|
||||
if(FAILED(hres))
|
||||
arguments->buf[i] = jsval_undefined();
|
||||
}
|
||||
}else {
|
||||
ERR("out of memory\n");
|
||||
arguments->argc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*ret = var_disp;
|
||||
return S_OK;
|
||||
jsdisp_release(frame->arguments_obj);
|
||||
}
|
||||
|
||||
static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv,
|
||||
BOOL is_constructor, BOOL caller_execs_source, jsval_t *r)
|
||||
{
|
||||
jsdisp_t *var_disp, *arg_disp;
|
||||
scope_chain_t *scope;
|
||||
jsdisp_t *var_disp;
|
||||
DWORD exec_flags = 0;
|
||||
HRESULT hres;
|
||||
|
||||
if(ctx->state == SCRIPTSTATE_UNINITIALIZED || ctx->state == SCRIPTSTATE_CLOSED) {
|
||||
|
@ -211,38 +239,17 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
|
|||
return E_FAIL;
|
||||
}
|
||||
|
||||
hres = create_var_disp(ctx, function, argc, argv, &var_disp);
|
||||
hres = create_dispex(ctx, NULL, NULL, &var_disp);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = create_arguments(ctx, function, var_disp, argc, argv, &arg_disp);
|
||||
if(FAILED(hres)) {
|
||||
jsdisp_release(var_disp);
|
||||
return hres;
|
||||
}
|
||||
if(caller_execs_source)
|
||||
exec_flags |= EXEC_RETURN_TO_INTERP;
|
||||
if(is_constructor)
|
||||
exec_flags |= EXEC_CONSTRUCTOR;
|
||||
hres = exec_source(ctx, exec_flags, function->code, function->func_code, function->scope_chain, this_obj,
|
||||
&function->dispex, var_disp, argc, argv, r);
|
||||
|
||||
hres = jsdisp_propput(var_disp, argumentsW, PROPF_DONTDELETE, jsval_obj(arg_disp));
|
||||
if(FAILED(hres)) {
|
||||
jsdisp_release(arg_disp);
|
||||
jsdisp_release(var_disp);
|
||||
return hres;
|
||||
}
|
||||
|
||||
hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope);
|
||||
if(SUCCEEDED(hres)) {
|
||||
DWORD exec_flags = 0;
|
||||
|
||||
if(caller_execs_source)
|
||||
exec_flags |= EXEC_RETURN_TO_INTERP;
|
||||
if(is_constructor)
|
||||
exec_flags |= EXEC_CONSTRUCTOR;
|
||||
hres = exec_source(ctx, exec_flags, function->code, function->func_code, scope, this_obj,
|
||||
&function->dispex, var_disp, arg_disp, r);
|
||||
|
||||
scope_release(scope);
|
||||
}
|
||||
|
||||
jsdisp_release(arg_disp);
|
||||
jsdisp_release(var_disp);
|
||||
return hres;
|
||||
}
|
||||
|
@ -419,7 +426,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
|
|||
|
||||
TRACE("\n");
|
||||
|
||||
if(!(function = function_this(jsthis)))
|
||||
if(!(function = function_this(jsthis)) && (jsthis->flags & VDISP_JSDISP))
|
||||
return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
|
||||
|
||||
if(argc) {
|
||||
|
@ -434,7 +441,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
|
|||
jsdisp_t *arg_array = NULL;
|
||||
|
||||
if(is_object_instance(argv[1])) {
|
||||
arg_array = iface_to_jsdisp((IUnknown*)get_object(argv[1]));
|
||||
arg_array = iface_to_jsdisp(get_object(argv[1]));
|
||||
if(arg_array &&
|
||||
(!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) {
|
||||
jsdisp_release(arg_array);
|
||||
|
@ -451,8 +458,20 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
|
|||
}
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hres))
|
||||
hres = call_function(ctx, function, this_obj, cnt, args, (flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE) != 0, r);
|
||||
if(SUCCEEDED(hres)) {
|
||||
if(function) {
|
||||
hres = call_function(ctx, function, this_obj, cnt, args, (flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE) != 0, r);
|
||||
}else {
|
||||
jsval_t res;
|
||||
hres = disp_call_value(ctx, jsthis->u.disp, this_obj, DISPATCH_METHOD, cnt, args, &res);
|
||||
if(SUCCEEDED(hres)) {
|
||||
if(r)
|
||||
*r = res;
|
||||
else
|
||||
jsval_release(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(this_obj)
|
||||
IDispatch_Release(this_obj);
|
||||
|
@ -529,11 +548,17 @@ static HRESULT Function_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval
|
|||
{
|
||||
FunctionInstance *function = function_from_jsdisp(jsthis);
|
||||
call_frame_t *frame;
|
||||
HRESULT hres;
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) {
|
||||
if(frame->function_instance == &function->dispex) {
|
||||
if(!frame->arguments_obj) {
|
||||
hres = setup_arguments_object(ctx, frame);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
*r = jsval_obj(jsdisp_addref(frame->arguments_obj));
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -775,7 +800,7 @@ static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *arg
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(code->global_code.func_cnt != 1 || code->global_code.var_cnt) {
|
||||
if(code->global_code.func_cnt != 1 || code->global_code.var_cnt != 1) {
|
||||
ERR("Invalid parser result!\n");
|
||||
release_bytecode(code);
|
||||
return E_UNEXPECTED;
|
||||
|
|
|
@ -179,7 +179,7 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a
|
|||
jsval_t *r)
|
||||
{
|
||||
call_frame_t *frame;
|
||||
DWORD exec_flags = 0;
|
||||
DWORD exec_flags = EXEC_EVAL;
|
||||
bytecode_t *code;
|
||||
const WCHAR *src;
|
||||
HRESULT hres;
|
||||
|
@ -219,7 +219,7 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a
|
|||
if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
|
||||
exec_flags |= EXEC_RETURN_TO_INTERP;
|
||||
hres = exec_source(ctx, exec_flags, code, &code->global_code, frame->scope,
|
||||
frame->this_obj, NULL, frame->variable_obj, NULL, r);
|
||||
frame->this_obj, NULL, frame->variable_obj, 0, NULL, r);
|
||||
release_bytecode(code);
|
||||
return hres;
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ static HRESULT exec_global_code(JScript *This, bytecode_t *code)
|
|||
IActiveScriptSite_OnEnterScript(This->site);
|
||||
|
||||
clear_ei(This->ctx);
|
||||
hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, NULL, NULL);
|
||||
hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, NULL);
|
||||
|
||||
IActiveScriptSite_OnLeaveScript(This->site);
|
||||
return hres;
|
||||
|
@ -765,7 +765,7 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
|
|||
IActiveScriptSite_OnEnterScript(This->site);
|
||||
|
||||
clear_ei(This->ctx);
|
||||
hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, NULL, &r);
|
||||
hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, &r);
|
||||
if(SUCCEEDED(hres)) {
|
||||
if(pvarResult)
|
||||
hres = jsval_to_variant(r, pvarResult);
|
||||
|
|
|
@ -142,7 +142,7 @@ typedef enum {
|
|||
JSCLASS_JSON
|
||||
} jsclass_t;
|
||||
|
||||
jsdisp_t *iface_to_jsdisp(IUnknown*) DECLSPEC_HIDDEN;
|
||||
jsdisp_t *iface_to_jsdisp(IDispatch*) DECLSPEC_HIDDEN;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
|
@ -184,7 +184,7 @@ static inline void set_disp(vdisp_t *vdisp, IDispatch *disp)
|
|||
jsdisp_t *jsdisp;
|
||||
HRESULT hres;
|
||||
|
||||
jsdisp = iface_to_jsdisp((IUnknown*)disp);
|
||||
jsdisp = iface_to_jsdisp(disp);
|
||||
if(jsdisp) {
|
||||
vdisp->u.jsdisp = jsdisp;
|
||||
vdisp->flags = VDISP_JSDISP | VDISP_DISPEX;
|
||||
|
|
|
@ -412,7 +412,7 @@ static HRESULT maybe_to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *r)
|
|||
jsdisp_t *obj;
|
||||
HRESULT hres;
|
||||
|
||||
if(!is_object_instance(val) || !get_object(val) || !(obj = iface_to_jsdisp((IUnknown*)get_object(val))))
|
||||
if(!is_object_instance(val) || !get_object(val) || !(obj = iface_to_jsdisp(get_object(val))))
|
||||
return jsval_copy(val, r);
|
||||
|
||||
if(is_class(obj, JSCLASS_NUMBER)) {
|
||||
|
@ -663,7 +663,7 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val)
|
|||
jsdisp_t *obj;
|
||||
DISPID id;
|
||||
|
||||
obj = iface_to_jsdisp((IUnknown*)get_object(val));
|
||||
obj = iface_to_jsdisp(get_object(val));
|
||||
if(!obj)
|
||||
return S_FALSE;
|
||||
|
||||
|
@ -721,7 +721,7 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val)
|
|||
case JSV_OBJECT: {
|
||||
jsdisp_t *obj;
|
||||
|
||||
obj = iface_to_jsdisp((IUnknown*)get_object(value));
|
||||
obj = iface_to_jsdisp(get_object(value));
|
||||
if(!obj) {
|
||||
hres = S_FALSE;
|
||||
break;
|
||||
|
|
|
@ -328,6 +328,7 @@ static HRESULT RegExp_set_lastIndex(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t
|
|||
|
||||
TRACE("\n");
|
||||
|
||||
jsval_release(regexp->last_index_val);
|
||||
hres = jsval_copy(value, ®exp->last_index_val);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
@ -697,7 +698,7 @@ HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg
|
|||
if(is_object_instance(src_arg)) {
|
||||
jsdisp_t *obj;
|
||||
|
||||
obj = iface_to_jsdisp((IUnknown*)get_object(src_arg));
|
||||
obj = iface_to_jsdisp(get_object(src_arg));
|
||||
if(obj) {
|
||||
if(is_class(obj, JSCLASS_REGEXP)) {
|
||||
RegExpInstance *regexp = (RegExpInstance*)obj;
|
||||
|
@ -948,7 +949,7 @@ static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
|
|||
case DISPATCH_METHOD:
|
||||
if(argc) {
|
||||
if(is_object_instance(argv[0])) {
|
||||
jsdisp_t *jsdisp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
|
||||
jsdisp_t *jsdisp = iface_to_jsdisp(get_object(argv[0]));
|
||||
if(jsdisp) {
|
||||
if(is_class(jsdisp, JSCLASS_REGEXP)) {
|
||||
if(argc > 1 && !is_undefined(argv[1])) {
|
||||
|
|
|
@ -138,7 +138,7 @@ void heap_pool_clear(heap_pool_t *heap)
|
|||
if(!heap)
|
||||
return;
|
||||
|
||||
while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
|
||||
while((tmp = list_head(&heap->custom_blocks))) {
|
||||
list_remove(tmp);
|
||||
heap_free(tmp);
|
||||
}
|
||||
|
@ -202,13 +202,17 @@ static HRESULT jsval_variant(jsval_t *val, VARIANT *var)
|
|||
|
||||
__JSVAL_TYPE(*val) = JSV_VARIANT;
|
||||
__JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT));
|
||||
if(!v)
|
||||
if(!v) {
|
||||
*val = jsval_undefined();
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
V_VT(v) = VT_EMPTY;
|
||||
hres = VariantCopy(v, var);
|
||||
if(FAILED(hres))
|
||||
if(FAILED(hres)) {
|
||||
*val = jsval_undefined();
|
||||
heap_free(v);
|
||||
}
|
||||
return hres;
|
||||
}
|
||||
|
||||
|
@ -382,7 +386,7 @@ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
jsdisp = iface_to_jsdisp((IUnknown*)get_object(val));
|
||||
jsdisp = iface_to_jsdisp(get_object(val));
|
||||
if(!jsdisp)
|
||||
return disp_propget(ctx, get_object(val), DISPID_VALUE, ret);
|
||||
|
||||
|
|
|
@ -255,6 +255,9 @@ static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
|
|||
|
||||
switch(flags) {
|
||||
case DISPATCH_METHOD:
|
||||
case DISPATCH_CONSTRUCT: {
|
||||
jsdisp_t *obj;
|
||||
|
||||
if(argc) {
|
||||
if(!is_undefined(argv[0]) && !is_null(argv[0]) && (!is_object_instance(argv[0]) || get_object(argv[0]))) {
|
||||
IDispatch *disp;
|
||||
|
@ -270,9 +273,6 @@ static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
|
|||
return S_OK;
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
case DISPATCH_CONSTRUCT: {
|
||||
jsdisp_t *obj;
|
||||
|
||||
hres = create_object(ctx, NULL, &obj);
|
||||
if(FAILED(hres))
|
||||
|
|
|
@ -296,6 +296,7 @@ typedef struct _function_expression_t {
|
|||
source_elements_t *source_elements;
|
||||
const WCHAR *src_str;
|
||||
DWORD src_len;
|
||||
unsigned func_id;
|
||||
|
||||
struct _function_expression_t *next; /* for compiler */
|
||||
} function_expression_t;
|
||||
|
|
|
@ -628,7 +628,7 @@ static HRESULT String_match(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi
|
|||
}
|
||||
|
||||
if(is_object_instance(argv[0])) {
|
||||
regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
|
||||
regexp = iface_to_jsdisp(get_object(argv[0]));
|
||||
if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
|
||||
jsdisp_release(regexp);
|
||||
regexp = NULL;
|
||||
|
@ -791,7 +791,7 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
|
|||
}
|
||||
|
||||
if(is_object_instance(argv[0])) {
|
||||
regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
|
||||
regexp = iface_to_jsdisp(get_object(argv[0]));
|
||||
if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
|
||||
jsdisp_release(regexp);
|
||||
regexp = NULL;
|
||||
|
@ -808,7 +808,7 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
|
|||
|
||||
if(argc >= 2) {
|
||||
if(is_object_instance(argv[1])) {
|
||||
rep_func = iface_to_jsdisp((IUnknown*)get_object(argv[1]));
|
||||
rep_func = iface_to_jsdisp(get_object(argv[1]));
|
||||
if(rep_func && !is_class(rep_func, JSCLASS_FUNCTION)) {
|
||||
jsdisp_release(rep_func);
|
||||
rep_func = NULL;
|
||||
|
@ -1009,7 +1009,7 @@ static HRESULT String_search(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns
|
|||
}
|
||||
|
||||
if(is_object_instance(argv[0])) {
|
||||
regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
|
||||
regexp = iface_to_jsdisp(get_object(argv[0]));
|
||||
if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
|
||||
jsdisp_release(regexp);
|
||||
regexp = NULL;
|
||||
|
@ -1153,7 +1153,7 @@ static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi
|
|||
}
|
||||
|
||||
if(is_object_instance(argv[0])) {
|
||||
regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
|
||||
regexp = iface_to_jsdisp(get_object(argv[0]));
|
||||
if(regexp) {
|
||||
if(!is_class(regexp, JSCLASS_REGEXP)) {
|
||||
jsdisp_release(regexp);
|
||||
|
|
|
@ -85,7 +85,7 @@ reactos/dll/win32/inseng # Synced to WineStaging-1.9.11
|
|||
reactos/dll/win32/iphlpapi # Out of sync
|
||||
reactos/dll/win32/itircl # Synced to WineStaging-1.9.11
|
||||
reactos/dll/win32/itss # Synced to WineStaging-1.9.11
|
||||
reactos/dll/win32/jscript # Synced to WineStaging-1.9.11
|
||||
reactos/dll/win32/jscript # Synced to WineStaging-1.9.16
|
||||
reactos/dll/win32/jsproxy # Synced to WineStaging-1.9.11
|
||||
reactos/dll/win32/loadperf # Synced to WineStaging-1.9.11
|
||||
reactos/dll/win32/localspl # Synced to WineStaging-1.9.11
|
||||
|
|
Loading…
Reference in a new issue