jscript: Use bytecode for logical or expression.
[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 /* ECMA-262 3rd Edition    11.14 */
160 static HRESULT compile_comma_expression(compiler_ctx_t *ctx, binary_expression_t *expr)
161 {
162     HRESULT hres;
163
164     hres = compile_expression(ctx, expr->expression1);
165     if(FAILED(hres))
166         return hres;
167
168     if(push_instr(ctx, OP_pop) == -1)
169         return E_OUTOFMEMORY;
170
171     return compile_expression(ctx, expr->expression2);
172 }
173
174 /* ECMA-262 3rd Edition    11.11 */
175 static HRESULT compile_logical_expression(compiler_ctx_t *ctx, binary_expression_t *expr, jsop_t op)
176 {
177     unsigned instr;
178     HRESULT hres;
179
180     hres = compile_expression(ctx, expr->expression1);
181     if(FAILED(hres))
182         return hres;
183
184     instr = push_instr(ctx, op);
185     if(instr == -1)
186         return E_OUTOFMEMORY;
187
188     hres = compile_expression(ctx, expr->expression2);
189     if(FAILED(hres))
190         return hres;
191
192     instr_ptr(ctx, instr)->arg1.uint = ctx->code_off;
193     return S_OK;
194 }
195
196 static HRESULT compile_interp_fallback(compiler_ctx_t *ctx, expression_t *expr)
197 {
198     unsigned instr;
199
200     instr = push_instr(ctx, OP_tree);
201     if(instr == -1)
202         return E_OUTOFMEMORY;
203
204     instr_ptr(ctx, instr)->arg1.expr = expr;
205     return S_OK;
206 }
207
208 static HRESULT compile_literal(compiler_ctx_t *ctx, literal_t *literal)
209 {
210     switch(literal->type) {
211     case LT_BOOL:
212         return push_instr_int(ctx, OP_bool, literal->u.bval);
213     case LT_DOUBLE:
214         return push_instr_double(ctx, OP_double, literal->u.dval);
215     case LT_INT:
216         return push_instr_int(ctx, OP_int, literal->u.lval);
217     case LT_NULL:
218         return push_instr(ctx, OP_null);
219     case LT_STRING:
220         return push_instr_str(ctx, OP_str, literal->u.wstr);
221     case LT_REGEXP: {
222         unsigned instr;
223         WCHAR *str;
224
225         str = compiler_alloc(ctx->code, (literal->u.regexp.str_len+1)*sizeof(WCHAR));
226         if(!str)
227             return E_OUTOFMEMORY;
228         memcpy(str, literal->u.regexp.str, literal->u.regexp.str_len*sizeof(WCHAR));
229         str[literal->u.regexp.str_len] = 0;
230
231         instr = push_instr(ctx, OP_regexp);
232         if(instr == -1)
233             return E_OUTOFMEMORY;
234
235         instr_ptr(ctx, instr)->arg1.str = str;
236         instr_ptr(ctx, instr)->arg2.lng = literal->u.regexp.flags;
237         return S_OK;
238     }
239     default:
240         assert(0);
241     }
242 }
243
244 static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr)
245 {
246     switch(expr->type) {
247     case EXPR_ADD:
248         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_add);
249     case EXPR_BITNEG:
250         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_bneg);
251     case EXPR_COMMA:
252         return compile_comma_expression(ctx, (binary_expression_t*)expr);
253     case EXPR_EQ:
254         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_eq);
255     case EXPR_EQEQ:
256         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_eq2);
257     case EXPR_IN:
258         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_in);
259     case EXPR_LITERAL:
260         return compile_literal(ctx, ((literal_expression_t*)expr)->literal);
261     case EXPR_LOGNEG:
262         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_neg);
263     case EXPR_MINUS:
264         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_minus);
265     case EXPR_NOTEQ:
266         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_neq);
267     case EXPR_NOTEQEQ:
268         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_neq2);
269     case EXPR_OR:
270         return compile_logical_expression(ctx, (binary_expression_t*)expr, OP_jmp_nz);
271     case EXPR_PLUS:
272         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_tonum);
273     case EXPR_SUB:
274         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_sub);
275     case EXPR_THIS:
276         return push_instr(ctx, OP_this) == -1 ? E_OUTOFMEMORY : S_OK;
277     case EXPR_VOID:
278         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_void);
279     default:
280         assert(expr->eval != compiled_expression_eval);
281         return compile_interp_fallback(ctx, expr);
282     }
283
284     return S_OK;
285 }
286
287 void release_bytecode(bytecode_t *code)
288 {
289     jsheap_free(&code->heap);
290     heap_free(code->instrs);
291     heap_free(code);
292 }
293
294 void release_compiler(compiler_ctx_t *ctx)
295 {
296     heap_free(ctx);
297 }
298
299 HRESULT compile_subscript(parser_ctx_t *parser, expression_t *expr, unsigned *ret_off)
300 {
301     HRESULT hres;
302
303     if(!parser->code) {
304         parser->code = heap_alloc_zero(sizeof(bytecode_t));
305         if(!parser->code)
306             return E_OUTOFMEMORY;
307         jsheap_init(&parser->code->heap);
308     }
309
310     if(!parser->compiler) {
311         parser->compiler = heap_alloc_zero(sizeof(compiler_ctx_t));
312         if(!parser->compiler)
313             return E_OUTOFMEMORY;
314
315         parser->compiler->parser = parser;
316         parser->compiler->code = parser->code;
317     }
318
319     *ret_off = parser->compiler->code_off;
320     hres = compile_expression(parser->compiler, expr);
321     if(FAILED(hres))
322         return hres;
323
324     return push_instr(parser->compiler, OP_ret) == -1 ? E_OUTOFMEMORY : S_OK;
325 }