wine/dlls/jscript/engine.h
Gabriel Ivăncescu b0db79d769 jscript: Use a jsdisp to hold refs for scopes.
So the garbage collector can traverse it.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
2022-12-08 20:32:10 +01:00

306 lines
8.9 KiB
C

/*
* Copyright 2008,2011 Jacek Caban for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define OP_LIST \
X(add, 1, 0,0) \
X(and, 1, 0,0) \
X(array, 1, 0,0) \
X(assign, 1, 0,0) \
X(assign_call,1, ARG_UINT, 0) \
X(bool, 1, ARG_INT, 0) \
X(bneg, 1, 0,0) \
X(call, 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) \
X(case, 0, ARG_ADDR, 0) \
X(cnd_nz, 0, ARG_ADDR, 0) \
X(cnd_z, 0, ARG_ADDR, 0) \
X(delete, 1, 0,0) \
X(delete_ident,1,ARG_BSTR, 0) \
X(div, 1, 0,0) \
X(double, 1, ARG_DBL, 0) \
X(end_finally,0, 0,0) \
X(enter_catch,1, ARG_BSTR, 0) \
X(eq, 1, 0,0) \
X(eq2, 1, 0,0) \
X(forin, 0, ARG_ADDR, 0) \
X(func, 1, ARG_UINT, 0) \
X(gt, 1, 0,0) \
X(gteq, 1, 0,0) \
X(ident, 1, ARG_BSTR, 0) \
X(identid, 1, ARG_BSTR, ARG_INT) \
X(in, 1, 0,0) \
X(instanceof, 1, 0,0) \
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) \
X(member, 1, ARG_BSTR, 0) \
X(memberid, 1, ARG_UINT, 0) \
X(minus, 1, 0,0) \
X(mod, 1, 0,0) \
X(mul, 1, 0,0) \
X(neg, 1, 0,0) \
X(neq, 1, 0,0) \
X(neq2, 1, 0,0) \
X(new, 1, ARG_UINT, 0) \
X(new_obj, 1, 0,0) \
X(null, 1, 0,0) \
X(obj_prop, 1, ARG_STR, ARG_UINT) \
X(or, 1, 0,0) \
X(pop, 1, ARG_UINT, 0) \
X(pop_except, 0, ARG_ADDR, 0) \
X(pop_scope, 1, 0,0) \
X(postinc, 1, ARG_INT, 0) \
X(preinc, 1, ARG_INT, 0) \
X(push_acc, 1, 0,0) \
X(push_except,1, ARG_ADDR, ARG_UINT) \
X(push_block_scope, 1, ARG_UINT, 0) \
X(push_with_scope, 1, 0,0) \
X(regexp, 1, ARG_STR, ARG_UINT) \
X(rshift, 1, 0,0) \
X(rshift2, 1, 0,0) \
X(str, 1, ARG_STR, 0) \
X(this, 1, 0,0) \
X(throw, 0, 0,0) \
X(throw_ref, 0, ARG_UINT, 0) \
X(throw_type, 0, ARG_UINT, ARG_STR) \
X(tonum, 1, 0,0) \
X(typeof, 1, 0,0) \
X(typeofid, 1, 0,0) \
X(typeofident,1, 0,0) \
X(refval, 1, 0,0) \
X(ret, 0, ARG_UINT, 0) \
X(set_member, 1, 0,0) \
X(setret, 1, 0,0) \
X(sub, 1, 0,0) \
X(to_string, 1, 0,0) \
X(undefined, 1, 0,0) \
X(void, 1, 0,0) \
X(xor, 1, 0,0)
typedef enum {
#define X(x,a,b,c) OP_##x,
OP_LIST
#undef X
OP_LAST
} jsop_t;
typedef struct _bytecode_t bytecode_t;
typedef union {
BSTR bstr;
LONG lng;
jsstr_t *str;
unsigned uint;
} instr_arg_t;
typedef enum {
ARG_NONE = 0,
ARG_ADDR,
ARG_BSTR,
ARG_DBL,
ARG_FUNC,
ARG_INT,
ARG_STR,
ARG_UINT
} instr_arg_type_t;
typedef struct {
jsop_t op;
unsigned loc;
union {
instr_arg_t arg[2];
double dbl;
} u;
} instr_t;
typedef enum {
PROPERTY_DEFINITION_VALUE,
PROPERTY_DEFINITION_GETTER,
PROPERTY_DEFINITION_SETTER
} property_definition_type_t;
typedef struct {
BSTR name;
int ref;
} local_ref_t;
#define INVALID_LOCAL_REF 0x7fffffff
typedef struct {
unsigned locals_cnt;
local_ref_t *locals;
} local_ref_scopes_t;
typedef struct _function_code_t {
BSTR name;
int local_ref;
BSTR event_target;
unsigned instr_off;
const WCHAR *source;
unsigned source_len;
unsigned func_cnt;
struct _function_code_t *funcs;
unsigned var_cnt;
struct {
BSTR name;
int func_id; /* -1 if not a function */
} *variables;
unsigned param_cnt;
BSTR *params;
local_ref_scopes_t *local_scopes;
unsigned local_scope_count;
unsigned int scope_index; /* index of scope in the parent function where the function is defined */
bytecode_t *bytecode;
} function_code_t;
IDispatch *lookup_global_host(script_ctx_t*) DECLSPEC_HIDDEN;
local_ref_t *lookup_local(const function_code_t*,const WCHAR*,unsigned int) DECLSPEC_HIDDEN;
struct _bytecode_t {
LONG ref;
BOOL is_persistent;
instr_t *instrs;
heap_pool_t heap;
function_code_t global_code;
named_item_t *named_item;
WCHAR *source;
UINT64 source_context;
unsigned start_line;
BSTR *bstr_pool;
unsigned bstr_pool_size;
unsigned bstr_cnt;
jsstr_t **str_pool;
unsigned str_pool_size;
unsigned str_cnt;
struct list entry;
};
HRESULT compile_script(script_ctx_t*,const WCHAR*,UINT64,unsigned,const WCHAR*,const WCHAR*,BOOL,BOOL,named_item_t*,bytecode_t**) DECLSPEC_HIDDEN;
void release_bytecode(bytecode_t*) DECLSPEC_HIDDEN;
unsigned get_location_line(bytecode_t *code, unsigned loc, unsigned *char_pos) DECLSPEC_HIDDEN;
static inline bytecode_t *bytecode_addref(bytecode_t *code)
{
code->ref++;
return code;
}
typedef struct _scope_chain_t {
jsdisp_t dispex; /* FIXME: don't wrap it in a jsdisp (it holds ref and traverse for the garbage collector) */
jsdisp_t *jsobj;
IDispatch *obj;
unsigned int scope_index;
struct _call_frame_t *frame;
struct _scope_chain_t *next;
} scope_chain_t;
static inline scope_chain_t *scope_addref(scope_chain_t *scope)
{
jsdisp_addref(&scope->dispex);
return scope;
}
static inline void scope_release(scope_chain_t *scope)
{
jsdisp_release(&scope->dispex);
}
struct _jsexcept_t {
HRESULT error;
BOOL valid_value;
jsval_t value;
jsstr_t *source;
jsstr_t *message;
jsstr_t *line;
bytecode_t *code;
unsigned loc;
BOOL enter_notified;
jsexcept_t *prev;
};
void enter_script(script_ctx_t*,jsexcept_t*) DECLSPEC_HIDDEN;
HRESULT leave_script(script_ctx_t*,HRESULT) DECLSPEC_HIDDEN;
void reset_ei(jsexcept_t*) DECLSPEC_HIDDEN;
void set_error_location(jsexcept_t*,bytecode_t*,unsigned,unsigned,jsstr_t*) DECLSPEC_HIDDEN;
typedef struct _except_frame_t except_frame_t;
struct _parser_ctx_t;
typedef struct _call_frame_t {
unsigned ip;
except_frame_t *except_frame;
unsigned stack_base;
scope_chain_t *scope;
scope_chain_t *base_scope;
jsval_t ret;
IDispatch *this_obj;
jsdisp_t *function_instance;
jsdisp_t *variable_obj;
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;
struct _call_frame_t *prev_frame;
} 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*,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;