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 : default:
130 0 : assert(false);
131 : break;
132 : }
133 0 : }
134 :
135 : /* trace_java_call_enter ******************************************************
136 :
137 : Traces an entry into a java method.
138 :
139 : arg_regs: Array containing all argument registers as int64_t values in
140 : the same order as listed in m->methoddesc. The array is usually allocated
141 : on the stack and used for restoring the argument registers later.
142 :
143 : stack: Pointer to first on stack argument in the same format passed to
144 : asm_vm_call_method.
145 :
146 : *******************************************************************************/
147 :
148 0 : void trace_java_call_enter(methodinfo *m, uint64_t *arg_regs, uint64_t *stack)
149 : {
150 : methoddesc *md;
151 : imm_union arg;
152 : s4 i;
153 :
154 : /* We can only trace "slow" builtin functions (those with a stub)
155 : * here, because the argument passing of "fast" ones happens via
156 : * the native ABI and does not fit these functions. */
157 :
158 0 : if (method_is_builtin(m)) {
159 0 : if (!opt_TraceBuiltinCalls)
160 0 : return;
161 : }
162 : else {
163 0 : if (!opt_TraceJavaCalls)
164 0 : return;
165 : #if defined(ENABLE_DEBUG_FILTER)
166 0 : if (!show_filters_test_verbosecall_enter(m))
167 0 : return;
168 : #endif
169 : }
170 :
171 : // Hook point on entry into Java method.
172 0 : Hook::method_enter(m);
173 :
174 0 : md = m->parseddesc;
175 :
176 : // Create new dump memory area.
177 : // DumpMemoryArea dma;
178 :
179 0 : Buffer<> logtext(128);
180 :
181 0 : TRACEJAVACALLCOUNT++;
182 :
183 0 : logtext.writef("%10d ", TRACEJAVACALLCOUNT);
184 0 : logtext.writef("-%d-", TRACEJAVACALLINDENT);
185 :
186 0 : for (i = 0; i < TRACEJAVACALLINDENT; i++)
187 0 : logtext.write("\t");
188 :
189 0 : logtext.write("called: ");
190 :
191 0 : if (m->clazz != NULL)
192 0 : logtext.write_slash_to_dot(m->clazz->name);
193 : else
194 0 : logtext.write("NULL");
195 0 : logtext.write(".");
196 0 : logtext.write(m->name);
197 0 : logtext.write(m->descriptor);
198 :
199 0 : if (m->flags & ACC_PUBLIC) logtext.write(" PUBLIC");
200 0 : if (m->flags & ACC_PRIVATE) logtext.write(" PRIVATE");
201 0 : if (m->flags & ACC_PROTECTED) logtext.write(" PROTECTED");
202 0 : if (m->flags & ACC_STATIC) logtext.write(" STATIC");
203 0 : if (m->flags & ACC_FINAL) logtext.write(" FINAL");
204 0 : if (m->flags & ACC_SYNCHRONIZED) logtext.write(" SYNCHRONIZED");
205 0 : if (m->flags & ACC_VOLATILE) logtext.write(" VOLATILE");
206 0 : if (m->flags & ACC_TRANSIENT) logtext.write(" TRANSIENT");
207 0 : if (m->flags & ACC_NATIVE) logtext.write(" NATIVE");
208 0 : if (m->flags & ACC_INTERFACE) logtext.write(" INTERFACE");
209 0 : if (m->flags & ACC_ABSTRACT) logtext.write(" ABSTRACT");
210 :
211 0 : logtext.write("(");
212 :
213 0 : for (i = 0; i < md->paramcount; ++i) {
214 0 : arg = argument_jitarray_load(md, i, arg_regs, stack);
215 0 : trace_java_call_print_argument(logtext, m, &md->paramtypes[i], arg);
216 :
217 0 : if (i != (md->paramcount - 1)) {
218 0 : logtext.write(", ");
219 : }
220 : }
221 :
222 0 : logtext.write(")");
223 :
224 0 : log_text(logtext.c_str());
225 :
226 0 : TRACEJAVACALLINDENT++;
227 : }
228 :
229 : /* trace_java_call_exit ********************************************************
230 :
231 : Traces an exit form a java method.
232 :
233 : return_regs: Array of size 1 containing return register.
234 : The array is usually allocated on the stack and used for restoring the
235 : registers later.
236 :
237 : *******************************************************************************/
238 :
239 0 : void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
240 : {
241 : methoddesc *md;
242 : s4 i;
243 : imm_union val;
244 :
245 : /* We can only trace "slow" builtin functions (those with a stub)
246 : * here, because the argument passing of "fast" ones happens via
247 : * the native ABI and does not fit these functions. */
248 :
249 0 : if (method_is_builtin(m)) {
250 0 : if (!opt_TraceBuiltinCalls)
251 0 : return;
252 : }
253 : else {
254 0 : if (!opt_TraceJavaCalls)
255 0 : return;
256 : #if defined(ENABLE_DEBUG_FILTER)
257 0 : if (!show_filters_test_verbosecall_exit(m))
258 0 : return;
259 : #endif
260 : }
261 :
262 : // Hook point upon exit from Java method.
263 0 : Hook::method_exit(m);
264 :
265 0 : md = m->parseddesc;
266 :
267 : /* outdent the log message */
268 :
269 0 : if (TRACEJAVACALLINDENT)
270 0 : TRACEJAVACALLINDENT--;
271 : else
272 0 : log_text("trace_java_call_exit: WARNING: unmatched unindent");
273 :
274 : // Create new dump memory area.
275 : // DumpMemoryArea dma;
276 :
277 0 : Buffer<> logtext(128);
278 :
279 : /* generate the message */
280 :
281 0 : logtext.write(" ");
282 0 : logtext.writef("-%d-", TRACEJAVACALLINDENT);
283 :
284 0 : for (i = 0; i < TRACEJAVACALLINDENT; i++)
285 0 : logtext.write("\t");
286 :
287 0 : logtext.write("finished: ");
288 0 : if (m->clazz != NULL)
289 0 : logtext.write_slash_to_dot(m->clazz->name);
290 : else
291 0 : logtext.write("NULL");
292 0 : logtext.write(".");
293 0 : logtext.write(m->name);
294 0 : logtext.write(m->descriptor);
295 :
296 0 : if (!IS_VOID_TYPE(md->returntype.type)) {
297 0 : logtext.write("->");
298 0 : val = argument_jitreturn_load(md, return_regs);
299 :
300 0 : trace_java_call_print_argument(logtext, m, &md->returntype, val);
301 : }
302 :
303 0 : log_text(logtext.c_str());
304 : }
305 :
306 :
307 : /* trace_exception *************************************************************
308 :
309 : Traces an exception which is handled by exceptions_handle_exception.
310 :
311 : *******************************************************************************/
312 :
313 0 : void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
314 : {
315 : codeinfo *code;
316 :
317 : // Create new dump memory area.
318 : // DumpMemoryArea dma;
319 :
320 0 : Buffer<> logtext(128);
321 :
322 0 : if (xptr) {
323 0 : logtext.write("Exception ");
324 0 : logtext.write_slash_to_dot(xptr->vftbl->clazz->name);
325 :
326 : } else {
327 0 : logtext.write("Some Throwable");
328 : }
329 :
330 0 : logtext.write(" thrown in ");
331 :
332 0 : if (m) {
333 0 : logtext.write_slash_to_dot(m->clazz->name);
334 0 : logtext.write(".");
335 0 : logtext.write(m->name);
336 0 : logtext.write(m->descriptor);
337 :
338 0 : if (m->flags & ACC_SYNCHRONIZED)
339 0 : logtext.write("(SYNC");
340 : else
341 0 : logtext.write("(NOSYNC");
342 :
343 0 : if (m->flags & ACC_NATIVE) {
344 0 : logtext.write(",NATIVE");
345 :
346 0 : code = m->code;
347 :
348 : logtext.write(")(").write_ptr(code->entrypoint)
349 0 : .write(") at position ").write_ptr(pos);
350 : } else {
351 :
352 : /* XXX preliminary: This should get the actual codeinfo */
353 : /* in which the exception happened. */
354 0 : code = m->code;
355 :
356 : logtext.write(")(").write_ptr(code->entrypoint)
357 0 : .write(") at position ").write_ptr(pos);
358 :
359 0 : if (m->clazz->sourcefile == NULL)
360 0 : logtext.write("<NO CLASSFILE INFORMATION>");
361 : else
362 0 : logtext.write(m->clazz->sourcefile);
363 :
364 0 : logtext.writef(":%d)", 0);
365 : }
366 :
367 : } else
368 0 : logtext.write("call_java_method");
369 :
370 0 : log_text(logtext.c_str());
371 0 : }
372 :
373 :
374 : /* trace_exception_builtin *****************************************************
375 :
376 : Traces an exception which is thrown by builtin_throw_exception.
377 :
378 : *******************************************************************************/
379 :
380 0 : void trace_exception_builtin(java_handle_t* h)
381 : {
382 0 : java_lang_Throwable jlt(h);
383 :
384 : // Get detail message.
385 0 : java_handle_t* s = NULL;
386 :
387 0 : if (jlt.get_handle() != NULL)
388 0 : s = jlt.get_detailMessage();
389 :
390 0 : java_lang_String jls(s);
391 :
392 : // Create new dump memory area.
393 : // DumpMemoryArea dma;
394 :
395 0 : Buffer<> logtext(128);
396 :
397 0 : logtext.write("Builtin exception thrown: ");
398 :
399 0 : if (jlt.get_handle()) {
400 0 : logtext.write_slash_to_dot(jlt.get_vftbl()->clazz->name);
401 :
402 0 : if (s) {
403 0 : logtext.write(": ");
404 0 : logtext.write(JavaString(jls.get_handle()));
405 : }
406 :
407 : } else {
408 0 : logtext.write("(nil)");
409 : }
410 :
411 0 : log_text(logtext.c_str());
412 0 : }
413 :
414 : #endif /* !defined(NDEBUG) */
415 :
416 :
417 : /*
418 : * These are local overrides for various environment variables in Emacs.
419 : * Please do not remove this and leave it at the end of the file, where
420 : * Emacs will automagically detect them.
421 : * ---------------------------------------------------------------------
422 : * Local variables:
423 : * mode: c++
424 : * indent-tabs-mode: t
425 : * c-basic-offset: 4
426 : * tab-width: 4
427 : * End:
428 : * vim:noexpandtab:sw=4:ts=4:
429 : */
|