wined3d: Get rid of the WINED3DADAPTER_IDENTIFIER typedef.
[wine] / dlls / jscript / compile.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <math.h>
20 #include <assert.h>
21
22 #include "jscript.h"
23 #include "engine.h"
24
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
28
29 struct _compiler_ctx_t {
30     parser_ctx_t *parser;
31     bytecode_t *code;
32
33     unsigned code_off;
34     unsigned code_size;
35 };
36
37 static HRESULT compile_expression(compiler_ctx_t*,expression_t*);
38
39 static inline void *compiler_alloc(bytecode_t *code, size_t size)
40 {
41     return jsheap_alloc(&code->heap, size);
42 }
43
44 static WCHAR *compiler_alloc_string(bytecode_t *code, const WCHAR *str)
45 {
46     size_t size;
47     WCHAR *ret;
48
49     size = (strlenW(str)+1)*sizeof(WCHAR);
50     ret = compiler_alloc(code, size);
51     if(ret)
52         memcpy(ret, str, size);
53     return ret;
54 }
55
56 static unsigned push_instr(compiler_ctx_t *ctx, jsop_t op)
57 {
58     assert(ctx->code_size >= ctx->code_off);
59
60     if(!ctx->code_size) {
61         ctx->code->instrs = heap_alloc(64 * sizeof(instr_t));
62         if(!ctx->code->instrs)
63             return -1;
64         ctx->code_size = 64;
65     }else if(ctx->code_size == ctx->code_off) {
66         instr_t *new_instrs;
67
68         new_instrs = heap_realloc(ctx->code->instrs, ctx->code_size*2*sizeof(instr_t));
69         if(!new_instrs)
70             return -1;
71
72         ctx->code->instrs = new_instrs;
73         ctx->code_size *= 2;
74     }
75
76     ctx->code->instrs[ctx->code_off].op = op;
77     return ctx->code_off++;
78 }
79
80 static inline instr_t *instr_ptr(compiler_ctx_t *ctx, unsigned off)
81 {
82     assert(off < ctx->code_off);
83     return ctx->code->instrs + off;
84 }
85
86 static HRESULT push_instr_int(compiler_ctx_t *ctx, jsop_t op, LONG arg)
87 {
88     unsigned instr;
89
90     instr = push_instr(ctx, op);
91     if(instr == -1)
92         return E_OUTOFMEMORY;
93
94     instr_ptr(ctx, instr)->arg1.lng = arg;
95     return S_OK;
96 }
97
98 static HRESULT push_instr_str(compiler_ctx_t *ctx, jsop_t op, const WCHAR *arg)
99 {
100     unsigned instr;
101     WCHAR *str;
102
103     str = compiler_alloc_string(ctx->code, arg);
104     if(!str)
105         return E_OUTOFMEMORY;
106
107     instr = push_instr(ctx, op);
108     if(instr == -1)
109         return E_OUTOFMEMORY;
110
111     instr_ptr(ctx, instr)->arg1.str = str;
112     return S_OK;
113 }
114
115 static HRESULT push_instr_double(compiler_ctx_t *ctx, jsop_t op, double arg)
116 {
117     unsigned instr;
118     DOUBLE *dbl;
119
120     dbl = compiler_alloc(ctx->code, sizeof(arg));
121     if(!dbl)
122         return E_OUTOFMEMORY;
123     *dbl = arg;
124
125     instr = push_instr(ctx, op);
126     if(instr == -1)
127         return E_OUTOFMEMORY;
128
129     instr_ptr(ctx, instr)->arg1.dbl = dbl;
130     return S_OK;
131 }
132
133 static HRESULT compile_binary_expression(compiler_ctx_t *ctx, binary_expression_t *expr, jsop_t op)
134 {
135     HRESULT hres;
136
137     hres = compile_expression(ctx, expr->expression1);
138     if(FAILED(hres))
139         return hres;
140
141     hres = compile_expression(ctx, expr->expression2);
142     if(FAILED(hres))
143         return hres;
144
145     return push_instr(ctx, op) == -1 ? E_OUTOFMEMORY : S_OK;
146 }
147
148 static HRESULT compile_unary_expression(compiler_ctx_t *ctx, unary_expression_t *expr, jsop_t op)
149 {
150     HRESULT hres;
151
152     hres = compile_expression(ctx, expr->expression);
153     if(FAILED(hres))
154         return hres;
155
156     return push_instr(ctx, op) == -1 ? E_OUTOFMEMORY : S_OK;
157 }
158
159 static HRESULT compile_interp_fallback(compiler_ctx_t *ctx, expression_t *expr)
160 {
161     unsigned instr;
162
163     instr = push_instr(ctx, OP_tree);
164     if(instr == -1)
165         return E_OUTOFMEMORY;
166
167     instr_ptr(ctx, instr)->arg1.expr = expr;
168     return S_OK;
169 }
170
171 static HRESULT compile_literal(compiler_ctx_t *ctx, literal_expression_t *expr)
172 {
173     literal_t *literal = expr->literal;
174
175     switch(literal->type) {
176     case LT_BOOL:
177         return push_instr_int(ctx, OP_bool, literal->u.bval);
178     case LT_DOUBLE:
179         return push_instr_double(ctx, OP_double, literal->u.dval);
180     case LT_INT:
181         return push_instr_int(ctx, OP_int, literal->u.lval);
182     case LT_STRING:
183         return push_instr_str(ctx, OP_str, literal->u.wstr);
184     default:
185         return compile_interp_fallback(ctx, &expr->expr);
186     }
187 }
188
189 static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr)
190 {
191     switch(expr->type) {
192     case EXPR_ADD:
193         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_add);
194     case EXPR_BITNEG:
195         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_bneg);
196     case EXPR_EQEQ:
197         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_eq2);
198     case EXPR_IN:
199         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_in);
200     case EXPR_LITERAL:
201         return compile_literal(ctx, (literal_expression_t*)expr);
202     case EXPR_LOGNEG:
203         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_neg);
204     case EXPR_NOTEQEQ:
205         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_neq2);
206     case EXPR_PLUS:
207         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_tonum);
208     default:
209         assert(expr->eval != compiled_expression_eval);
210         return compile_interp_fallback(ctx, expr);
211     }
212
213     return S_OK;
214 }
215
216 void release_bytecode(bytecode_t *code)
217 {
218     jsheap_free(&code->heap);
219     heap_free(code->instrs);
220     heap_free(code);
221 }
222
223 void release_compiler(compiler_ctx_t *ctx)
224 {
225     heap_free(ctx);
226 }
227
228 HRESULT compile_subscript(parser_ctx_t *parser, expression_t *expr, unsigned *ret_off)
229 {
230     HRESULT hres;
231
232     if(!parser->code) {
233         parser->code = heap_alloc_zero(sizeof(bytecode_t));
234         if(!parser->code)
235             return E_OUTOFMEMORY;
236         jsheap_init(&parser->code->heap);
237     }
238
239     if(!parser->compiler) {
240         parser->compiler = heap_alloc_zero(sizeof(compiler_ctx_t));
241         if(!parser->compiler)
242             return E_OUTOFMEMORY;
243
244         parser->compiler->parser = parser;
245         parser->compiler->code = parser->code;
246     }
247
248     *ret_off = parser->compiler->code_off;
249     hres = compile_expression(parser->compiler, expr);
250     if(FAILED(hres))
251         return hres;
252
253     return push_instr(parser->compiler, OP_ret) == -1 ? E_OUTOFMEMORY : S_OK;
254 }