blob: e0043efb4f56d39710f279f9d674b4c13f3575bc [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
12#include <dlfcn.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000013#include <errno.h>
Jack Palevichac0e95e2009-05-29 13:53:44 -070014#include <setjmp.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070015#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070016#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070017#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070018#include <stdlib.h>
19#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070020#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070021
Jack Palevich8dc662e2009-06-09 22:53:47 +000022#if defined(__i386__)
23#include <sys/mman.h>
24#endif
25
Jack Palevich546b2242009-05-13 15:10:04 -070026#if defined(__arm__)
27#include <unistd.h>
28#endif
29
Jack Paleviche7b59062009-05-19 17:12:17 -070030#if defined(__arm__)
31#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070032#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070033#elif defined(__i386__)
34#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070035#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070036#elif defined(__x86_64__)
37#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070038#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070039#endif
40
Jack Paleviche7b59062009-05-19 17:12:17 -070041
42#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070043#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070044#endif
Jack Palevicha6535612009-05-13 16:24:17 -070045
Jack Palevich1cdef202009-05-22 12:06:27 -070046#include <acc/acc.h>
47
Jack Palevich09555c72009-05-27 12:25:55 -070048#define LOG_API(...) do {} while(0)
49// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070050// #define ENABLE_ARM_DISASSEMBLY
51
Jack Palevichbbf8ab52009-05-11 11:54:30 -070052namespace acc {
53
Jack Palevichac0e95e2009-05-29 13:53:44 -070054class ErrorSink {
55public:
56 void error(const char *fmt, ...) {
57 va_list ap;
58 va_start(ap, fmt);
59 verror(fmt, ap);
60 va_end(ap);
61 }
62
63 virtual void verror(const char* fmt, va_list ap) = 0;
64};
65
66class Compiler : public ErrorSink {
Jack Palevich21a15a22009-05-11 14:49:29 -070067 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -070068 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -070069 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -070070 ErrorSink* mErrorSink;
71 int mSize;
Jack Palevichf0cbc922009-05-08 16:35:13 -070072
Jack Palevich21a15a22009-05-11 14:49:29 -070073 void release() {
74 if (pProgramBase != 0) {
75 free(pProgramBase);
76 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070077 }
Jack Palevich21a15a22009-05-11 14:49:29 -070078 }
79
Jack Palevichac0e95e2009-05-29 13:53:44 -070080 void check(int n) {
81 int newSize = ind - pProgramBase + n;
82 if (newSize > mSize) {
83 if (mErrorSink) {
84 mErrorSink->error("Code too large: %d bytes", newSize);
85 }
86 }
87 }
88
Jack Palevich21a15a22009-05-11 14:49:29 -070089 public:
90 CodeBuf() {
91 pProgramBase = 0;
92 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -070093 mErrorSink = 0;
94 mSize = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -070095 }
96
97 ~CodeBuf() {
98 release();
99 }
100
101 void init(int size) {
102 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700103 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700104 pProgramBase = (char*) calloc(1, size);
105 ind = pProgramBase;
106 }
107
Jack Palevichac0e95e2009-05-29 13:53:44 -0700108 void setErrorSink(ErrorSink* pErrorSink) {
109 mErrorSink = pErrorSink;
110 }
111
Jack Palevich546b2242009-05-13 15:10:04 -0700112 int o4(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700113 check(4);
Jack Palevich8b0624c2009-05-20 12:12:06 -0700114 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700115 * (int*) ind = n;
116 ind += 4;
117 return result;
118 }
119
Jack Palevich21a15a22009-05-11 14:49:29 -0700120 /*
121 * Output a byte. Handles all values, 0..ff.
122 */
123 void ob(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700124 check(1);
Jack Palevich21a15a22009-05-11 14:49:29 -0700125 *ind++ = n;
126 }
127
Jack Palevich21a15a22009-05-11 14:49:29 -0700128 inline void* getBase() {
129 return (void*) pProgramBase;
130 }
131
Jack Palevich8b0624c2009-05-20 12:12:06 -0700132 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700133 return ind - pProgramBase;
134 }
135
Jack Palevich8b0624c2009-05-20 12:12:06 -0700136 intptr_t getPC() {
137 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700138 }
139 };
140
Jack Palevich1cdef202009-05-22 12:06:27 -0700141 /**
142 * A code generator creates an in-memory program, generating the code on
143 * the fly. There is one code generator implementation for each supported
144 * architecture.
145 *
146 * The code generator implements the following abstract machine:
147 * R0 - the main accumulator.
148 * R1 - the secondary accumulator.
149 * FP - a frame pointer for accessing function arguments and local
150 * variables.
151 * SP - a stack pointer for storing intermediate results while evaluating
152 * expressions. The stack pointer grows downwards.
153 *
154 * The function calling convention is that all arguments are placed on the
155 * stack such that the first argument has the lowest address.
156 * After the call, the result is in R0. The caller is responsible for
157 * removing the arguments from the stack.
158 * The R0 and R1 registers are not saved across function calls. The
159 * FP and SP registers are saved.
160 */
161
Jack Palevich21a15a22009-05-11 14:49:29 -0700162 class CodeGenerator {
163 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700164 CodeGenerator() {
165 mErrorSink = 0;
166 pCodeBuf = 0;
167 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700168 virtual ~CodeGenerator() {}
169
Jack Palevich22305132009-05-13 10:58:45 -0700170 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700171 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700172 pCodeBuf->setErrorSink(mErrorSink);
173 }
174
175 void setErrorSink(ErrorSink* pErrorSink) {
176 mErrorSink = pErrorSink;
177 if (pCodeBuf) {
178 pCodeBuf->setErrorSink(mErrorSink);
179 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700180 }
181
Jack Palevich1cdef202009-05-22 12:06:27 -0700182 /* Emit a function prolog.
183 * argCount is the number of arguments.
184 * Save the old value of the FP.
185 * Set the new value of the FP.
186 * Convert from the native platform calling convention to
187 * our stack-based calling convention. This may require
188 * pushing arguments from registers to the stack.
189 * Allocate "N" bytes of stack space. N isn't known yet, so
190 * just emit the instructions for adjusting the stack, and return
191 * the address to patch up. The patching will be done in
192 * functionExit().
193 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700194 */
Jack Palevich546b2242009-05-13 15:10:04 -0700195 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700196
Jack Palevich1cdef202009-05-22 12:06:27 -0700197 /* Emit a function epilog.
198 * Restore the old SP and FP register values.
199 * Return to the calling function.
200 * argCount - the number of arguments to the function.
201 * localVariableAddress - returned from functionEntry()
202 * localVariableSize - the size in bytes of the local variables.
203 */
204 virtual void functionExit(int argCount, int localVariableAddress,
205 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700206
Jack Palevich1cdef202009-05-22 12:06:27 -0700207 /* load immediate value to R0 */
Jack Palevich546b2242009-05-13 15:10:04 -0700208 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700209
Jack Palevich1cdef202009-05-22 12:06:27 -0700210 /* Jump to a target, and return the address of the word that
211 * holds the target data, in case it needs to be fixed up later.
212 */
Jack Palevich22305132009-05-13 10:58:45 -0700213 virtual int gjmp(int t) = 0;
214
Jack Palevich1cdef202009-05-22 12:06:27 -0700215 /* Test R0 and jump to a target if the test succeeds.
216 * l = 0: je, l == 1: jne
217 * Return the address of the word that holds the targed data, in
218 * case it needs to be fixed up later.
219 */
Jack Palevich22305132009-05-13 10:58:45 -0700220 virtual int gtst(bool l, int t) = 0;
221
Jack Palevich1cdef202009-05-22 12:06:27 -0700222 /* Compare R1 against R0, and store the boolean result in R0.
223 * op specifies the comparison.
224 */
Jack Palevich22305132009-05-13 10:58:45 -0700225 virtual void gcmp(int op) = 0;
226
Jack Palevich1cdef202009-05-22 12:06:27 -0700227 /* Perform the arithmetic op specified by op. R1 is the
228 * left argument, R0 is the right argument.
229 */
Jack Palevich546b2242009-05-13 15:10:04 -0700230 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700231
Jack Palevich1cdef202009-05-22 12:06:27 -0700232 /* Set R1 to 0.
233 */
234 virtual void clearR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700235
Jack Palevich1cdef202009-05-22 12:06:27 -0700236 /* Push R0 onto the stack.
237 */
238 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700239
Jack Palevich1cdef202009-05-22 12:06:27 -0700240 /* Pop R1 off of the stack.
241 */
242 virtual void popR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700243
Jack Palevich1cdef202009-05-22 12:06:27 -0700244 /* Store R0 to the address stored in R1.
245 * isInt is true if a whole 4-byte integer value
246 * should be stored, otherwise a 1-byte character
247 * value should be stored.
248 */
249 virtual void storeR0ToR1(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700250
Jack Palevich1cdef202009-05-22 12:06:27 -0700251 /* Load R0 from the address stored in R0.
252 * isInt is true if a whole 4-byte integer value
253 * should be loaded, otherwise a 1-byte character
254 * value should be loaded.
255 */
256 virtual void loadR0FromR0(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700257
Jack Palevich1cdef202009-05-22 12:06:27 -0700258 /* Load the absolute address of a variable to R0.
259 * If ea <= LOCAL, then this is a local variable, or an
260 * argument, addressed relative to FP.
261 * else it is an absolute global address.
262 */
263 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700264
Jack Palevich1cdef202009-05-22 12:06:27 -0700265 /* Store R0 to a variable.
266 * If ea <= LOCAL, then this is a local variable, or an
267 * argument, addressed relative to FP.
268 * else it is an absolute global address.
269 */
270 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700271
Jack Palevich1cdef202009-05-22 12:06:27 -0700272 /* load R0 from a variable.
273 * If ea <= LOCAL, then this is a local variable, or an
274 * argument, addressed relative to FP.
275 * else it is an absolute global address.
276 * If isIncDec is true, then the stored variable's value
277 * should be post-incremented or post-decremented, based
278 * on the value of op.
279 */
280 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700281
Jack Palevich1cdef202009-05-22 12:06:27 -0700282 /* Emit code to adjust the stack for a function call. Return the
283 * label for the address of the instruction that adjusts the
284 * stack size. This will be passed as argument "a" to
285 * endFunctionCallArguments.
286 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700287 virtual int beginFunctionCallArguments() = 0;
288
Jack Palevich1cdef202009-05-22 12:06:27 -0700289 /* Emit code to store R0 to the stack at byte offset l.
290 */
291 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700292
Jack Palevich1cdef202009-05-22 12:06:27 -0700293 /* Patch the function call preamble.
294 * a is the address returned from beginFunctionCallArguments
295 * l is the number of bytes the arguments took on the stack.
296 * Typically you would also emit code to convert the argument
297 * list into whatever the native function calling convention is.
298 * On ARM for example you would pop the first 5 arguments into
299 * R0..R4
300 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700301 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700302
Jack Palevich1cdef202009-05-22 12:06:27 -0700303 /* Emit a call to an unknown function. The argument "symbol" needs to
304 * be stored in the location where the address should go. It forms
305 * a chain. The address will be patched later.
306 * Return the address of the word that has to be patched.
307 */
Jack Palevich22305132009-05-13 10:58:45 -0700308 virtual int callForward(int symbol) = 0;
309
Jack Palevich1cdef202009-05-22 12:06:27 -0700310 /* Call a function using PC-relative addressing. t is the PC-relative
311 * address of the function. It has already been adjusted for the
312 * architectural jump offset, so just store it as-is.
313 */
Jack Palevich22305132009-05-13 10:58:45 -0700314 virtual void callRelative(int t) = 0;
315
Jack Palevich1cdef202009-05-22 12:06:27 -0700316 /* Call a function pointer. L is the number of bytes the arguments
317 * take on the stack. The address of the function is stored at
318 * location SP + l.
319 */
Jack Palevich22305132009-05-13 10:58:45 -0700320 virtual void callIndirect(int l) = 0;
321
Jack Palevich1cdef202009-05-22 12:06:27 -0700322 /* Adjust SP after returning from a function call. l is the
323 * number of bytes of arguments stored on the stack. isIndirect
324 * is true if this was an indirect call. (In which case the
325 * address of the function is stored at location SP + l.)
326 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700327 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700328
Jack Palevich1cdef202009-05-22 12:06:27 -0700329 /* Print a disassembly of the assembled code to out. Return
330 * non-zero if there is an error.
331 */
Jack Palevicha6535612009-05-13 16:24:17 -0700332 virtual int disassemble(FILE* out) = 0;
333
Jack Palevich1cdef202009-05-22 12:06:27 -0700334 /* Generate a symbol at the current PC. t is the head of a
335 * linked list of addresses to patch.
336 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700337 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700338
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 /*
340 * Do any cleanup work required at the end of a compile.
341 * For example, an instruction cache might need to be
342 * invalidated.
343 * Return non-zero if there is an error.
344 */
345 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700346
Jack Palevicha6535612009-05-13 16:24:17 -0700347 /**
348 * Adjust relative branches by this amount.
349 */
350 virtual int jumpOffset() = 0;
351
Jack Palevich21a15a22009-05-11 14:49:29 -0700352 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700353 /*
354 * Output a byte. Handles all values, 0..ff.
355 */
356 void ob(int n) {
357 pCodeBuf->ob(n);
358 }
359
Jack Palevich8b0624c2009-05-20 12:12:06 -0700360 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700361 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700362 }
363
Jack Palevich8b0624c2009-05-20 12:12:06 -0700364 intptr_t getBase() {
365 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700366 }
367
Jack Palevich8b0624c2009-05-20 12:12:06 -0700368 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700369 return pCodeBuf->getPC();
370 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700371
372 intptr_t getSize() {
373 return pCodeBuf->getSize();
374 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700375
376 void error(const char* fmt,...) {
377 va_list ap;
378 va_start(ap, fmt);
379 mErrorSink->verror(fmt, ap);
380 va_end(ap);
381 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700382 private:
383 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700384 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700385 };
386
Jack Paleviche7b59062009-05-19 17:12:17 -0700387#ifdef PROVIDE_ARM_CODEGEN
388
Jack Palevich22305132009-05-13 10:58:45 -0700389 class ARMCodeGenerator : public CodeGenerator {
390 public:
391 ARMCodeGenerator() {}
392 virtual ~ARMCodeGenerator() {}
393
394 /* returns address to patch with local variable size
395 */
Jack Palevich546b2242009-05-13 15:10:04 -0700396 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700397 LOG_API("functionEntry(%d);\n", argCount);
Jack Palevich69796b62009-05-14 15:42:26 -0700398 // sp -> arg4 arg5 ...
399 // Push our register-based arguments back on the stack
400 if (argCount > 0) {
401 int regArgCount = argCount <= 4 ? argCount : 4;
402 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
403 }
404 // sp -> arg0 arg1 ...
405 o4(0xE92D4800); // stmfd sp!, {fp, lr}
406 // sp, fp -> oldfp, retadr, arg0 arg1 ....
407 o4(0xE1A0B00D); // mov fp, sp
408 return o4(0xE24DD000); // sub sp, sp, # <local variables>
Jack Palevich22305132009-05-13 10:58:45 -0700409 }
410
Jack Palevich546b2242009-05-13 15:10:04 -0700411 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700412 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
Jack Palevich69796b62009-05-14 15:42:26 -0700413 // Patch local variable allocation code:
414 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700415 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700416 }
Jack Palevich69796b62009-05-14 15:42:26 -0700417 *(char*) (localVariableAddress) = localVariableSize;
418
419 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
420 o4(0xE1A0E00B); // mov lr, fp
421 o4(0xE59BB000); // ldr fp, [fp]
422 o4(0xE28ED004); // add sp, lr, #4
423 // sp -> retadr, arg0, ...
424 o4(0xE8BD4000); // ldmfd sp!, {lr}
425 // sp -> arg0 ....
426 if (argCount > 0) {
427 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700428 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700429 // earlier. We don't need to actually store them anywhere,
430 // just adjust the stack.
431 int regArgCount = argCount <= 4 ? argCount : 4;
432 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
433 }
434 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700435 }
436
437 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700438 virtual void li(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700439 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700440 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700441 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700442 } else if (t >= -256 && t < 0) {
443 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700444 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700445 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700446 o4(0xE51F0000); // ldr r0, .L3
447 o4(0xEA000000); // b .L99
448 o4(t); // .L3: .word 0
449 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700450 }
Jack Palevich22305132009-05-13 10:58:45 -0700451 }
452
453 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700454 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700455 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700456 }
457
458 /* l = 0: je, l == 1: jne */
459 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700460 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700461 o4(0xE3500000); // cmp r0,#0
462 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
463 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700464 }
465
466 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700467 LOG_API("gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700468 o4(0xE1510000); // cmp r1, r1
469 switch(op) {
470 case OP_EQUALS:
471 o4(0x03A00001); // moveq r0,#1
472 o4(0x13A00000); // movne r0,#0
473 break;
474 case OP_NOT_EQUALS:
475 o4(0x03A00000); // moveq r0,#0
476 o4(0x13A00001); // movne r0,#1
477 break;
478 case OP_LESS_EQUAL:
479 o4(0xD3A00001); // movle r0,#1
480 o4(0xC3A00000); // movgt r0,#0
481 break;
482 case OP_GREATER:
483 o4(0xD3A00000); // movle r0,#0
484 o4(0xC3A00001); // movgt r0,#1
485 break;
486 case OP_GREATER_EQUAL:
487 o4(0xA3A00001); // movge r0,#1
488 o4(0xB3A00000); // movlt r0,#0
489 break;
490 case OP_LESS:
491 o4(0xA3A00000); // movge r0,#0
492 o4(0xB3A00001); // movlt r0,#1
493 break;
494 default:
495 error("Unknown comparison op %d", op);
496 break;
497 }
Jack Palevich22305132009-05-13 10:58:45 -0700498 }
499
Jack Palevich546b2242009-05-13 15:10:04 -0700500 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700501 LOG_API("genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700502 switch(op) {
503 case OP_MUL:
504 o4(0x0E0000091); // mul r0,r1,r0
505 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700506 case OP_DIV:
507 callRuntime(runtime_DIV);
508 break;
509 case OP_MOD:
510 callRuntime(runtime_MOD);
511 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700512 case OP_PLUS:
513 o4(0xE0810000); // add r0,r1,r0
514 break;
515 case OP_MINUS:
516 o4(0xE0410000); // sub r0,r1,r0
517 break;
518 case OP_SHIFT_LEFT:
519 o4(0xE1A00011); // lsl r0,r1,r0
520 break;
521 case OP_SHIFT_RIGHT:
522 o4(0xE1A00051); // asr r0,r1,r0
523 break;
524 case OP_BIT_AND:
525 o4(0xE0010000); // and r0,r1,r0
526 break;
527 case OP_BIT_XOR:
528 o4(0xE0210000); // eor r0,r1,r0
529 break;
530 case OP_BIT_OR:
531 o4(0xE1810000); // orr r0,r1,r0
532 break;
533 case OP_BIT_NOT:
534 o4(0xE1E00000); // mvn r0, r0
535 break;
536 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700537 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700538 break;
539 }
Jack Palevich22305132009-05-13 10:58:45 -0700540#if 0
541 o(decodeOp(op));
542 if (op == OP_MOD)
543 o(0x92); /* xchg %edx, %eax */
544#endif
545 }
546
Jack Palevich1cdef202009-05-22 12:06:27 -0700547 virtual void clearR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700548 LOG_API("clearR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700549 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700550 }
551
Jack Palevich1cdef202009-05-22 12:06:27 -0700552 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700553 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700554 o4(0xE92D0001); // stmfd sp!,{r0}
Jack Palevich22305132009-05-13 10:58:45 -0700555 }
556
Jack Palevich1cdef202009-05-22 12:06:27 -0700557 virtual void popR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700558 LOG_API("popR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700559 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich22305132009-05-13 10:58:45 -0700560 }
561
Jack Palevich1cdef202009-05-22 12:06:27 -0700562 virtual void storeR0ToR1(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700563 LOG_API("storeR0ToR1(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700564 if (isInt) {
565 o4(0xE5810000); // str r0, [r1]
566 } else {
567 o4(0xE5C10000); // strb r0, [r1]
568 }
Jack Palevich22305132009-05-13 10:58:45 -0700569 }
570
Jack Palevich1cdef202009-05-22 12:06:27 -0700571 virtual void loadR0FromR0(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700572 LOG_API("loadR0FromR0(%d);\n", isInt);
Jack Palevich22305132009-05-13 10:58:45 -0700573 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700574 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700575 else
Jack Palevich69796b62009-05-14 15:42:26 -0700576 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700577 }
578
Jack Palevich1cdef202009-05-22 12:06:27 -0700579 virtual void leaR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700580 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700581 if (ea < LOCAL) {
582 // Local, fp relative
583 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
584 error("Offset out of range: %08x", ea);
585 }
586 if (ea < 0) {
587 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
588 } else {
589 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
590 }
Jack Palevichbd894902009-05-14 19:35:31 -0700591 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700592 // Global, absolute.
593 o4(0xE59F0000); // ldr r0, .L1
594 o4(0xEA000000); // b .L99
595 o4(ea); // .L1: .word 0
596 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700597 }
Jack Palevich22305132009-05-13 10:58:45 -0700598 }
599
Jack Palevich1cdef202009-05-22 12:06:27 -0700600 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700601 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700602 if (ea < LOCAL) {
603 // Local, fp relative
604 if (ea < -4095 || ea > 4095) {
605 error("Offset out of range: %08x", ea);
606 }
607 if (ea < 0) {
608 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
609 } else {
610 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
611 }
612 } else{
613 // Global, absolute
614 o4(0xE59F1000); // ldr r1, .L1
615 o4(0xEA000000); // b .L99
616 o4(ea); // .L1: .word 0
617 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700618 }
Jack Palevich22305132009-05-13 10:58:45 -0700619 }
620
Jack Palevich1cdef202009-05-22 12:06:27 -0700621 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700622 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700623 if (ea < LOCAL) {
624 // Local, fp relative
625 if (ea < -4095 || ea > 4095) {
626 error("Offset out of range: %08x", ea);
627 }
628 if (ea < 0) {
629 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
630 } else {
631 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
632 }
Jack Palevich69796b62009-05-14 15:42:26 -0700633 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700634 // Global, absolute
635 o4(0xE59F2000); // ldr r2, .L1
636 o4(0xEA000000); // b .L99
637 o4(ea); // .L1: .word ea
638 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700639 }
Jack Palevich22305132009-05-13 10:58:45 -0700640
Jack Palevich4d93f302009-05-15 13:30:00 -0700641 if (isIncDec) {
642 switch (op) {
643 case OP_INCREMENT:
644 o4(0xE2801001); // add r1, r0, #1
645 break;
646 case OP_DECREMENT:
647 o4(0xE2401001); // sub r1, r0, #1
648 break;
649 default:
650 error("unknown opcode: %d", op);
651 }
652 if (ea < LOCAL) {
653 // Local, fp relative
654 // Don't need range check, was already checked above
655 if (ea < 0) {
656 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
657 } else {
658 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
659 }
660 } else{
661 // Global, absolute
662 // r2 is already set up from before.
663 o4(0xE5821000); // str r1, [r2]
664 }
Jack Palevichbd894902009-05-14 19:35:31 -0700665 }
Jack Palevich22305132009-05-13 10:58:45 -0700666 }
667
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700668 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700669 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700670 return o4(0xE24DDF00); // Placeholder
671 }
672
Jack Palevich1cdef202009-05-22 12:06:27 -0700673 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700674 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700675 if (l < 0 || l > 4096-4) {
676 error("l out of range for stack offset: 0x%08x", l);
677 }
678 o4(0xE58D0000 + l); // str r0, [sp, #4]
679 }
680
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700681 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700682 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700683 if (l < 0 || l > 0x3FC) {
684 error("L out of range for stack adjustment: 0x%08x", l);
685 }
686 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
687 int argCount = l >> 2;
688 if (argCount > 0) {
689 int regArgCount = argCount > 4 ? 4 : argCount;
690 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
691 }
Jack Palevich22305132009-05-13 10:58:45 -0700692 }
693
Jack Palevich22305132009-05-13 10:58:45 -0700694 virtual int callForward(int symbol) {
Jack Palevich09555c72009-05-27 12:25:55 -0700695 LOG_API("callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700696 // Forward calls are always short (local)
697 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700698 }
699
700 virtual void callRelative(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700701 LOG_API("callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700702 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700703 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700704 if (t >= - (1 << 25) && t < (1 << 25)) {
705 o4(0xEB000000 | encodeAddress(t));
706 } else {
707 // Long call.
708 o4(0xE59FC000); // ldr r12, .L1
709 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700710 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700711 o4(0xE08CC00F); // .L99: add r12,pc
712 o4(0xE12FFF3C); // blx r12
713 }
Jack Palevich22305132009-05-13 10:58:45 -0700714 }
715
716 virtual void callIndirect(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700717 LOG_API("callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700718 int argCount = l >> 2;
719 int poppedArgs = argCount > 4 ? 4 : argCount;
720 int adjustedL = l - (poppedArgs << 2);
721 if (adjustedL < 0 || adjustedL > 4096-4) {
722 error("l out of range for stack offset: 0x%08x", l);
723 }
724 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
725 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700726 }
727
Jack Palevich7810bc92009-05-15 14:31:47 -0700728 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700729 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700730 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700731 int stackArgs = argCount > 4 ? argCount - 4 : 0;
732 int stackUse = stackArgs + (isIndirect ? 1 : 0);
733 if (stackUse) {
734 if (stackUse < 0 || stackUse > 255) {
735 error("L out of range for stack adjustment: 0x%08x", l);
736 }
737 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700738 }
Jack Palevich22305132009-05-13 10:58:45 -0700739 }
740
Jack Palevicha6535612009-05-13 16:24:17 -0700741 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700742 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700743 }
744
745 /* output a symbol and patch all calls to it */
746 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700747 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700748 int n;
749 int base = getBase();
750 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -0700751 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -0700752 while (t) {
753 int data = * (int*) t;
754 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
755 if (decodedOffset == 0) {
756 n = 0;
757 } else {
758 n = base + decodedOffset; /* next value */
759 }
760 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
761 | encodeRelAddress(pc - t - 8);
762 t = n;
763 }
764 }
765
Jack Palevich1cdef202009-05-22 12:06:27 -0700766 virtual int finishCompile() {
767#if defined(__arm__)
768 const long base = long(getBase());
769 const long curr = long(getPC());
770 int err = cacheflush(base, curr, 0);
771 return err;
772#else
773 return 0;
774#endif
775 }
776
Jack Palevicha6535612009-05-13 16:24:17 -0700777 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -0700778#ifdef ENABLE_ARM_DISASSEMBLY
779 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -0700780 disasm_interface_t di;
781 di.di_readword = disassemble_readword;
782 di.di_printaddr = disassemble_printaddr;
783 di.di_printf = disassemble_printf;
784
785 int base = getBase();
786 int pc = getPC();
787 for(int i = base; i < pc; i += 4) {
788 fprintf(out, "%08x: %08x ", i, *(int*) i);
789 ::disasm(&di, i, 0);
790 }
Jack Palevich09555c72009-05-27 12:25:55 -0700791#endif
Jack Palevicha6535612009-05-13 16:24:17 -0700792 return 0;
793 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700794
Jack Palevich22305132009-05-13 10:58:45 -0700795 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700796 static FILE* disasmOut;
797
798 static u_int
799 disassemble_readword(u_int address)
800 {
801 return(*((u_int *)address));
802 }
803
804 static void
805 disassemble_printaddr(u_int address)
806 {
807 fprintf(disasmOut, "0x%08x", address);
808 }
809
810 static void
811 disassemble_printf(const char *fmt, ...) {
812 va_list ap;
813 va_start(ap, fmt);
814 vfprintf(disasmOut, fmt, ap);
815 va_end(ap);
816 }
817
818 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
819
820 /** Encode a relative address that might also be
821 * a label.
822 */
823 int encodeAddress(int value) {
824 int base = getBase();
825 if (value >= base && value <= getPC() ) {
826 // This is a label, encode it relative to the base.
827 value = value - base;
828 }
829 return encodeRelAddress(value);
830 }
831
832 int encodeRelAddress(int value) {
833 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
834 }
Jack Palevich22305132009-05-13 10:58:45 -0700835
Jack Palevich3d474a72009-05-15 15:12:38 -0700836 typedef int (*int2FnPtr)(int a, int b);
837 void callRuntime(int2FnPtr fn) {
838 o4(0xE59F2000); // ldr r2, .L1
839 o4(0xEA000000); // b .L99
840 o4((int) fn); //.L1: .word fn
841 o4(0xE12FFF32); //.L99: blx r2
842 }
843
844 static int runtime_DIV(int a, int b) {
845 return b / a;
846 }
847
848 static int runtime_MOD(int a, int b) {
849 return b % a;
850 }
Jack Palevich22305132009-05-13 10:58:45 -0700851 };
852
Jack Palevich09555c72009-05-27 12:25:55 -0700853#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -0700854
855#ifdef PROVIDE_X86_CODEGEN
856
Jack Palevich21a15a22009-05-11 14:49:29 -0700857 class X86CodeGenerator : public CodeGenerator {
858 public:
859 X86CodeGenerator() {}
860 virtual ~X86CodeGenerator() {}
861
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700862 /* returns address to patch with local variable size
863 */
Jack Palevich546b2242009-05-13 15:10:04 -0700864 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700865 o(0xe58955); /* push %ebp, mov %esp, %ebp */
866 return oad(0xec81, 0); /* sub $xxx, %esp */
867 }
868
Jack Palevich546b2242009-05-13 15:10:04 -0700869 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700870 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700871 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700872 }
873
Jack Palevich21a15a22009-05-11 14:49:29 -0700874 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700875 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700876 oad(0xb8, t); /* mov $xx, %eax */
877 }
878
Jack Palevich22305132009-05-13 10:58:45 -0700879 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700880 return psym(0xe9, t);
881 }
882
883 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700884 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700885 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
886 return psym(0x84 + l, t);
887 }
888
Jack Palevich22305132009-05-13 10:58:45 -0700889 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700890 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700891 o(0xc139); /* cmp %eax,%ecx */
892 li(0);
893 o(0x0f); /* setxx %al */
894 o(t + 0x90);
895 o(0xc0);
896 }
897
Jack Palevich546b2242009-05-13 15:10:04 -0700898 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700899 o(decodeOp(op));
900 if (op == OP_MOD)
901 o(0x92); /* xchg %edx, %eax */
902 }
903
Jack Palevich1cdef202009-05-22 12:06:27 -0700904 virtual void clearR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700905 oad(0xb9, 0); /* movl $0, %ecx */
906 }
907
Jack Palevich1cdef202009-05-22 12:06:27 -0700908 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700909 o(0x50); /* push %eax */
910 }
911
Jack Palevich1cdef202009-05-22 12:06:27 -0700912 virtual void popR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700913 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700914 }
915
Jack Palevich1cdef202009-05-22 12:06:27 -0700916 virtual void storeR0ToR1(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700917 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
918 }
919
Jack Palevich1cdef202009-05-22 12:06:27 -0700920 virtual void loadR0FromR0(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700921 if (isInt)
922 o(0x8b); /* mov (%eax), %eax */
923 else
924 o(0xbe0f); /* movsbl (%eax), %eax */
925 ob(0); /* add zero in code */
926 }
927
Jack Palevich1cdef202009-05-22 12:06:27 -0700928 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700929 gmov(10, ea); /* leal EA, %eax */
930 }
931
Jack Palevich1cdef202009-05-22 12:06:27 -0700932 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700933 gmov(6, ea); /* mov %eax, EA */
934 }
935
Jack Palevich1cdef202009-05-22 12:06:27 -0700936 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700937 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700938 if (isIncDec) {
939 /* Implement post-increment or post decrement.
940 */
941 gmov(0, ea); /* 83 ADD */
942 o(decodeOp(op));
943 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700944 }
945
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700946 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700947 return oad(0xec81, 0); /* sub $xxx, %esp */
948 }
949
Jack Palevich1cdef202009-05-22 12:06:27 -0700950 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700951 oad(0x248489, l); /* movl %eax, xxx(%esp) */
952 }
953
Jack Palevich7810bc92009-05-15 14:31:47 -0700954 virtual void endFunctionCallArguments(int a, int l) {
955 * (int*) a = l;
956 }
957
Jack Palevich22305132009-05-13 10:58:45 -0700958 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700959 return psym(0xe8, symbol); /* call xxx */
960 }
961
Jack Palevich22305132009-05-13 10:58:45 -0700962 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700963 psym(0xe8, t); /* call xxx */
964 }
965
Jack Palevich22305132009-05-13 10:58:45 -0700966 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700967 oad(0x2494ff, l); /* call *xxx(%esp) */
968 }
969
Jack Palevich7810bc92009-05-15 14:31:47 -0700970 virtual void adjustStackAfterCall(int l, bool isIndirect) {
971 if (isIndirect) {
972 l += 4;
973 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700974 oad(0xc481, l); /* add $xxx, %esp */
975 }
976
Jack Palevicha6535612009-05-13 16:24:17 -0700977 virtual int jumpOffset() {
978 return 5;
979 }
980
981 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -0700982 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -0700983 }
984
Jack Paleviche7b59062009-05-19 17:12:17 -0700985 /* output a symbol and patch all calls to it */
986 virtual void gsym(int t) {
987 int n;
988 int pc = getPC();
989 while (t) {
990 n = *(int *) t; /* next value */
991 *(int *) t = pc - t - 4;
992 t = n;
993 }
994 }
995
Jack Palevich1cdef202009-05-22 12:06:27 -0700996 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +0000997 size_t pagesize = 4096;
998 size_t base = (size_t) getBase() & ~ (pagesize - 1);
999 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1000 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1001 if (err) {
1002 error("mprotect() failed: %d", errno);
1003 }
1004 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001005 }
1006
Jack Palevich21a15a22009-05-11 14:49:29 -07001007 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001008
1009 /** Output 1 to 4 bytes.
1010 *
1011 */
1012 void o(int n) {
1013 /* cannot use unsigned, so we must do a hack */
1014 while (n && n != -1) {
1015 ob(n & 0xff);
1016 n = n >> 8;
1017 }
1018 }
1019
1020 /* psym is used to put an instruction with a data field which is a
1021 reference to a symbol. It is in fact the same as oad ! */
1022 int psym(int n, int t) {
1023 return oad(n, t);
1024 }
1025
1026 /* instruction + address */
1027 int oad(int n, int t) {
1028 o(n);
1029 int result = getPC();
1030 o4(t);
1031 return result;
1032 }
1033
1034
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001035 static const int operatorHelper[];
1036
1037 int decodeOp(int op) {
1038 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001039 error("Out-of-range operator: %d\n", op);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001040 }
1041 return operatorHelper[op];
1042 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001043
Jack Palevich546b2242009-05-13 15:10:04 -07001044 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001045 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001046 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001047 }
1048 };
1049
Jack Paleviche7b59062009-05-19 17:12:17 -07001050#endif // PROVIDE_X86_CODEGEN
1051
Jack Palevich1cdef202009-05-22 12:06:27 -07001052 class InputStream {
1053 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001054 int getChar() {
1055 if (bumpLine) {
1056 line++;
1057 bumpLine = false;
1058 }
1059 int ch = get();
1060 if (ch == '\n') {
1061 bumpLine = true;
1062 }
1063 return ch;
1064 }
1065 int getLine() {
1066 return line;
1067 }
1068 protected:
1069 InputStream() :
1070 line(1), bumpLine(false) {
1071 }
1072 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001073 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001074 int line;
1075 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001076 };
1077
1078 class FileInputStream : public InputStream {
1079 public:
1080 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001081 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001082 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001083 FILE* f;
1084 };
1085
1086 class TextInputStream : public InputStream {
1087 public:
1088 TextInputStream(const char* text, size_t textLength)
1089 : pText(text), mTextLength(textLength), mPosition(0) {
1090 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001091
1092 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001093 virtual int get() {
1094 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1095 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001096
Jack Palevich1cdef202009-05-22 12:06:27 -07001097 const char* pText;
1098 size_t mTextLength;
1099 size_t mPosition;
1100 };
1101
Jack Palevicheedf9d22009-06-04 16:23:40 -07001102 class String {
1103 public:
1104 String() {
1105 mpBase = 0;
1106 mUsed = 0;
1107 mSize = 0;
1108 }
1109
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001110 String(char* item, int len, bool adopt) {
1111 if (adopt) {
1112 mpBase = item;
1113 mUsed = len;
1114 mSize = len + 1;
1115 } else {
1116 mpBase = 0;
1117 mUsed = 0;
1118 mSize = 0;
1119 appendBytes(item, len);
1120 }
1121 }
1122
Jack Palevicheedf9d22009-06-04 16:23:40 -07001123 ~String() {
1124 if (mpBase) {
1125 free(mpBase);
1126 }
1127 }
1128
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001129 inline char* getUnwrapped() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001130 return mpBase;
1131 }
1132
1133 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001134 appendBytes(s, strlen(s));
1135 }
1136
1137 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001138 memcpy(ensure(n), s, n + 1);
1139 }
1140
1141 void append(char c) {
1142 * ensure(1) = c;
1143 }
1144
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001145 char* orphan() {
1146 char* result = mpBase;
1147 mpBase = 0;
1148 mUsed = 0;
1149 mSize = 0;
1150 return result;
1151 }
1152
Jack Palevicheedf9d22009-06-04 16:23:40 -07001153 void printf(const char* fmt,...) {
1154 va_list ap;
1155 va_start(ap, fmt);
1156 vprintf(fmt, ap);
1157 va_end(ap);
1158 }
1159
1160 void vprintf(const char* fmt, va_list ap) {
1161 char* temp;
1162 int numChars = vasprintf(&temp, fmt, ap);
1163 memcpy(ensure(numChars), temp, numChars+1);
1164 free(temp);
1165 }
1166
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001167 inline size_t len() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001168 return mUsed;
1169 }
1170
1171 private:
1172 char* ensure(int n) {
1173 size_t newUsed = mUsed + n;
1174 if (newUsed > mSize) {
1175 size_t newSize = mSize * 2 + 10;
1176 if (newSize < newUsed) {
1177 newSize = newUsed;
1178 }
1179 mpBase = (char*) realloc(mpBase, newSize + 1);
1180 mSize = newSize;
1181 }
1182 mpBase[newUsed] = '\0';
1183 char* result = mpBase + mUsed;
1184 mUsed = newUsed;
1185 return result;
1186 }
1187
1188 char* mpBase;
1189 size_t mUsed;
1190 size_t mSize;
1191 };
1192
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001193 /**
1194 * Wrap an externally allocated string for use as a hash key.
1195 */
1196 class FakeString : public String {
1197 public:
1198 FakeString(char* string, size_t length) :
1199 String(string, length, true) {}
1200
1201 ~FakeString() {
1202 orphan();
1203 }
1204 };
1205
1206 template<class V> class StringTable {
1207 public:
1208 StringTable(size_t initialCapacity) {
1209 mpMap = hashmapCreate(initialCapacity, hashFn, equalsFn);
1210 }
1211
1212 ~StringTable() {
1213 clear();
1214 }
1215
1216 void clear() {
1217 hashmapForEach(mpMap, freeKeyValue, this);
1218 }
1219
1220 bool contains(String* pKey) {
1221 bool result = hashmapContainsKey(mpMap, pKey);
1222 return result;
1223 }
1224
1225 V* get(String* pKey) {
1226 V* result = (V*) hashmapGet(mpMap, pKey);
1227 return result;
1228 }
1229
1230 V* remove(String* pKey) {
1231 V* result = (V*) hashmapRemove(mpMap, pKey);
1232 return result;
1233 }
1234
1235 V* put(String* pKey, V* value) {
1236 V* result = (V*) hashmapPut(mpMap, pKey, value);
1237 if (result) {
1238 // The key was not adopted by the map, so delete it here.
1239 delete pKey;
1240 }
1241 return result;
1242 }
1243
1244 protected:
1245 static int hashFn(void* pKey) {
1246 String* pString = (String*) pKey;
1247 return hashmapHash(pString->getUnwrapped(), pString->len());
1248 }
1249
1250 static bool equalsFn(void* keyA, void* keyB) {
1251 String* pStringA = (String*) keyA;
1252 String* pStringB = (String*) keyB;
1253 return pStringA->len() == pStringB->len()
1254 && strcmp(pStringA->getUnwrapped(), pStringB->getUnwrapped())
1255 == 0;
1256 }
1257
1258 static bool freeKeyValue(void* key, void* value, void* context) {
1259 delete (String*) key;
1260 delete (V*) value;
1261 return true;
1262 }
1263
1264 Hashmap* mpMap;
1265 };
1266
1267 class MacroTable : public StringTable<String> {
1268 public:
1269 MacroTable() : StringTable<String>(10) {}
1270 };
1271
1272 template<class E> class Array {
1273 public:
1274 Array() {
1275 mpBase = 0;
1276 mUsed = 0;
1277 mSize = 0;
1278 }
1279
1280 ~Array() {
1281 if (mpBase) {
1282 free(mpBase);
1283 }
1284 }
1285
1286 E get(int i) {
1287 if (i < 0 || i > mUsed) {
1288 error("internal error: Index out of range");
1289 return E();
1290 }
1291 return mpBase[i];
1292 }
1293
1294 void set(int i, E val) {
1295 mpBase[i] = val;
1296 }
1297
1298 void pop() {
1299 if (mUsed > 0) {
1300 mUsed -= 1;
Jack Palevich36d94142009-06-08 15:55:32 -07001301 } else {
1302 error("internal error: Popped empty stack.");
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001303 }
1304 }
1305
1306 void push(E item) {
1307 * ensure(1) = item;
1308 }
1309
1310 size_t len() {
1311 return mUsed;
1312 }
1313
1314 private:
1315 E* ensure(int n) {
1316 size_t newUsed = mUsed + n;
1317 if (newUsed > mSize) {
1318 size_t newSize = mSize * 2 + 10;
1319 if (newSize < newUsed) {
1320 newSize = newUsed;
1321 }
1322 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
1323 mSize = newSize;
1324 }
1325 E* result = mpBase + mUsed;
1326 mUsed = newUsed;
1327 return result;
1328 }
1329
1330 E* mpBase;
1331 size_t mUsed;
1332 size_t mSize;
1333 };
1334
Jack Palevich36d94142009-06-08 15:55:32 -07001335 struct InputState {
1336 InputStream* pStream;
1337 int oldCh;
1338 };
1339
1340
1341 int ch; // Current input character, or EOF
1342 intptr_t tok; // token
1343 intptr_t tokc; // token extra info
1344 int tokl; // token operator level
1345 intptr_t rsym; // return symbol
1346 intptr_t loc; // local variable index
1347 char* glo; // global variable index
1348 char* sym_stk;
1349 char* dstk; // Define stack
1350 char* dptr; // Macro state: Points to macro text during macro playback.
1351 int dch; // Macro state: Saves old value of ch during a macro playback.
1352 char* last_id;
1353 char* pGlobalBase;
1354 char* pVarsBase; // Value of variables
1355
1356 InputStream* file;
1357
1358 CodeBuf codeBuf;
1359 CodeGenerator* pGen;
1360
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001361 MacroTable mMacros;
Jack Palevich36d94142009-06-08 15:55:32 -07001362 Array<InputState> mInputStateStack;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001363
Jack Palevicheedf9d22009-06-04 16:23:40 -07001364 String mErrorBuf;
1365
Jack Palevichac0e95e2009-05-29 13:53:44 -07001366 jmp_buf mErrorRecoveryJumpBuf;
1367
Jack Palevicheedf9d22009-06-04 16:23:40 -07001368 String mPragmas;
1369 int mPragmaStringCount;
1370
Jack Palevich21a15a22009-05-11 14:49:29 -07001371 static const int ALLOC_SIZE = 99999;
1372
Jack Palevicheedf9d22009-06-04 16:23:40 -07001373 // Indentifiers start at 0x100 and increase by # (chars + 1) * 8
Jack Palevich21a15a22009-05-11 14:49:29 -07001374 static const int TOK_IDENT = 0x100;
1375 static const int TOK_INT = 0x100;
Jack Palevichb7c81e92009-06-04 19:56:13 -07001376 static const int TOK_CHAR = TOK_INT + 4*8;
1377 static const int TOK_VOID = TOK_CHAR + 5*8;
1378 static const int TOK_IF = TOK_VOID + 5*8;
1379 static const int TOK_ELSE = TOK_IF + 3*8;
1380 static const int TOK_WHILE = TOK_ELSE + 5*8;
1381 static const int TOK_BREAK = TOK_WHILE + 6*8;
1382 static const int TOK_RETURN = TOK_BREAK + 6*8;
1383 static const int TOK_FOR = TOK_RETURN + 7*8;
1384 static const int TOK_PRAGMA = TOK_FOR + 4*8;
1385 static const int TOK_DEFINE = TOK_PRAGMA + 7*8;
1386 static const int TOK_MAIN = TOK_DEFINE + 7*8;
Jack Palevich21a15a22009-05-11 14:49:29 -07001387
1388 static const int TOK_DUMMY = 1;
1389 static const int TOK_NUM = 2;
1390
1391 static const int LOCAL = 0x200;
1392
1393 static const int SYM_FORWARD = 0;
1394 static const int SYM_DEFINE = 1;
1395
1396 /* tokens in string heap */
1397 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07001398
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001399 static const int OP_INCREMENT = 0;
1400 static const int OP_DECREMENT = 1;
1401 static const int OP_MUL = 2;
1402 static const int OP_DIV = 3;
1403 static const int OP_MOD = 4;
1404 static const int OP_PLUS = 5;
1405 static const int OP_MINUS = 6;
1406 static const int OP_SHIFT_LEFT = 7;
1407 static const int OP_SHIFT_RIGHT = 8;
1408 static const int OP_LESS_EQUAL = 9;
1409 static const int OP_GREATER_EQUAL = 10;
1410 static const int OP_LESS = 11;
1411 static const int OP_GREATER = 12;
1412 static const int OP_EQUALS = 13;
1413 static const int OP_NOT_EQUALS = 14;
1414 static const int OP_LOGICAL_AND = 15;
1415 static const int OP_LOGICAL_OR = 16;
1416 static const int OP_BIT_AND = 17;
1417 static const int OP_BIT_XOR = 18;
1418 static const int OP_BIT_OR = 19;
1419 static const int OP_BIT_NOT = 20;
1420 static const int OP_LOGICAL_NOT = 21;
1421 static const int OP_COUNT = 22;
1422
1423 /* Operators are searched from front, the two-character operators appear
1424 * before the single-character operators with the same first character.
1425 * @ is used to pad out single-character operators.
1426 */
1427 static const char* operatorChars;
1428 static const char operatorLevel[];
1429
Jack Palevich21a15a22009-05-11 14:49:29 -07001430 void pdef(int t) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001431 if (dstk - sym_stk >= ALLOC_SIZE) {
1432 error("Symbol table exhausted");
1433 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001434 *dstk++ = t;
Jack Palevich21a15a22009-05-11 14:49:29 -07001435 }
1436
1437 void inp() {
1438 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001439 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001440 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001441 dptr = 0;
1442 ch = dch;
1443 }
1444 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07001445 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001446#if 0
1447 printf("ch='%c' 0x%x\n", ch, ch);
1448#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07001449 }
1450
1451 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07001452 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07001453 }
1454
1455 /* read a character constant */
1456 void getq() {
1457 if (ch == '\\') {
1458 inp();
1459 if (ch == 'n')
1460 ch = '\n';
1461 }
1462 }
1463
1464 void next() {
1465 int l, a;
1466
Jack Palevich546b2242009-05-13 15:10:04 -07001467 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001468 if (ch == '#') {
1469 inp();
1470 next();
1471 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001472 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07001473 } else if (tok == TOK_PRAGMA) {
1474 doPragma();
1475 } else {
1476 error("Unsupported preprocessor directive \"%s\"", last_id);
Jack Palevich21a15a22009-05-11 14:49:29 -07001477 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001478
Jack Palevich21a15a22009-05-11 14:49:29 -07001479 }
1480 inp();
1481 }
1482 tokl = 0;
1483 tok = ch;
1484 /* encode identifiers & numbers */
1485 if (isid()) {
1486 pdef(TAG_TOK);
1487 last_id = dstk;
1488 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001489 pdef(ch);
1490 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07001491 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001492 if (isdigit(tok)) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001493 tokc = strtol(last_id, 0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001494 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001495 } else {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001496 if (dstk - sym_stk + 1 > ALLOC_SIZE) {
1497 error("symbol stack overflow");
1498 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001499 FakeString token(last_id, dstk-last_id);
1500 // Is this a macro?
1501 String* pValue = mMacros.get(&token);
1502 if (pValue) {
1503 // Yes, it is a macro
1504 dstk = last_id-1;
1505 dptr = pValue->getUnwrapped();
1506 dch = ch;
1507 inp();
1508 next();
1509 } else {
1510 * dstk = TAG_TOK; /* no need to mark end of string (we
1511 suppose data is initialized to zero by calloc) */
1512 tok = (intptr_t) (strstr(sym_stk, (last_id - 1))
1513 - sym_stk);
1514 * dstk = 0; /* mark real end of ident for dlsym() */
1515 tok = tok * 8 + TOK_IDENT;
1516 if (tok > TOK_DEFINE) {
1517 if (tok + 8 > ALLOC_SIZE) {
1518 error("Variable Table overflow.");
1519 }
1520 tok = (intptr_t) (pVarsBase + tok);
1521 /* printf("tok=%s %x\n", last_id, tok); */
Jack Palevich21a15a22009-05-11 14:49:29 -07001522 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001523 }
1524 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001525 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001526 inp();
1527 if (tok == '\'') {
1528 tok = TOK_NUM;
1529 getq();
1530 tokc = ch;
1531 inp();
1532 inp();
Jack Palevich546b2242009-05-13 15:10:04 -07001533 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001534 inp();
1535 while (ch) {
1536 while (ch != '*')
1537 inp();
1538 inp();
1539 if (ch == '/')
1540 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001541 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001542 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001543 next();
Jack Palevichbd894902009-05-14 19:35:31 -07001544 } else if ((tok == '/') & (ch == '/')) {
1545 inp();
1546 while (ch && (ch != '\n')) {
1547 inp();
1548 }
1549 inp();
1550 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001551 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001552 const char* t = operatorChars;
1553 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001554 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001555 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001556 tokl = operatorLevel[opIndex];
1557 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07001558 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001559#if 0
1560 printf("%c%c -> tokl=%d tokc=0x%x\n",
1561 l, a, tokl, tokc);
1562#endif
1563 if (a == ch) {
1564 inp();
1565 tok = TOK_DUMMY; /* dummy token for double tokens */
1566 }
1567 break;
1568 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001569 opIndex++;
1570 }
1571 if (l == 0) {
1572 tokl = 0;
1573 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001574 }
1575 }
1576 }
1577#if 0
1578 {
Jack Palevich653f42d2009-05-28 17:15:32 -07001579 char* p;
Jack Palevich21a15a22009-05-11 14:49:29 -07001580
1581 printf("tok=0x%x ", tok);
1582 if (tok >= TOK_IDENT) {
1583 printf("'");
1584 if (tok> TOK_DEFINE)
Jack Palevich653f42d2009-05-28 17:15:32 -07001585 p = sym_stk + 1 + ((char*) tok - pVarsBase - TOK_IDENT) / 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07001586 else
1587 p = sym_stk + 1 + (tok - TOK_IDENT) / 8;
Jack Palevich653f42d2009-05-28 17:15:32 -07001588 while (*p != TAG_TOK && *p)
1589 printf("%c", *p++);
Jack Palevich21a15a22009-05-11 14:49:29 -07001590 printf("'\n");
1591 } else if (tok == TOK_NUM) {
1592 printf("%d\n", tokc);
1593 } else {
1594 printf("'%c'\n", tok);
1595 }
1596 }
1597#endif
1598 }
1599
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001600 void doDefine() {
1601 String* pName = new String();
1602 while (isspace(ch)) {
1603 inp();
1604 }
1605 while (isid()) {
1606 pName->append(ch);
1607 inp();
1608 }
1609 if (ch == '(') {
1610 delete pName;
1611 error("Defines with arguments not supported");
1612 }
1613 while (isspace(ch)) {
1614 inp();
1615 }
1616 String* pValue = new String();
1617 while (ch != '\n' && ch != EOF) {
1618 pValue->append(ch);
1619 inp();
1620 }
1621 delete mMacros.put(pName, pValue);
1622 }
1623
Jack Palevicheedf9d22009-06-04 16:23:40 -07001624 void doPragma() {
1625 // # pragma name(val)
1626 int state = 0;
1627 while(ch != EOF && ch != '\n' && state < 10) {
1628 switch(state) {
1629 case 0:
1630 if (isspace(ch)) {
1631 inp();
1632 } else {
1633 state++;
1634 }
1635 break;
1636 case 1:
1637 if (isalnum(ch)) {
1638 mPragmas.append(ch);
1639 inp();
1640 } else if (ch == '(') {
1641 mPragmas.append(0);
1642 inp();
1643 state++;
1644 } else {
1645 state = 11;
1646 }
1647 break;
1648 case 2:
1649 if (isalnum(ch)) {
1650 mPragmas.append(ch);
1651 inp();
1652 } else if (ch == ')') {
1653 mPragmas.append(0);
1654 inp();
1655 state = 10;
1656 } else {
1657 state = 11;
1658 }
1659 break;
1660 }
1661 }
1662 if(state != 10) {
1663 error("Unexpected pragma syntax");
1664 }
1665 mPragmaStringCount += 2;
1666 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001667
Jack Palevichac0e95e2009-05-29 13:53:44 -07001668 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001669 mErrorBuf.printf("%ld: ", file->getLine());
1670 mErrorBuf.vprintf(fmt, ap);
1671 mErrorBuf.printf("\n");
Jack Palevichac0e95e2009-05-29 13:53:44 -07001672 longjmp(mErrorRecoveryJumpBuf, 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07001673 }
1674
Jack Palevich8b0624c2009-05-20 12:12:06 -07001675 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001676 if (tok != c) {
1677 error("'%c' expected", c);
1678 }
1679 next();
1680 }
1681
Jack Palevich21a15a22009-05-11 14:49:29 -07001682 /* l is one if '=' parsing wanted (quick hack) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001683 void unary(intptr_t l) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001684 intptr_t n, t, a;
1685 int c;
Jack Palevich546b2242009-05-13 15:10:04 -07001686 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001687 n = 1; /* type of expression 0 = forward, 1 = value, other =
1688 lvalue */
1689 if (tok == '\"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07001690 pGen->li((int) glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001691 while (ch != '\"') {
1692 getq();
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001693 *allocGlobalSpace(1) = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07001694 inp();
1695 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001696 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001697 /* align heap */
1698 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001699 inp();
1700 next();
1701 } else {
1702 c = tokl;
1703 a = tokc;
1704 t = tok;
1705 next();
1706 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001707 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001708 } else if (c == 2) {
1709 /* -, +, !, ~ */
1710 unary(0);
Jack Palevich1cdef202009-05-22 12:06:27 -07001711 pGen->clearR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07001712 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001713 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001714 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001715 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001716 } else if (t == '(') {
1717 expr();
1718 skip(')');
1719 } else if (t == '*') {
1720 /* parse cast */
1721 skip('(');
1722 t = tok; /* get type */
1723 next(); /* skip int/char/void */
1724 next(); /* skip '*' or '(' */
1725 if (tok == '*') {
1726 /* function type */
1727 skip('*');
1728 skip(')');
1729 skip('(');
1730 skip(')');
1731 t = 0;
1732 }
1733 skip(')');
1734 unary(0);
1735 if (tok == '=') {
1736 next();
Jack Palevich1cdef202009-05-22 12:06:27 -07001737 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001738 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001739 pGen->popR1();
1740 pGen->storeR0ToR1(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001741 } else if (t) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001742 pGen->loadR0FromR0(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001743 }
1744 } else if (t == '&') {
Jack Palevich1cdef202009-05-22 12:06:27 -07001745 pGen->leaR0(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07001746 next();
1747 } else {
1748 n = *(int *) t;
1749 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001750 if (!n) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001751 n = (intptr_t) dlsym(RTLD_DEFAULT, last_id);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001752 }
Jack Palevich546b2242009-05-13 15:10:04 -07001753 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001754 /* assignment */
1755 next();
1756 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001757 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07001758 } else if (tok != '(') {
1759 /* variable */
Jack Palevich1cdef202009-05-22 12:06:27 -07001760 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001761 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001762 next();
1763 }
1764 }
1765 }
1766 }
1767
1768 /* function call */
1769 if (tok == '(') {
1770 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07001771 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001772
1773 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001774 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07001775 next();
1776 l = 0;
1777 while (tok != ')') {
1778 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001779 pGen->storeR0ToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001780 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001781 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001782 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001783 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001784 pGen->endFunctionCallArguments(a, l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001785 next();
1786 if (!n) {
1787 /* forward reference */
1788 t = t + 4;
1789 *(int *) t = pGen->callForward(*(int *) t);
1790 } else if (n == 1) {
1791 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001792 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07001793 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07001794 }
Jack Palevich3d474a72009-05-15 15:12:38 -07001795 if (l | (n == 1))
Jack Palevich7810bc92009-05-15 14:31:47 -07001796 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07001797 }
1798 }
1799
Jack Palevich653f42d2009-05-28 17:15:32 -07001800 void sum(int l) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07001801 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07001802 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001803 if (l-- == 1)
1804 unary(1);
1805 else {
1806 sum(l);
1807 a = 0;
1808 while (l == tokl) {
1809 n = tok;
1810 t = tokc;
1811 next();
1812
1813 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001814 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07001815 sum(l);
1816 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07001817 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001818 sum(l);
Jack Palevich1cdef202009-05-22 12:06:27 -07001819 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07001820
Jack Palevich546b2242009-05-13 15:10:04 -07001821 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001822 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001823 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001824 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001825 }
1826 }
1827 }
1828 /* && and || output code generation */
1829 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001830 a = pGen->gtst(t == OP_LOGICAL_OR, a);
1831 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07001832 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001833 pGen->gsym(a);
1834 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07001835 }
1836 }
1837 }
1838
1839 void expr() {
1840 sum(11);
1841 }
1842
1843 int test_expr() {
1844 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001845 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001846 }
1847
Jack Palevich8b0624c2009-05-20 12:12:06 -07001848 void block(intptr_t l) {
1849 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07001850
1851 if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001852 next();
1853 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07001854 a = test_expr();
1855 skip(')');
1856 block(l);
1857 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001858 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001859 n = pGen->gjmp(0); /* jmp */
1860 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001861 block(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001862 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001863 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001864 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001865 }
Jack Palevich546b2242009-05-13 15:10:04 -07001866 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001867 t = tok;
1868 next();
1869 skip('(');
1870 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07001871 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07001872 a = test_expr();
1873 } else {
1874 if (tok != ';')
1875 expr();
1876 skip(';');
1877 n = codeBuf.getPC();
1878 a = 0;
1879 if (tok != ';')
1880 a = test_expr();
1881 skip(';');
1882 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001883 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001884 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07001885 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001886 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001887 n = t + 4;
1888 }
1889 }
1890 skip(')');
Jack Palevich8b0624c2009-05-20 12:12:06 -07001891 block((intptr_t) &a);
Jack Palevicha6535612009-05-13 16:24:17 -07001892 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001893 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001894 } else if (tok == '{') {
1895 next();
1896 /* declarations */
Jack Palevichb7c81e92009-06-04 19:56:13 -07001897 localDeclarations();
Jack Palevich21a15a22009-05-11 14:49:29 -07001898 while (tok != '}')
1899 block(l);
1900 next();
1901 } else {
1902 if (tok == TOK_RETURN) {
1903 next();
1904 if (tok != ';')
1905 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001906 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001907 } else if (tok == TOK_BREAK) {
1908 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001909 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001910 } else if (tok != ';')
1911 expr();
1912 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001913 }
1914 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001915
Jack Palevichb7c81e92009-06-04 19:56:13 -07001916 typedef int Type;
1917 static const Type TY_UNKNOWN = 0;
1918 static const Type TY_INT = 1;
1919 static const Type TY_CHAR = 2;
1920 static const Type TY_VOID = 3;
1921 static const int TY_BASE_TYPE_MASK = 0xf;
1922 static const int TY_INDIRECTION_MASK = 0xf0;
1923 static const int TY_INDIRECTION_SHIFT = 4;
1924 static const int MAX_INDIRECTION_COUNT = 15;
Jack Palevich21a15a22009-05-11 14:49:29 -07001925
Jack Palevichb7c81e92009-06-04 19:56:13 -07001926 Type getBaseType(Type t) {
1927 return t & TY_BASE_TYPE_MASK;
1928 }
1929
1930 int getIndirectionCount(Type t) {
1931 return (TY_INDIRECTION_MASK & t) >> TY_INDIRECTION_SHIFT;
1932 }
1933
1934 void setIndirectionCount(Type& t, int count) {
1935 t = ((TY_INDIRECTION_MASK & (count << TY_INDIRECTION_SHIFT))
1936 | (t & ~TY_INDIRECTION_MASK));
1937 }
1938
1939 bool acceptType(Type& t) {
1940 t = TY_UNKNOWN;
1941 if (tok == TOK_INT) {
1942 t = TY_INT;
1943 } else if (tok == TOK_CHAR) {
1944 t = TY_CHAR;
1945 } else if (tok == TOK_VOID) {
1946 t = TY_VOID;
1947 } else {
1948 return false;
1949 }
1950 next();
1951 return true;
1952 }
1953
1954 Type acceptPointerDeclaration(Type& base) {
1955 Type t = base;
1956 int indirectionCount = 0;
1957 while (tok == '*' && indirectionCount <= MAX_INDIRECTION_COUNT) {
1958 next();
1959 indirectionCount++;
1960 }
1961 if (indirectionCount > MAX_INDIRECTION_COUNT) {
1962 error("Too many levels of pointer. Max %d", MAX_INDIRECTION_COUNT);
1963 }
1964 setIndirectionCount(t, indirectionCount);
1965 return t;
1966 }
1967
1968 void expectType(Type& t) {
1969 if (!acceptType(t)) {
1970 error("Expected a type.");
1971 }
1972 }
1973
1974 void checkSymbol() {
1975 if (tok <= TOK_DEFINE) {
1976 error("Expected a symbol");
1977 }
1978 }
1979
1980 void localDeclarations() {
1981 intptr_t a;
1982 Type base;
1983
1984 while (acceptType(base)) {
1985 while (tok != ';') {
1986 Type t = acceptPointerDeclaration(t);
1987 checkSymbol();
1988 loc = loc + 4;
1989 *(int *) tok = -loc;
1990
Jack Palevich21a15a22009-05-11 14:49:29 -07001991 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001992 if (tok == ',')
1993 next();
1994 }
1995 skip(';');
1996 }
1997 }
1998
1999 void globalDeclarations() {
2000 while (tok != EOF) {
2001 Type base;
2002 expectType(base);
2003 Type t = acceptPointerDeclaration(t);
2004 checkSymbol();
2005 int name = tok;
2006 next();
2007 if (tok == ',' || tok == ';') {
2008 // it's a variable declaration
2009 for(;;) {
2010 *(int* *) name = (int*) allocGlobalSpace(4);
2011 if (tok != ',') {
2012 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07002013 }
2014 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002015 t = acceptPointerDeclaration(t);
2016 checkSymbol();
2017 name = tok;
2018 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002019 }
2020 skip(';');
2021 } else {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002022 /* patch forward references (XXX: does not work for function
Jack Palevich21a15a22009-05-11 14:49:29 -07002023 pointers) */
Jack Palevichb7c81e92009-06-04 19:56:13 -07002024 pGen->gsym(*(int *) (name + 4));
Jack Palevich21a15a22009-05-11 14:49:29 -07002025 /* put function address */
Jack Palevichb7c81e92009-06-04 19:56:13 -07002026 *(int *) name = codeBuf.getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07002027 skip('(');
Jack Palevichb7c81e92009-06-04 19:56:13 -07002028 intptr_t a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07002029 int argCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002030 while (tok != ')') {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002031 Type aType;
2032 expectType(aType);
2033 aType = acceptPointerDeclaration(aType);
2034 checkSymbol();
Jack Palevich21a15a22009-05-11 14:49:29 -07002035 /* read param name and compute offset */
2036 *(int *) tok = a;
2037 a = a + 4;
2038 next();
2039 if (tok == ',')
2040 next();
Jack Palevich546b2242009-05-13 15:10:04 -07002041 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07002042 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002043 skip(')'); /* skip ')' */
Jack Palevich21a15a22009-05-11 14:49:29 -07002044 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002045 a = pGen->functionEntry(argCount);
Jack Palevich21a15a22009-05-11 14:49:29 -07002046 block(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002047 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07002048 pGen->functionExit(argCount, a, loc);
Jack Palevich21a15a22009-05-11 14:49:29 -07002049 }
2050 }
2051 }
2052
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002053 char* allocGlobalSpace(int bytes) {
2054 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
2055 error("Global space exhausted");
2056 }
2057 char* result = glo;
2058 glo += bytes;
2059 return result;
2060 }
2061
Jack Palevich21a15a22009-05-11 14:49:29 -07002062 void cleanup() {
2063 if (sym_stk != 0) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002064 free(sym_stk);
Jack Palevich21a15a22009-05-11 14:49:29 -07002065 sym_stk = 0;
2066 }
2067 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002068 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07002069 pGlobalBase = 0;
2070 }
2071 if (pVarsBase != 0) {
2072 free(pVarsBase);
2073 pVarsBase = 0;
2074 }
2075 if (pGen) {
2076 delete pGen;
2077 pGen = 0;
2078 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002079 if (file) {
2080 delete file;
2081 file = 0;
2082 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002083 }
2084
2085 void clear() {
2086 tok = 0;
2087 tokc = 0;
2088 tokl = 0;
2089 ch = 0;
Jack Palevich653f42d2009-05-28 17:15:32 -07002090 pVarsBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002091 rsym = 0;
2092 loc = 0;
2093 glo = 0;
2094 sym_stk = 0;
2095 dstk = 0;
2096 dptr = 0;
2097 dch = 0;
2098 last_id = 0;
2099 file = 0;
2100 pGlobalBase = 0;
2101 pVarsBase = 0;
2102 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002103 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002104 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002105
Jack Palevich22305132009-05-13 10:58:45 -07002106 void setArchitecture(const char* architecture) {
2107 delete pGen;
2108 pGen = 0;
2109
2110 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002111#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002112 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002113 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002114 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002115#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07002116#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002117 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002118 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002119 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002120#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07002121 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002122 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07002123 }
2124 }
2125
2126 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002127#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07002128 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07002129#elif defined(DEFAULT_X86_CODEGEN)
2130 pGen = new X86CodeGenerator();
2131#endif
2132 }
2133 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002134 error("No code generator defined.");
Jack Palevich22305132009-05-13 10:58:45 -07002135 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002136 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07002137 }
2138
Jack Palevich77ae76e2009-05-10 19:59:24 -07002139public:
Jack Palevich22305132009-05-13 10:58:45 -07002140 struct args {
2141 args() {
2142 architecture = 0;
2143 }
2144 const char* architecture;
2145 };
2146
Jack Paleviche7b59062009-05-19 17:12:17 -07002147 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002148 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002149 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002150
Jack Paleviche7b59062009-05-19 17:12:17 -07002151 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002152 cleanup();
2153 }
2154
Jack Palevich1cdef202009-05-22 12:06:27 -07002155 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002156 int result;
2157 if (! (result = setjmp(mErrorRecoveryJumpBuf))) {
2158 cleanup();
2159 clear();
2160 codeBuf.init(ALLOC_SIZE);
2161 setArchitecture(NULL);
2162 if (!pGen) {
2163 return -1;
2164 }
2165 pGen->init(&codeBuf);
2166 file = new TextInputStream(text, textLength);
2167 sym_stk = (char*) calloc(1, ALLOC_SIZE);
Jack Palevicheedf9d22009-06-04 16:23:40 -07002168 static const char* predefinedSymbols =
Jack Palevichb7c81e92009-06-04 19:56:13 -07002169 " int char void"
2170 " if else while break return for"
2171 " pragma define main ";
Jack Palevicheedf9d22009-06-04 16:23:40 -07002172 dstk = strcpy(sym_stk, predefinedSymbols)
2173 + strlen(predefinedSymbols);
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002174 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
2175 glo = pGlobalBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -07002176 pVarsBase = (char*) calloc(1, ALLOC_SIZE);
2177 inp();
2178 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002179 globalDeclarations();
Jack Palevich8dc662e2009-06-09 22:53:47 +00002180 result = pGen->finishCompile();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002181 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002182 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07002183 }
2184
2185 int run(int argc, char** argv) {
2186 typedef int (*mainPtr)(int argc, char** argv);
Jack Palevich653f42d2009-05-28 17:15:32 -07002187 mainPtr aMain = (mainPtr) *(int*) (pVarsBase + TOK_MAIN);
Jack Palevich21a15a22009-05-11 14:49:29 -07002188 if (!aMain) {
2189 fprintf(stderr, "Could not find function \"main\".\n");
2190 return -1;
2191 }
2192 return aMain(argc, argv);
2193 }
2194
2195 int dump(FILE* out) {
2196 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
2197 return 0;
2198 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07002199
Jack Palevicha6535612009-05-13 16:24:17 -07002200 int disassemble(FILE* out) {
2201 return pGen->disassemble(out);
2202 }
2203
Jack Palevich1cdef202009-05-22 12:06:27 -07002204 /* Look through the symbol table to find a symbol.
2205 * If found, return its value.
2206 */
2207 void* lookup(const char* name) {
2208 if (!sym_stk) {
2209 return NULL;
2210 }
2211 size_t nameLen = strlen(name);
Jack Palevich653f42d2009-05-28 17:15:32 -07002212 char* pSym = sym_stk;
Jack Palevich1cdef202009-05-22 12:06:27 -07002213 char c;
2214 for(;;) {
2215 c = *pSym++;
2216 if (c == 0) {
2217 break;
2218 }
2219 if (c == TAG_TOK) {
2220 if (memcmp(pSym, name, nameLen) == 0
2221 && pSym[nameLen] == TAG_TOK) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002222 int tok = pSym - 1 - sym_stk;
Jack Palevich1cdef202009-05-22 12:06:27 -07002223 tok = tok * 8 + TOK_IDENT;
2224 if (tok <= TOK_DEFINE) {
2225 return 0;
2226 } else {
Jack Palevich653f42d2009-05-28 17:15:32 -07002227 tok = (intptr_t) (pVarsBase + tok);
Jack Palevich1cdef202009-05-22 12:06:27 -07002228 return * (void**) tok;
2229 }
2230 }
2231 }
2232 }
2233 return NULL;
2234 }
2235
Jack Palevicheedf9d22009-06-04 16:23:40 -07002236 void getPragmas(ACCsizei* actualStringCount,
2237 ACCsizei maxStringCount, ACCchar** strings) {
2238 int stringCount = mPragmaStringCount;
2239 if (actualStringCount) {
2240 *actualStringCount = stringCount;
2241 }
2242 if (stringCount > maxStringCount) {
2243 stringCount = maxStringCount;
2244 }
2245 if (strings) {
2246 char* pPragmas = mPragmas.getUnwrapped();
2247 while (stringCount-- > 0) {
2248 *strings++ = pPragmas;
2249 pPragmas += strlen(pPragmas) + 1;
2250 }
2251 }
2252 }
2253
Jack Palevichac0e95e2009-05-29 13:53:44 -07002254 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002255 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07002256 }
2257
Jack Palevich77ae76e2009-05-10 19:59:24 -07002258};
2259
Jack Paleviche7b59062009-05-19 17:12:17 -07002260const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002261 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
2262
Jack Paleviche7b59062009-05-19 17:12:17 -07002263const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002264 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
2265 5, 5, /* ==, != */
2266 9, 10, /* &&, || */
2267 6, 7, 8, /* & ^ | */
2268 2, 2 /* ~ ! */
2269 };
2270
Jack Palevich8b0624c2009-05-20 12:12:06 -07002271#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002272FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07002273#endif
Jack Palevicha6535612009-05-13 16:24:17 -07002274
Jack Palevich8b0624c2009-05-20 12:12:06 -07002275#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002276const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002277 0x1, // ++
2278 0xff, // --
2279 0xc1af0f, // *
2280 0xf9f79991, // /
2281 0xf9f79991, // % (With manual assist to swap results)
2282 0xc801, // +
2283 0xd8f7c829, // -
2284 0xe0d391, // <<
2285 0xf8d391, // >>
2286 0xe, // <=
2287 0xd, // >=
2288 0xc, // <
2289 0xf, // >
2290 0x4, // ==
2291 0x5, // !=
2292 0x0, // &&
2293 0x1, // ||
2294 0xc821, // &
2295 0xc831, // ^
2296 0xc809, // |
2297 0xd0f7, // ~
2298 0x4 // !
2299};
Jack Palevich8b0624c2009-05-20 12:12:06 -07002300#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002301
Jack Palevich1cdef202009-05-22 12:06:27 -07002302struct ACCscript {
2303 ACCscript() {
2304 text = 0;
2305 textLength = 0;
2306 accError = ACC_NO_ERROR;
2307 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002308
Jack Palevich1cdef202009-05-22 12:06:27 -07002309 ~ACCscript() {
2310 delete text;
2311 }
Jack Palevich546b2242009-05-13 15:10:04 -07002312
Jack Palevich1cdef202009-05-22 12:06:27 -07002313 void setError(ACCenum error) {
2314 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
2315 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002316 }
2317 }
2318
Jack Palevich1cdef202009-05-22 12:06:27 -07002319 ACCenum getError() {
2320 ACCenum result = accError;
2321 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07002322 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002323 }
2324
Jack Palevich1cdef202009-05-22 12:06:27 -07002325 Compiler compiler;
2326 char* text;
2327 int textLength;
2328 ACCenum accError;
2329};
2330
2331
2332extern "C"
2333ACCscript* accCreateScript() {
2334 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002335}
Jack Palevich1cdef202009-05-22 12:06:27 -07002336
2337extern "C"
2338ACCenum accGetError( ACCscript* script ) {
2339 return script->getError();
2340}
2341
2342extern "C"
2343void accDeleteScript(ACCscript* script) {
2344 delete script;
2345}
2346
2347extern "C"
2348void accScriptSource(ACCscript* script,
2349 ACCsizei count,
2350 const ACCchar ** string,
2351 const ACCint * length) {
2352 int totalLength = 0;
2353 for(int i = 0; i < count; i++) {
2354 int len = -1;
2355 const ACCchar* s = string[i];
2356 if (length) {
2357 len = length[i];
2358 }
2359 if (len < 0) {
2360 len = strlen(s);
2361 }
2362 totalLength += len;
2363 }
2364 delete script->text;
2365 char* text = new char[totalLength + 1];
2366 script->text = text;
2367 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07002368 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07002369 for(int i = 0; i < count; i++) {
2370 int len = -1;
2371 const ACCchar* s = string[i];
2372 if (length) {
2373 len = length[i];
2374 }
2375 if (len < 0) {
2376 len = strlen(s);
2377 }
Jack Palevich09555c72009-05-27 12:25:55 -07002378 memcpy(dest, s, len);
2379 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07002380 }
2381 text[totalLength] = '\0';
2382}
2383
2384extern "C"
2385void accCompileScript(ACCscript* script) {
2386 int result = script->compiler.compile(script->text, script->textLength);
2387 if (result) {
2388 script->setError(ACC_INVALID_OPERATION);
2389 }
2390}
2391
2392extern "C"
2393void accGetScriptiv(ACCscript* script,
2394 ACCenum pname,
2395 ACCint * params) {
2396 switch (pname) {
2397 case ACC_INFO_LOG_LENGTH:
2398 *params = 0;
2399 break;
2400 }
2401}
2402
2403extern "C"
2404void accGetScriptInfoLog(ACCscript* script,
2405 ACCsizei maxLength,
2406 ACCsizei * length,
2407 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002408 char* message = script->compiler.getErrorMessage();
2409 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07002410 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002411 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07002412 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002413 if (infoLog && maxLength > 0) {
2414 int trimmedLength = maxLength < messageLength ?
2415 maxLength : messageLength;
2416 memcpy(infoLog, message, trimmedLength);
2417 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002418 }
2419}
2420
2421extern "C"
2422void accGetScriptLabel(ACCscript* script, const ACCchar * name,
2423 ACCvoid ** address) {
2424 void* value = script->compiler.lookup(name);
2425 if (value) {
2426 *address = value;
2427 } else {
2428 script->setError(ACC_INVALID_VALUE);
2429 }
2430}
2431
Jack Palevicheedf9d22009-06-04 16:23:40 -07002432extern "C"
2433void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
2434 ACCsizei maxStringCount, ACCchar** strings){
2435 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
2436}
2437
2438
Jack Palevich1cdef202009-05-22 12:06:27 -07002439} // namespace acc
2440