Line data Source code
1 : /* src/vm/jit/trace.cpp - Functions for tracing from java code.
2 :
3 : Copyright (C) 1996-2013
4 : CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 :
6 : This file is part of CACAO.
7 :
8 : This program is free software; you can redistribute it and/or
9 : modify it under the terms of the GNU General Public License as
10 : published by the Free Software Foundation; either version 2, or (at
11 : your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program; if not, write to the Free Software
20 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 : 02110-1301, USA.
22 :
23 : */
24 :
25 : #include "vm/jit/trace.hpp"
26 : #include <cstdio>
27 : #include "config.h" // for ENABLE_DEBUG_FILTER, etc
28 : #include "md-abi.hpp"
29 : #include "native/llni.hpp"
30 : #include "threads/thread.hpp" // for threadobject
31 : #include "toolbox/logging.hpp"
32 : #include "toolbox/buffer.hpp" // for Buffer
33 : #include "vm/array.hpp"
34 : #include "vm/class.hpp" // for classinfo
35 : #include "vm/descriptor.hpp" // for methoddesc, typedesc
36 : #include "vm/global.hpp" // for imm_union, java_object_t, etc
37 : #include "vm/globals.hpp" // for class_java_lang_Class, etc
38 : #include "vm/hook.hpp" // for method_enter, method_exit
39 : #include "vm/javaobjects.hpp" // for java_lang_Throwable, etc
40 : #include "vm/jit/argument.hpp" // for argument_jitarray_load, etc
41 : #include "vm/jit/code.hpp" // for codeinfo
42 : #include "vm/jit/codegen-common.hpp"
43 : #include "vm/jit/show.hpp"
44 : #include "vm/method.hpp" // for methodinfo, etc
45 : #include "vm/options.hpp" // for opt_TraceBuiltinCalls, etc
46 : #include "vm/string.hpp" // for JavaString
47 : #include "vm/types.hpp" // for s4
48 : #include "vm/utf8.hpp" // for Utf8String
49 : #include "vm/vftbl.hpp" // for vftbl_t
50 :
51 : #if !defined(NDEBUG)
52 :
53 : /* trace_java_call_print_argument **********************************************
54 :
55 : XXX: Document me!
56 :
57 : *******************************************************************************/
58 :
59 0 : static void trace_java_call_print_argument(Buffer<>& logtext, methodinfo *m, typedesc *paramtype, imm_union imu)
60 : {
61 : java_object_t *o;
62 : classinfo *c;
63 0 : Utf8String u;
64 :
65 0 : switch (paramtype->type) {
66 : case TYPE_INT:
67 0 : logtext.write_dec(imu.i).write(" (").write_hex(imu.i).write(')');
68 0 : break;
69 : case TYPE_LNG:
70 0 : logtext.write_dec(imu.l).write(" (").write_hex(imu.l).write(')');
71 0 : break;
72 : case TYPE_FLT:
73 0 : logtext.write_dec(imu.f).write(" (").write_hex(imu.f).write(')');
74 0 : break;
75 : case TYPE_DBL:
76 0 : logtext.write_dec(imu.d).write(" (").write_hex(imu.d).write(')');
77 0 : break;
78 :
79 : case TYPE_ADR:
80 0 : logtext.write_ptr(imu.a);
81 :
82 : /* Workaround for sun.misc.Unsafe methods. In the future
83 : (exact GC) we should check if the address is on the GC
84 : heap. */
85 :
86 0 : if ((m->clazz != NULL) &&
87 : (m->clazz->name == Utf8String::from_utf8("sun/misc/Unsafe")))
88 0 : break;
89 :
90 : /* Cast to java.lang.Object. */
91 :
92 0 : o = (java_handle_t*) (uintptr_t) imu.l;
93 :
94 : /* Check return argument for java.lang.Class or
95 : java.lang.String. */
96 :
97 0 : if (o != NULL) {
98 0 : if (o->vftbl->clazz == class_java_lang_String) {
99 : /* convert java.lang.String object to utf8 string and strcat it to the logtext */
100 :
101 : logtext.write(" (String = \"")
102 : .write(o)
103 0 : .write("\")");
104 : }
105 : else {
106 0 : if (o->vftbl->clazz == class_java_lang_Class) {
107 : /* if the object returned is a java.lang.Class
108 : cast it to classinfo structure and get the name
109 : of the class */
110 :
111 0 : c = (classinfo *) o;
112 :
113 0 : u = c->name;
114 : }
115 : else {
116 : /* if the object returned is not a java.lang.String or
117 : a java.lang.Class just print the name of the class */
118 :
119 0 : u = o->vftbl->clazz->name;
120 : }
121 :
122 : /* strcat to the logtext */
123 :
124 : logtext.write(" (Class = \"")
125 : .write_slash_to_dot(u)
126 0 : .write("\")");
127 : }
128 : }
129 0 : break;
130 : default:
131 0 : assert(false);
132 : break;
133 : }
134 0 : }
135 :
136 : /* trace_java_call_enter ******************************************************
137 :
138 : Traces an entry into a java method.
139 :
140 : arg_regs: Array containing all argument registers as int64_t values in
141 : the same order as listed in m->methoddesc. The array is usually allocated
142 : on the stack and used for restoring the argument registers later.
143 :
144 : stack: Pointer to first on stack argument in the same format passed to
145 : asm_vm_call_method.
146 :
147 : *******************************************************************************/
148 :
149 0 : void trace_java_call_enter(methodinfo *m, uint64_t *arg_regs, uint64_t *stack)
150 : {
151 : methoddesc *md;
152 : imm_union arg;
153 : s4 i;
154 :
155 : /* We can only trace "slow" builtin functions (those with a stub)
156 : * here, because the argument passing of "fast" ones happens via
157 : * the native ABI and does not fit these functions. */
158 :
159 0 : if (method_is_builtin(m)) {
160 0 : if (!opt_TraceBuiltinCalls)
161 0 : return;
162 : }
163 : else {
164 0 : if (!opt_TraceJavaCalls)
165 0 : return;
166 : #if defined(ENABLE_DEBUG_FILTER)
167 0 : if (!show_filters_test_verbosecall_enter(m))
168 0 : return;
169 : #endif
170 : }
171 :
172 : // Hook point on entry into Java method.
173 0 : Hook::method_enter(m);
174 :
175 0 : md = m->parseddesc;
176 :
177 : // Create new dump memory area.
178 : // DumpMemoryArea dma;
179 :
180 0 : Buffer<> logtext(128);
181 :
182 0 : TRACEJAVACALLCOUNT++;
183 :
184 0 : logtext.writef("%10d ", TRACEJAVACALLCOUNT);
185 0 : logtext.writef("-%d-", TRACEJAVACALLINDENT);
186 :
187 0 : for (i = 0; i < TRACEJAVACALLINDENT; i++)
188 0 : logtext.write("\t");
189 :
190 0 : logtext.write("called: ");
191 :
192 0 : if (m->clazz != NULL)
193 0 : logtext.write_slash_to_dot(m->clazz->name);
194 : else
195 0 : logtext.write("NULL");
196 0 : logtext.write(".");
197 0 : logtext.write(m->name);
198 0 : logtext.write(m->descriptor);
199 :
200 0 : if (m->flags & ACC_PUBLIC) logtext.write(" PUBLIC");
201 0 : if (m->flags & ACC_PRIVATE) logtext.write(" PRIVATE");
202 0 : if (m->flags & ACC_PROTECTED) logtext.write(" PROTECTED");
203 0 : if (m->flags & ACC_STATIC) logtext.write(" STATIC");
204 0 : if (m->flags & ACC_FINAL) logtext.write(" FINAL");
205 0 : if (m->flags & ACC_SYNCHRONIZED) logtext.write(" SYNCHRONIZED");
206 0 : if (m->flags & ACC_VOLATILE) logtext.write(" VOLATILE");
207 0 : if (m->flags & ACC_TRANSIENT) logtext.write(" TRANSIENT");
208 0 : if (m->flags & ACC_NATIVE) logtext.write(" NATIVE");
209 0 : if (m->flags & ACC_INTERFACE) logtext.write(" INTERFACE");
210 0 : if (m->flags & ACC_ABSTRACT) logtext.write(" ABSTRACT");
211 :
212 0 : logtext.write("(");
213 :
214 0 : for (i = 0; i < md->paramcount; ++i) {
215 0 : arg = argument_jitarray_load(md, i, arg_regs, stack);
216 0 : trace_java_call_print_argument(logtext, m, &md->paramtypes[i], arg);
217 :
218 0 : if (i != (md->paramcount - 1)) {
219 0 : logtext.write(", ");
220 : }
221 : }
222 :
223 0 : logtext.write(")");
224 :
225 0 : log_text(logtext.c_str());
226 :
227 0 : TRACEJAVACALLINDENT++;
228 : }
229 :
230 : /* trace_java_call_exit ********************************************************
231 :
232 : Traces an exit form a java method.
233 :
234 : return_regs: Array of size 1 containing return register.
235 : The array is usually allocated on the stack and used for restoring the
236 : registers later.
237 :
238 : *******************************************************************************/
239 :
240 0 : void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
241 : {
242 : methoddesc *md;
243 : s4 i;
244 : imm_union val;
245 :
246 : /* We can only trace "slow" builtin functions (those with a stub)
247 : * here, because the argument passing of "fast" ones happens via
248 : * the native ABI and does not fit these functions. */
249 :
250 0 : if (method_is_builtin(m)) {
251 0 : if (!opt_TraceBuiltinCalls)
252 0 : return;
253 : }
254 : else {
255 0 : if (!opt_TraceJavaCalls)
256 0 : return;
257 : #if defined(ENABLE_DEBUG_FILTER)
258 0 : if (!show_filters_test_verbosecall_exit(m))
259 0 : return;
260 : #endif
261 : }
262 :
263 : // Hook point upon exit from Java method.
264 0 : Hook::method_exit(m);
265 :
266 0 : md = m->parseddesc;
267 :
268 : /* outdent the log message */
269 :
270 0 : if (TRACEJAVACALLINDENT)
271 0 : TRACEJAVACALLINDENT--;
272 : else
273 0 : log_text("trace_java_call_exit: WARNING: unmatched unindent");
274 :
275 : // Create new dump memory area.
276 : // DumpMemoryArea dma;
277 :
278 0 : Buffer<> logtext(128);
279 :
280 : /* generate the message */
281 :
282 0 : logtext.write(" ");
283 0 : logtext.writef("-%d-", TRACEJAVACALLINDENT);
284 :
285 0 : for (i = 0; i < TRACEJAVACALLINDENT; i++)
286 0 : logtext.write("\t");
287 :
288 0 : logtext.write("finished: ");
289 0 : if (m->clazz != NULL)
290 0 : logtext.write_slash_to_dot(m->clazz->name);
291 : else
292 0 : logtext.write("NULL");
293 0 : logtext.write(".");
294 0 : logtext.write(m->name);
295 0 : logtext.write(m->descriptor);
296 :
297 0 : if (!IS_VOID_TYPE(md->returntype.type)) {
298 0 : logtext.write("->");
299 0 : val = argument_jitreturn_load(md, return_regs);
300 :
301 0 : trace_java_call_print_argument(logtext, m, &md->returntype, val);
302 : }
303 :
304 0 : log_text(logtext.c_str());
305 : }
306 :
307 :
308 : /* trace_exception *************************************************************
309 :
310 : Traces an exception which is handled by exceptions_handle_exception.
311 :
312 : *******************************************************************************/
313 :
314 0 : void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
315 : {
316 : codeinfo *code;
317 :
318 : // Create new dump memory area.
319 : // DumpMemoryArea dma;
320 :
321 0 : Buffer<> logtext(128);
322 :
323 0 : if (xptr) {
324 0 : logtext.write("Exception ");
325 0 : logtext.write_slash_to_dot(xptr->vftbl->clazz->name);
326 :
327 : } else {
328 0 : logtext.write("Some Throwable");
329 : }
330 :
331 0 : logtext.write(" thrown in ");
332 :
333 0 : if (m) {
334 0 : logtext.write_slash_to_dot(m->clazz->name);
335 0 : logtext.write(".");
336 0 : logtext.write(m->name);
337 0 : logtext.write(m->descriptor);
338 :
339 0 : if (m->flags & ACC_SYNCHRONIZED)
340 0 : logtext.write("(SYNC");
341 : else
342 0 : logtext.write("(NOSYNC");
343 :
344 0 : if (m->flags & ACC_NATIVE) {
345 0 : logtext.write(",NATIVE");
346 :
347 0 : code = m->code;
348 :
349 : logtext.write(")(").write_ptr(code->entrypoint)
350 0 : .write(") at position ").write_ptr(pos);
351 : } else {
352 :
353 : /* XXX preliminary: This should get the actual codeinfo */
354 : /* in which the exception happened. */
355 0 : code = m->code;
356 :
357 : logtext.write(")(").write_ptr(code->entrypoint)
358 0 : .write(") at position ").write_ptr(pos);
359 :
360 0 : if (m->clazz->sourcefile == NULL)
361 0 : logtext.write("<NO CLASSFILE INFORMATION>");
362 : else
363 0 : logtext.write(m->clazz->sourcefile);
364 :
365 0 : logtext.writef(":%d)", 0);
366 : }
367 :
368 : } else
369 0 : logtext.write("call_java_method");
370 :
371 0 : log_text(logtext.c_str());
372 0 : }
373 :
374 :
375 : /* trace_exception_builtin *****************************************************
376 :
377 : Traces an exception which is thrown by builtin_throw_exception.
378 :
379 : *******************************************************************************/
380 :
381 0 : void trace_exception_builtin(java_handle_t* h)
382 : {
383 0 : java_lang_Throwable jlt(h);
384 :
385 : // Get detail message.
386 0 : java_handle_t* s = NULL;
387 :
388 0 : if (jlt.get_handle() != NULL)
389 0 : s = jlt.get_detailMessage();
390 :
391 0 : java_lang_String jls(s);
392 :
393 : // Create new dump memory area.
394 : // DumpMemoryArea dma;
395 :
396 0 : Buffer<> logtext(128);
397 :
398 0 : logtext.write("Builtin exception thrown: ");
399 :
400 0 : if (jlt.get_handle()) {
401 0 : logtext.write_slash_to_dot(jlt.get_vftbl()->clazz->name);
402 :
403 0 : if (s) {
404 0 : logtext.write(": ");
405 0 : logtext.write(JavaString(jls.get_handle()));
406 : }
407 :
408 : } else {
409 0 : logtext.write("(nil)");
410 : }
411 :
412 0 : log_text(logtext.c_str());
413 0 : }
414 :
415 : #endif /* !defined(NDEBUG) */
416 :
417 :
418 : /*
419 : * These are local overrides for various environment variables in Emacs.
420 : * Please do not remove this and leave it at the end of the file, where
421 : * Emacs will automagically detect them.
422 : * ---------------------------------------------------------------------
423 : * Local variables:
424 : * mode: c++
425 : * indent-tabs-mode: t
426 : * c-basic-offset: 4
427 : * tab-width: 4
428 : * End:
429 : * vim:noexpandtab:sw=4:ts=4:
430 : */
|