]>
Commit | Line | Data |
---|---|---|
58eb6e7c AG |
1 | // java-interp.h - Header file for the bytecode interpreter. -*- c++ -*- |
2 | ||
896b1c87 | 3 | /* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation |
58eb6e7c AG |
4 | |
5 | This file is part of libgcj. | |
6 | ||
7 | This software is copyrighted work licensed under the terms of the | |
8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | #ifndef __JAVA_INTERP_H__ | |
12 | #define __JAVA_INTERP_H__ | |
13 | ||
58eb6e7c AG |
14 | #include <jvm.h> |
15 | #include <java-cpool.h> | |
3308c46e | 16 | #include <gnu/gcj/runtime/NameFinder.h> |
58eb6e7c | 17 | |
86acf60c DD |
18 | enum _Jv_FrameType |
19 | { | |
20 | frame_native, | |
21 | frame_interpreter, | |
22 | frame_proxy | |
23 | }; | |
24 | ||
58eb6e7c AG |
25 | #ifdef INTERPRETER |
26 | ||
27 | #pragma interface | |
28 | ||
29 | #include <java/lang/Class.h> | |
30 | #include <java/lang/ClassLoader.h> | |
a1aba4f9 | 31 | #include <java/lang/reflect/Modifier.h> |
1349c688 BM |
32 | #include <java/lang/Thread.h> |
33 | #include <gnu/gcj/RawData.h> | |
58eb6e7c | 34 | |
18744d9b BM |
35 | // Define this to get the direct-threaded interpreter. If undefined, |
36 | // we revert to a basic bytecode interpreter. The former is faster | |
37 | // but uses more memory. | |
38 | #define DIRECT_THREADED | |
39 | ||
58eb6e7c | 40 | #include <ffi.h> |
58eb6e7c | 41 | |
58eb6e7c AG |
42 | struct _Jv_ResolvedMethod; |
43 | ||
6187fd28 | 44 | void _Jv_InitInterpreter (); |
36739040 | 45 | void _Jv_DefineClass (jclass, jbyteArray, jint, jint, |
42c51695 TT |
46 | java::security::ProtectionDomain *, |
47 | _Jv_Utf8Const **); | |
58eb6e7c AG |
48 | |
49 | void _Jv_InitField (jobject, jclass, int); | |
50 | void * _Jv_AllocMethodInvocation (jsize size); | |
a12fe13d TT |
51 | int _Jv_count_arguments (_Jv_Utf8Const *signature, |
52 | jboolean staticp = true); | |
53 | void _Jv_VerifyMethod (_Jv_InterpMethod *method); | |
d0f4aa53 | 54 | void _Jv_CompileMethod (_Jv_InterpMethod* method); |
97b8365c TT |
55 | int _Jv_init_cif (_Jv_Utf8Const* signature, |
56 | int arg_count, | |
57 | jboolean staticp, | |
58 | ffi_cif *cif, | |
59 | ffi_type **arg_types, | |
60 | ffi_type **rtype_p); | |
58eb6e7c | 61 | |
58eb6e7c AG |
62 | /* the interpreter is written in C++, primarily because it makes it easy for |
63 | * the entire thing to be "friend" with class Class. */ | |
64 | ||
65 | class _Jv_InterpClass; | |
66 | class _Jv_InterpMethod; | |
fdae83ab TT |
67 | |
68 | // Before a method is "compiled" we store values as the bytecode PC, | |
69 | // an int. Afterwards we store them as pointers into the prepared | |
70 | // code itself. | |
71 | union _Jv_InterpPC | |
72 | { | |
73 | int i; | |
74 | void *p; | |
75 | }; | |
58eb6e7c | 76 | |
a12fe13d TT |
77 | class _Jv_InterpException |
78 | { | |
fdae83ab TT |
79 | _Jv_InterpPC start_pc; |
80 | _Jv_InterpPC end_pc; | |
81 | _Jv_InterpPC handler_pc; | |
82 | _Jv_InterpPC handler_type; | |
58eb6e7c AG |
83 | |
84 | friend class _Jv_ClassReader; | |
85 | friend class _Jv_InterpMethod; | |
a12fe13d | 86 | friend class _Jv_BytecodeVerifier; |
58eb6e7c AG |
87 | }; |
88 | ||
f39b788a TT |
89 | // Base class for method representations. Subclasses are interpreted |
90 | // and JNI methods. | |
91 | class _Jv_MethodBase | |
92 | { | |
93 | protected: | |
94 | // The class which defined this method. | |
f5310108 | 95 | jclass defining_class; |
f39b788a TT |
96 | |
97 | // The method description. | |
98 | _Jv_Method *self; | |
d348bda4 TT |
99 | |
100 | // Size of raw arguments. | |
101 | _Jv_ushort args_raw_size; | |
8ade4771 | 102 | |
36739040 | 103 | friend class _Jv_InterpreterEngine; |
90471585 | 104 | |
8ade4771 TT |
105 | public: |
106 | _Jv_Method *get_method () | |
107 | { | |
108 | return self; | |
109 | } | |
f39b788a TT |
110 | }; |
111 | ||
18744d9b BM |
112 | // The type of the PC depends on whether we're doing direct threading |
113 | // or a more ordinary bytecode interpreter. | |
114 | #ifdef DIRECT_THREADED | |
115 | // Slot in the "compiled" form of the bytecode. | |
116 | union insn_slot | |
117 | { | |
118 | // Address of code. | |
119 | void *insn; | |
120 | // An integer value used by an instruction. | |
121 | jint int_val; | |
122 | // A pointer value used by an instruction. | |
123 | void *datum; | |
124 | }; | |
125 | ||
126 | typedef insn_slot *pc_t; | |
127 | #else | |
128 | typedef unsigned char *pc_t; | |
129 | #endif | |
130 | ||
131 | ||
132 | // This structure holds the bytecode pc and corresponding source code | |
133 | // line number. An array (plus length field) of this structure is put | |
134 | // in each _Jv_InterpMethod and used to resolve the (internal) program | |
135 | // counter of the interpreted method to an actual java source file | |
136 | // line. | |
137 | struct _Jv_LineTableEntry | |
138 | { | |
139 | union | |
140 | { | |
141 | pc_t pc; | |
142 | int bytecode_pc; | |
143 | }; | |
144 | int line; | |
145 | }; | |
146 | ||
fe60528e | 147 | // This structure holds local variable information. |
7dace0ca KS |
148 | // Like _Jv_LineTableEntry above, it is remapped when the method is |
149 | // compiled for direct threading. | |
fe60528e KG |
150 | struct _Jv_LocalVarTableEntry |
151 | { | |
7dace0ca KS |
152 | // First PC value at which variable is live |
153 | union | |
154 | { | |
155 | pc_t pc; | |
156 | int bytecode_pc; | |
157 | }; | |
158 | ||
159 | // length of visibility of variable | |
fe60528e | 160 | int length; |
7dace0ca KS |
161 | |
162 | // variable name | |
fe60528e | 163 | char *name; |
7dace0ca KS |
164 | |
165 | // type description | |
fe60528e | 166 | char *descriptor; |
7dace0ca KS |
167 | |
168 | // stack slot number (long and double occupy slot and slot + 1) | |
fe60528e KG |
169 | int slot; |
170 | }; | |
171 | ||
facc279f TT |
172 | class _Jv_InterpMethod : public _Jv_MethodBase |
173 | { | |
0f546316 KS |
174 | // Breakpoint instruction |
175 | static pc_t breakpoint_insn; | |
176 | #ifdef DIRECT_THREADED | |
177 | static insn_slot bp_insn_slot; | |
178 | #else | |
179 | static unsigned char bp_insn_opcode; | |
180 | #endif | |
181 | ||
58eb6e7c AG |
182 | _Jv_ushort max_stack; |
183 | _Jv_ushort max_locals; | |
184 | int code_length; | |
185 | ||
186 | _Jv_ushort exc_count; | |
a022cd59 | 187 | bool is_15; |
58eb6e7c | 188 | |
18744d9b BM |
189 | // Length of the line_table - when this is zero then line_table is NULL. |
190 | int line_table_len; | |
191 | _Jv_LineTableEntry *line_table; | |
fe60528e KG |
192 | |
193 | // The local variable table length and the table itself | |
194 | int local_var_table_len; | |
195 | _Jv_LocalVarTableEntry *local_var_table; | |
18744d9b | 196 | |
19add4f7 | 197 | pc_t prepared; |
e939885f | 198 | int number_insn_slots; |
fdae83ab | 199 | |
58eb6e7c AG |
200 | unsigned char* bytecode () |
201 | { | |
202 | return | |
203 | ((unsigned char*)this) | |
204 | + ROUND((sizeof (_Jv_InterpMethod) | |
205 | + exc_count*sizeof (_Jv_InterpException)), 4); | |
206 | } | |
fdae83ab | 207 | |
58eb6e7c AG |
208 | _Jv_InterpException * exceptions () |
209 | { | |
210 | return (_Jv_InterpException*) (this+1); | |
211 | } | |
212 | ||
213 | static size_t size (int exc_count, int code_length) | |
214 | { | |
215 | return | |
216 | ROUND ((sizeof (_Jv_InterpMethod) | |
217 | + (exc_count * sizeof (_Jv_InterpException))), 4) | |
218 | + code_length; | |
219 | } | |
220 | ||
221 | // return the method's invocation pointer (a stub). | |
18fa3240 | 222 | void *ncode (jclass); |
fdae83ab | 223 | void compile (const void * const *); |
58eb6e7c | 224 | |
4c42b3d8 DD |
225 | #if FFI_NATIVE_RAW_API |
226 | # define INTERP_FFI_RAW_TYPE ffi_raw | |
227 | #else | |
228 | # define INTERP_FFI_RAW_TYPE ffi_java_raw | |
229 | #endif | |
58eb6e7c | 230 | |
4c42b3d8 DD |
231 | static void run_normal (ffi_cif*, void*, INTERP_FFI_RAW_TYPE*, void*); |
232 | static void run_synch_object (ffi_cif*, void*, INTERP_FFI_RAW_TYPE*, void*); | |
233 | static void run_class (ffi_cif*, void*, INTERP_FFI_RAW_TYPE*, void*); | |
234 | static void run_synch_class (ffi_cif*, void*, INTERP_FFI_RAW_TYPE*, void*); | |
235 | ||
236 | static void run_normal_debug (ffi_cif*, void*, INTERP_FFI_RAW_TYPE*, void*); | |
237 | static void run_synch_object_debug (ffi_cif*, void*, INTERP_FFI_RAW_TYPE*, | |
238 | void*); | |
239 | static void run_class_debug (ffi_cif*, void*, INTERP_FFI_RAW_TYPE*, void*); | |
240 | static void run_synch_class_debug (ffi_cif*, void*, INTERP_FFI_RAW_TYPE*, | |
241 | void*); | |
242 | ||
243 | static void run (void *, INTERP_FFI_RAW_TYPE *, _Jv_InterpMethod *); | |
244 | static void run_debug (void *, INTERP_FFI_RAW_TYPE *, _Jv_InterpMethod *); | |
50ac2500 | 245 | |
18744d9b | 246 | |
50ac2500 | 247 | |
18744d9b BM |
248 | // Returns source file line number for given PC value, or -1 if line |
249 | // number info is unavailable. | |
250 | int get_source_line(pc_t mpc); | |
58eb6e7c | 251 | |
39273131 KG |
252 | public: |
253 | ||
e939885f KS |
254 | // Convenience function for indexing bytecode PC/insn slots in |
255 | // line tables for JDWP | |
256 | jlong insn_index (pc_t pc); | |
7a1bf87c KG |
257 | |
258 | // Helper function used to check if there is a handler for an exception | |
259 | // present at this code index | |
260 | jboolean check_handler (pc_t *pc, _Jv_InterpMethod *meth, | |
261 | java::lang::Throwable *ex); | |
50ac2500 | 262 | |
e939885f KS |
263 | /* Get the line table for this method. |
264 | * start is the lowest index in the method | |
265 | * end is the highest index in the method | |
266 | * line_numbers is an array to hold the list of source line numbers | |
267 | * code_indices is an array to hold the corresponding list of code indices | |
268 | */ | |
269 | void get_line_table (jlong& start, jlong& end, jintArray& line_numbers, | |
270 | jlongArray& code_indices); | |
04ab4573 KG |
271 | |
272 | int get_max_locals () | |
273 | { | |
274 | return static_cast<int> (max_locals); | |
275 | } | |
fe60528e KG |
276 | |
277 | /* Get info for a local variable of this method. | |
278 | * If there is no loca_var_table for this method it will return -1. | |
279 | * table_slot indicates which slot in the local_var_table to get, if there is | |
280 | * no variable at this location it will return 0. | |
281 | * Otherwise, it will return the number of table slots after the selected | |
282 | * slot, indexed from 0. | |
283 | * | |
284 | * Example: there are 5 slots in the table, you request slot 0 so it will | |
285 | * return 4. | |
286 | */ | |
287 | int get_local_var_table (char **name, char **sig, char **generic_sig, | |
288 | jlong *startloc, jint *length, jint *slot, | |
289 | int table_slot); | |
e939885f | 290 | |
0f546316 KS |
291 | /* Installs a break instruction at the given code index. Returns |
292 | the pc_t of the breakpoint or NULL if index is invalid. */ | |
293 | pc_t install_break (jlong index); | |
294 | ||
05ee9ca0 KS |
295 | // Gets the instruction at the given index |
296 | pc_t get_insn (jlong index); | |
297 | ||
298 | /* Writes the given instruction at the given code index. Returns | |
299 | the insn or NULL if index is invalid. */ | |
300 | pc_t set_insn (jlong index, pc_t insn); | |
301 | ||
8faab1f4 KS |
302 | // Is the given location in this method a breakpoint? |
303 | bool breakpoint_at (jlong index); | |
304 | ||
d0f4aa53 KS |
305 | #ifdef DIRECT_THREADED |
306 | friend void _Jv_CompileMethod (_Jv_InterpMethod*); | |
307 | #endif | |
308 | ||
58eb6e7c | 309 | friend class _Jv_ClassReader; |
a12fe13d | 310 | friend class _Jv_BytecodeVerifier; |
18744d9b | 311 | friend class _Jv_StackTrace; |
36739040 | 312 | friend class _Jv_InterpreterEngine; |
58eb6e7c | 313 | |
b4d0051b TT |
314 | #ifdef JV_MARKOBJ_DECL |
315 | friend JV_MARKOBJ_DECL; | |
316 | #endif | |
58eb6e7c AG |
317 | }; |
318 | ||
f5310108 | 319 | class _Jv_InterpClass |
58eb6e7c | 320 | { |
facc279f | 321 | _Jv_MethodBase **interpreted_methods; |
18744d9b BM |
322 | _Jv_ushort *field_initializers; |
323 | jstring source_file_name; | |
18fa3240 | 324 | _Jv_ClosureList **closures; |
58eb6e7c AG |
325 | |
326 | friend class _Jv_ClassReader; | |
327 | friend class _Jv_InterpMethod; | |
18744d9b | 328 | friend class _Jv_StackTrace; |
36739040 | 329 | friend class _Jv_InterpreterEngine; |
18744d9b | 330 | |
58eb6e7c | 331 | friend void _Jv_InitField (jobject, jclass, int); |
470042c7 TT |
332 | #ifdef JV_MARKOBJ_DECL |
333 | friend JV_MARKOBJ_DECL; | |
334 | #endif | |
8ade4771 TT |
335 | |
336 | friend _Jv_MethodBase ** _Jv_GetFirstMethod (_Jv_InterpClass *klass); | |
bde6c7a9 | 337 | friend jstring _Jv_GetInterpClassSourceFile (jclass); |
58eb6e7c AG |
338 | }; |
339 | ||
8ade4771 TT |
340 | extern inline _Jv_MethodBase ** |
341 | _Jv_GetFirstMethod (_Jv_InterpClass *klass) | |
342 | { | |
343 | return klass->interpreted_methods; | |
344 | } | |
345 | ||
a022cd59 TT |
346 | struct _Jv_ResolvedMethod |
347 | { | |
58eb6e7c | 348 | jint stack_item_count; |
58eb6e7c AG |
349 | jclass klass; |
350 | _Jv_Method* method; | |
351 | ||
352 | // a resolved method holds the cif in-line, so that _Jv_MarkObj just needs | |
353 | // to mark the resolved method to hold on to the cif. Some memory could be | |
354 | // saved by keeping a cache of cif's, since many will be the same. | |
355 | ffi_cif cif; | |
356 | ffi_type * arg_types[0]; | |
357 | }; | |
358 | ||
facc279f TT |
359 | class _Jv_JNIMethod : public _Jv_MethodBase |
360 | { | |
361 | // The underlying function. If NULL we have to look for the | |
362 | // function. | |
363 | void *function; | |
364 | ||
d348bda4 TT |
365 | // This is the CIF used by the JNI function. |
366 | ffi_cif jni_cif; | |
367 | ||
368 | // These are the argument types used by the JNI function. | |
369 | ffi_type **jni_arg_types; | |
370 | ||
facc279f | 371 | // This function is used when making a JNI call from the interpreter. |
4c42b3d8 | 372 | static void call (ffi_cif *, void *, INTERP_FFI_RAW_TYPE *, void *); |
facc279f | 373 | |
18fa3240 | 374 | void *ncode (jclass); |
facc279f TT |
375 | |
376 | friend class _Jv_ClassReader; | |
36739040 TT |
377 | friend class _Jv_InterpreterEngine; |
378 | ||
379 | #ifdef JV_MARKOBJ_DECL | |
380 | friend JV_MARKOBJ_DECL; | |
381 | #endif | |
8ade4771 TT |
382 | |
383 | public: | |
384 | // FIXME: this is ugly. | |
385 | void set_function (void *f) | |
386 | { | |
387 | function = f; | |
388 | } | |
facc279f TT |
389 | }; |
390 | ||
39273131 KG |
391 | // The composite call stack as represented by a linked list of frames |
392 | class _Jv_Frame | |
393 | { | |
394 | public: | |
395 | java::lang::Thread *thread; | |
396 | ||
97b8365c TT |
397 | union |
398 | { | |
39273131 | 399 | _Jv_MethodBase *self; |
97b8365c | 400 | void *meth; |
97b8365c TT |
401 | _Jv_Method *proxyMethod; |
402 | }; | |
39273131 KG |
403 | |
404 | //The full list of frames, JNI and interpreted | |
405 | _Jv_Frame *next; | |
406 | _Jv_FrameType frame_type; | |
407 | ||
408 | _Jv_Frame (_Jv_MethodBase *s, java::lang::Thread *thr, _Jv_FrameType type) | |
409 | { | |
410 | self = s; | |
411 | frame_type = type; | |
412 | next = (_Jv_Frame *) thr->frame; | |
413 | thr->frame = (gnu::gcj::RawData *) this; | |
414 | thread = thr; | |
415 | } | |
416 | ||
417 | ~_Jv_Frame () | |
418 | { | |
419 | thread->frame = (gnu::gcj::RawData *) next; | |
420 | } | |
896b1c87 KS |
421 | |
422 | int depth () | |
423 | { | |
424 | int depth = 0; | |
425 | struct _Jv_Frame *f; | |
426 | for (f = this; f != NULL; f = f->next) | |
427 | ++depth; | |
428 | ||
429 | return depth; | |
430 | } | |
39273131 KG |
431 | }; |
432 | ||
433 | // An interpreted frame in the call stack | |
434 | class _Jv_InterpFrame : public _Jv_Frame | |
435 | { | |
436 | public: | |
437 | ||
438 | // Keep the purely interpreted list around so as not to break backtraces | |
439 | _Jv_InterpFrame *next_interp; | |
440 | ||
97b8365c TT |
441 | union |
442 | { | |
443 | pc_t pc; | |
444 | jclass proxyClass; | |
445 | }; | |
d7647361 KG |
446 | |
447 | // Pointer to the actual pc value. | |
448 | pc_t *pc_ptr; | |
39273131 KG |
449 | |
450 | //Debug info for local variables. | |
451 | _Jv_word *locals; | |
452 | char *locals_type; | |
453 | ||
72268e15 KG |
454 | // Object pointer for this frame ("this") |
455 | jobject obj_ptr; | |
456 | ||
d7647361 KG |
457 | _Jv_InterpFrame (void *meth, java::lang::Thread *thr, jclass proxyCls = NULL, |
458 | pc_t *pc = NULL) | |
39273131 KG |
459 | : _Jv_Frame (reinterpret_cast<_Jv_MethodBase *> (meth), thr, |
460 | frame_interpreter) | |
3308c46e | 461 | { |
39273131 KG |
462 | next_interp = (_Jv_InterpFrame *) thr->interp_frame; |
463 | proxyClass = proxyCls; | |
1349c688 | 464 | thr->interp_frame = (gnu::gcj::RawData *) this; |
72268e15 | 465 | obj_ptr = NULL; |
d7647361 | 466 | pc_ptr = pc; |
3308c46e TT |
467 | } |
468 | ||
18744d9b | 469 | ~_Jv_InterpFrame () |
3308c46e | 470 | { |
39273131 KG |
471 | thread->interp_frame = (gnu::gcj::RawData *) next_interp; |
472 | } | |
72268e15 KG |
473 | |
474 | jobject get_this_ptr () | |
475 | { | |
476 | return obj_ptr; | |
d7647361 KG |
477 | } |
478 | ||
479 | pc_t get_pc () | |
480 | { | |
481 | pc_t pc; | |
482 | ||
483 | // If the PC_PTR is NULL, we are not debugging. | |
484 | if (pc_ptr == NULL) | |
485 | pc = 0; | |
486 | else | |
e1b871ec | 487 | pc = *pc_ptr - 1; |
d7647361 | 488 | |
e1b871ec | 489 | return pc; |
d7647361 | 490 | } |
39273131 KG |
491 | }; |
492 | ||
493 | // A native frame in the call stack really just a placeholder | |
494 | class _Jv_NativeFrame : public _Jv_Frame | |
495 | { | |
496 | public: | |
497 | ||
498 | _Jv_NativeFrame (_Jv_JNIMethod *s, java::lang::Thread *thr) | |
499 | : _Jv_Frame (s, thr, frame_native) | |
500 | { | |
3308c46e TT |
501 | } |
502 | }; | |
503 | ||
f39b788a TT |
504 | #endif /* INTERPRETER */ |
505 | ||
58eb6e7c | 506 | #endif /* __JAVA_INTERP_H__ */ |