OSDN Git Service

b02db7160bee14f4ca8eb164836895a5ae415f02
[nxt-jsp/lejos_nxj.git] / nxtOSEK / lejos_nxj / src / nxtvm / javavm / interpreter.c
1
2 #include "trace.h"
3 #include "types.h"
4 #include "constants.h"
5 #include "classes.h"
6 #include "interpreter.h"
7 #include "platform_hooks.h"
8 #include "threads.h"
9 #include "opcodes.h"
10 #include "configure.h"
11 #include "memory.h"
12 #include "language.h"
13 #include "exceptions.h"
14 #include "specialclasses.h"
15 #include "fields.h"
16 #include "stack.h"
17 #include "poll.h"
18
19
20 #define F_OFFSET_MASK  0x0F
21
22 #if DEBUG_BYTECODE
23 extern char *OPCODE_NAME[];
24 #endif
25
26 // Interpreter globals:
27
28 volatile boolean gMakeRequest;
29 byte    gRequestCode;
30 unsigned int gNextProgram;
31 unsigned int gNextProgramSize;
32
33 byte *pc;
34 STACKWORD *localsBase;
35 STACKWORD *stackTop;
36
37 // Temporary globals:
38
39 byte tempByte;
40 byte *tempBytePtr;
41 JFLOAT tempFloat;
42 ConstantRecord *tempConstRec;
43 STACKWORD tempStackWord;
44 STACKWORD *tempWordPtr;
45 JSHORT tempInt;
46   
47 /**
48  * Assumes pc points to 2-byte offset, and jumps.
49  */
50 void do_goto (boolean aCond)
51 {
52   if (aCond)
53   {
54     pc += (JSHORT) (((TWOBYTES) *pc << 8) | *(pc+1));
55     pc--;
56   }
57   else
58   {
59     pc += 2;
60   }
61 }
62
63 void do_isub (void)
64 {
65   STACKWORD poppedWord;
66
67   poppedWord = pop_word();
68   set_top_word (word2jint(get_top_word()) - word2jint(poppedWord));
69 }
70
71 #if FP_ARITHMETIC
72
73 void do_fcmp (JFLOAT f1, JFLOAT f2, STACKWORD def)
74 {
75   if (f1 > f2)
76     push_word (1);
77   else if (f1 == f2)
78     push_word (0);
79   else if (f1 < f2)
80     push_word (-1);
81   else 
82     push_word (def);
83 }
84
85 #endif
86
87 /**
88  * @return A String instance, or JNULL if an exception was thrown
89  *         or the static initializer of String had to be executed.
90  */
91 static inline Object *create_string (ConstantRecord *constantRecord, 
92                                      byte *btAddr)
93 {
94   Object *ref;
95   Object *arr;
96   TWOBYTES i;
97
98   ref = new_object_checked (JAVA_LANG_STRING, btAddr);
99   if (ref == JNULL)
100     return JNULL;
101   arr = new_primitive_array (T_CHAR, constantRecord->constantSize);
102   if (arr == JNULL)
103   {
104     deallocate (obj2ptr(ref), class_size (JAVA_LANG_STRING));    
105     return JNULL;
106   }
107   
108 //  printf ("char array at %d\n", (int) arr);
109   
110   store_word ((byte *) &(((String *) ref)->characters), 4, obj2word(arr));
111   
112   for (i = 0; i < constantRecord->constantSize; i++)
113   {
114     jchar_array(arr)[i] = (JCHAR) get_constant_ptr(constantRecord)[i];
115
116     //printf ("char %d: %c\n", i, (char) (jchar_array(arr)[i])); 
117   }
118   return ref;
119 }
120
121 /**
122  * Pops the array index off the stack, assigns
123  * both tempInt and tempBytePtr, and checks
124  * bounds and null reference. The array reference
125  * is the top word on the stack after this operation.
126  * @return True if successful, false if an exception has been scheduled.
127  */
128 boolean array_load_helper()
129 {
130   tempInt = word2jshort(pop_word());
131   tempBytePtr = word2ptr(get_top_ref());
132   if (tempBytePtr == JNULL)
133     throw_exception (nullPointerException);
134   else if (tempInt < 0 || tempInt >= get_array_length ((Object *) tempBytePtr))
135     throw_exception (arrayIndexOutOfBoundsException);
136   else
137     return true;
138   return false;
139 }
140
141 /**
142  * Same as array_load_helper, except that it pops
143  * the reference from the stack.
144  */
145 boolean array_store_helper()
146 {
147   if (array_load_helper())
148   {
149     pop_ref();
150     return true;
151   }
152   return false;
153 }
154
155 /**
156  * Everything runs inside here, essentially.
157  *
158  * To be able use only a single fast test on each instruction
159  * several assumptions are made:
160  * - currentThread is initialized and non-null and
161  *   it is not set to null by any bytecode instruction.
162  * - Thus it is not allowed to call schedule_thread() in instructions,
163  *   use schedule_request( REQUEST_SWITCH_THREAD) instead.
164  * - Whenever gMakeRequest is false, gRequestCode is REQUEST_TICK.
165  * - Thus anybody who sets gRequestCode must also set gMakeRequest to true
166  *   (using schedule_request assures this).
167  * - Only the request handler may set gMakeRequest to false.
168  * - The millisecond timer interrupt must set gMakeRequest to true
169  *   for time slices to work.
170  * 
171  */
172 void engine()
173 {
174   byte ticks_until_switch = TICKS_PER_TIME_SLICE;
175
176   assert( currentThread != null, INTERPRETER0);
177
178   schedule_request( REQUEST_SWITCH_THREAD);
179
180  LABEL_ENGINELOOP: 
181   instruction_hook();
182
183   assert( currentThread != null, INTERPRETER1);
184
185   while( gMakeRequest)
186   {
187     byte requestCode = gRequestCode;
188
189     gMakeRequest = false;
190     gRequestCode = REQUEST_TICK;
191     
192     tick_hook();
193
194     if( requestCode == REQUEST_EXIT)
195     {
196       return;
197     }
198
199     if( requestCode == REQUEST_TICK)
200       ticks_until_switch--;
201
202     if( requestCode == REQUEST_SWITCH_THREAD
203         || ticks_until_switch == 0){
204       ticks_until_switch = TICKS_PER_TIME_SLICE;
205 #if DEBUG_THREADS
206       printf ("switching thread: %d\n", (int)ticks_until_switch);
207 #endif
208       switch_thread();
209 #if DEBUG_THREADS
210       printf ("done switching thread\n");
211 #endif
212       switch_thread_hook();
213     }
214     if( currentThread == null   /* no runnable thread */
215         && gRequestCode == REQUEST_TICK){ /* no important request */
216       idle_hook();
217       schedule_request( REQUEST_SWITCH_THREAD);
218     }
219   }
220
221   assert( gRequestCode == REQUEST_TICK, INTERPRETER2);
222   assert( currentThread != null, INTERPRETER3);
223
224   //-----------------------------------------------
225   // SWITCH BEGINS HERE
226   //-----------------------------------------------
227
228   #if DEBUG_BYTECODE
229   printf ("0x%X: \n", (int) pc);
230   printf ("OPCODE (0x%X) %s\n", (int) *pc, OPCODE_NAME[*pc]);
231   #endif
232
233   switch (*pc++)
234   {
235     case OP_NOP:
236         goto LABEL_ENGINELOOP;
237
238     #include "op_stack.hc"
239     #include "op_locals.hc"
240     #include "op_arrays.hc"
241     #include "op_objects.hc"
242     #include "op_control.hc"
243     #include "op_other.hc"
244     #include "op_conversions.hc"
245     #include "op_logical.hc"
246     #include "op_arithmetic.hc"
247     #include "op_methods.hc"
248
249 /*
250 #ifdef VERIFY
251         default:
252                 assert(false, (TWOBYTES)(pc-1) % 10000);
253                 break;
254 #endif
255 */
256   }
257
258   //-----------------------------------------------
259   // SWITCH ENDS HERE
260   //-----------------------------------------------
261
262    #if !FP_ARITHMETIC
263
264    throw_exception (noSuchMethodError);
265
266    #else
267   
268    // This point should never be reached
269
270    #ifdef VERIFY
271    assert (false, 1000 + *pc);
272    #endif // VERIFY
273
274    #endif // FP_ARITHMETIC
275 }
276
277
278
279
280