From: Michael Starzinger Date: Sat, 19 Sep 2009 21:18:25 +0000 (+0200) Subject: * src/vm/breakpoint.hpp: Added header file for breakpoint handling. X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=cacao.git;a=commitdiff_plain;h=32c007e8b0b9ab31ddb0c30d7aa0428546d1dffd * src/vm/breakpoint.hpp: Added header file for breakpoint handling. * src/vm/Makefile.am (libvm_la_SOURCES): Added above file. * src/vm/method.hpp (methodinfo): Added pointer to breakpoint table. * src/vm/method.cpp (method_free): Frees breakpoint table if present. * src/vm/jit/patcher-common.cpp (patcher_breakpoint): Added patcher method. * src/vm/jit/patcher-common.hpp: Likewise. * src/vm/jit/ir/icmd.hpp (ICMD_BREAKPOINT): Added. * src/vm/jit/ir/icmdtable.inc: Adapted entry for above ICMD. * src/vm/jit/parse.cpp (parse): Generate breakpoints if requested. * src/vm/jit/stack.c: Correctly handles ICMD_BREAKPOINT. * src/vm/jit/allocator/simplereg.c: Likewise. * src/vm/jit/codegen-common.cpp (codegen_emit): Generate ICMD_BREAKPOINT code. --- diff --git a/src/vm/Makefile.am b/src/vm/Makefile.am index 7830a5a19..f443c78cd 100644 --- a/src/vm/Makefile.am +++ b/src/vm/Makefile.am @@ -83,6 +83,7 @@ libvm_la_SOURCES = \ array.cpp \ array.hpp \ $(ASSERTION_SOURCES) \ + breakpoint.hpp \ class.cpp \ class.hpp \ classcache.cpp \ diff --git a/src/vm/breakpoint.hpp b/src/vm/breakpoint.hpp new file mode 100644 index 000000000..2b6db25cf --- /dev/null +++ b/src/vm/breakpoint.hpp @@ -0,0 +1,120 @@ +/* src/vm/breakpoint.hpp - breakpoint handling header + + Copyright (C) 2009 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + */ + + +#ifndef _BREAKPOINT_HPP +#define _BREAKPOINT_HPP + +#include "config.h" + +#ifdef __cplusplus +#include + + +/** + * This structure contains information about a breakpoint. Feel + * free to extend it to hold all the information you need. It is + * the responsibility of the user to set the fields accordingly. + */ +typedef struct Breakpoint { + bool is_oneshot; ///< Indicates a "one-shot". + +#if defined(ENABLE_JVMTI) + int32_t location; ///< Used for JVMTI breakpoints. + methodinfo* method; ///< Used for JVMTI breakpoints. +#endif +} Breakpoint; + + +/** + * This class is used to record breakpoints in the methodinfo + * structure. The term "location" is used to refer to the bytecode + * index at which the breakpoint should be placed. + */ +class BreakpointTable { +private: + std::map _breakpoints; + +public: + // Querying operations. + bool is_empty(); + bool contains(int32_t location); + + // Modification operations. + Breakpoint* add_breakpoint (int32_t location); + Breakpoint* get_breakpoint (int32_t location); + void remove_breakpoint(int32_t location); +}; + + +inline bool BreakpointTable::is_empty() +{ + return _breakpoints.empty(); +} + +inline bool BreakpointTable::contains(int32_t location) +{ + return (_breakpoints.find(location) != _breakpoints.end()); +} + +inline Breakpoint* BreakpointTable::add_breakpoint(int32_t location) +{ + assert(!contains(location)); + _breakpoints.insert(std::make_pair(location, Breakpoint())); + return &(_breakpoints.find(location)->second); +} + +inline Breakpoint* BreakpointTable::get_breakpoint(int32_t location) +{ + assert(contains(location)); + return &(_breakpoints.find(location)->second); +} + +inline void BreakpointTable::remove_breakpoint(int32_t location) +{ + assert(contains(location)); + _breakpoints.erase(location); +} + + +#else // __cplusplus +typedef struct BreakpointTable BreakpointTable; +#endif // __cplusplus + +#endif /* _BREAKPOINT_HPP */ + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c++ + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/allocator/simplereg.c b/src/vm/jit/allocator/simplereg.c index ed0b5736e..0d386b808 100644 --- a/src/vm/jit/allocator/simplereg.c +++ b/src/vm/jit/allocator/simplereg.c @@ -1370,6 +1370,7 @@ static void simplereg_allocate_temporaries(jitdata *jd) case ICMD_RET: case ICMD_RETURN: case ICMD_GOTO: + case ICMD_BREAKPOINT: case ICMD_PUTSTATICCONST: case ICMD_INLINE_START: case ICMD_INLINE_END: diff --git a/src/vm/jit/codegen-common.cpp b/src/vm/jit/codegen-common.cpp index 9920715b1..62ee9aecd 100644 --- a/src/vm/jit/codegen-common.cpp +++ b/src/vm/jit/codegen-common.cpp @@ -1250,6 +1250,13 @@ bool codegen_emit(jitdata *jd) emit_nullpointer_check(cd, iptr, s1); break; + case ICMD_BREAKPOINT: /* ... ==> ... */ + /* sx.val.anyptr = Breakpoint */ + + patcher_add_patch_ref(jd, PATCHER_breakpoint, iptr->sx.val.anyptr, 0); + PATCHER_NOPS; + break; + #if defined(ENABLE_SSA) case ICMD_GETEXCEPTION: diff --git a/src/vm/jit/ir/icmd.hpp b/src/vm/jit/ir/icmd.hpp index 34557be37..613f76289 100644 --- a/src/vm/jit/ir/icmd.hpp +++ b/src/vm/jit/ir/icmd.hpp @@ -300,7 +300,8 @@ enum { /* 200 */ /* 201 */ - /* 202 */ + + ICMD_BREAKPOINT = BC_breakpoint, ICMD_IASTORECONST = 204, ICMD_LASTORECONST = 205, diff --git a/src/vm/jit/ir/icmdtable.inc b/src/vm/jit/ir/icmdtable.inc index 4b0639cdc..2d2dadc26 100644 --- a/src/vm/jit/ir/icmdtable.inc +++ b/src/vm/jit/ir/icmdtable.inc @@ -253,7 +253,7 @@ /*199*/ {N("IFNONNULL ") DF_1_TO_0 , CF_IF , 0 /* (A--) */}, /*200*/ {N("UNDEF200 ") DF_0_TO_0 , CF_NORMAL, 0 /* -- () */}, /*201*/ {N("UNDEF201 ") DF_0_TO_0 , CF_NORMAL, 0 /* -- () */}, -/*202*/ {N("UNDEF202 ") DF_0_TO_0 , CF_NORMAL, 0 /* -- () */}, +/*202*/ {N("BREAKPOINT ") DF_0_TO_0 , CF_NORMAL, 0 /* (--) */}, /*203*/ {N("UNDEF203 ") DF_0_TO_0 , CF_NORMAL, 0 /* -- () */}, /*204*/ {N("IASTORECONST ") DF_2_TO_0 , CF_NORMAL, PEI /* S+ (AI--) */}, /*205*/ {N("LASTORECONST ") DF_2_TO_0 , CF_NORMAL, PEI /* S+ (AI--) */}, diff --git a/src/vm/jit/parse.cpp b/src/vm/jit/parse.cpp index 49fa5c2bc..c894d47d9 100644 --- a/src/vm/jit/parse.cpp +++ b/src/vm/jit/parse.cpp @@ -1,6 +1,6 @@ /* src/vm/jit/parse.c - parser for JavaVM to intermediate code translation - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -534,6 +534,17 @@ fetch_opcode: s_count += bytecode[opcode].slots; + /* Generate a breakpoint instruction right before the actual + instruction, if the method contains a breakpoint at the + current bytecode index. */ + + if (m->breakpoints != NULL && m->breakpoints->contains(bcindex)) { + INSTRUCTIONS_CHECK(1); + OP_PREPARE_ZEROFLAGS(ICMD_BREAKPOINT); + iptr->sx.val.anyptr = m->breakpoints->get_breakpoint(bcindex); + PINC; + } + /* We check here for the space of 1 instruction in the instruction array. If an opcode is converted to more than 1 instruction, this is checked in the corresponding diff --git a/src/vm/jit/patcher-common.cpp b/src/vm/jit/patcher-common.cpp index 5992bea1f..216b4fc85 100644 --- a/src/vm/jit/patcher-common.cpp +++ b/src/vm/jit/patcher-common.cpp @@ -1,6 +1,6 @@ /* src/vm/jit/patcher-common.cpp - architecture independent code patching stuff - Copyright (C) 2007, 2008 + Copyright (C) 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO Copyright (C) 2008 Theobroma Systems Ltd. @@ -43,11 +43,12 @@ #include "toolbox/list.hpp" #include "toolbox/logging.hpp" /* XXX remove me! */ +#include "vm/breakpoint.hpp" #include "vm/exceptions.hpp" #include "vm/initialize.hpp" #include "vm/options.h" +#include "vm/os.hpp" #include "vm/resolve.hpp" -#include "vm/vm.hpp" /* for vm_abort */ #include "vm/jit/code.hpp" #include "vm/jit/disass.h" @@ -78,6 +79,7 @@ static patcher_function_list_t patcher_function_list[] = { { PATCHER_invokestatic_special, "invokestatic_special" }, { PATCHER_invokevirtual, "invokevirtual" }, { PATCHER_invokeinterface, "invokeinterface" }, + { PATCHER_breakpoint, "breakpoint" }, { NULL, "-UNKNOWN PATCHER FUNCTION-" } }; #endif @@ -226,7 +228,7 @@ void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp) #if !defined(NDEBUG) if (patcher_list_find(code, (void*) (intptr_t) patchmpc) != NULL) - vm_abort("patcher_add_patch_ref: different patchers at same position."); + os::abort("patcher_add_patch_ref: different patchers at same position."); #endif // Set patcher information (mpc is resolved later). @@ -380,7 +382,7 @@ java_handle_t *patcher_handler(u1 *pc) pr = patcher_list_find(code, pc); if (pr == NULL) - vm_abort("patcher_handler: Unable to find patcher reference."); + os::abort("patcher_handler: Unable to find patcher reference."); if (pr->done) { #if !defined(NDEBUG) @@ -564,6 +566,36 @@ bool patcher_resolve_native_function(patchref_t *pr) } +/** + * Deals with breakpoint instructions (ICMD_BREAKPOINT) compiled + * into a JIT method. This patcher might never patch back the + * original machine code because breakpoints are kept active. + */ +bool patcher_breakpoint(patchref_t *pr) +{ + // Get stuff from the patcher reference. + Breakpoint* breakp = (Breakpoint*) pr->ref; + +#if defined(ENABLE_JVMTI) + methodinfo* m = breakp->method; + int32_t l = breakp->location; + + log_message_method("JVMTI: Reached breakpoint in method ", m); + log_println("JVMTI: Reached breakpoint at location %d", l); +#endif + + // In case the breakpoint wants to be kept active, we simply + // fail to "patch" at this point. + if (!breakp->is_oneshot) + return false; + + // Patch back original code. + patcher_patch_code(pr); + + return true; +} + + /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where diff --git a/src/vm/jit/patcher-common.hpp b/src/vm/jit/patcher-common.hpp index 159c6f5aa..d4a920339 100644 --- a/src/vm/jit/patcher-common.hpp +++ b/src/vm/jit/patcher-common.hpp @@ -1,6 +1,6 @@ /* src/vm/jit/patcher-common.hpp - architecture independent code patching stuff - Copyright (C) 2007, 2008 + Copyright (C) 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -118,6 +118,9 @@ bool patcher_resolve_classref_to_flags(patchref_t *pr); bool patcher_resolve_native_function(patchref_t *pr); #define PATCHER_resolve_native_function (functionptr) patcher_resolve_native_function +bool patcher_breakpoint(patchref_t *pr); +#define PATCHER_breakpoint (functionptr) patcher_breakpoint + /* old patcher functions */ bool patcher_get_putstatic(patchref_t *pr); diff --git a/src/vm/jit/stack.c b/src/vm/jit/stack.c index 592ce1544..3b3828cf5 100644 --- a/src/vm/jit/stack.c +++ b/src/vm/jit/stack.c @@ -2337,6 +2337,10 @@ icmd_NOP: sd.jd->returnblock = sd.bptr; break; + case ICMD_BREAKPOINT: + OP0_0; + break; + /* pop 0 push 1 const */ diff --git a/src/vm/method.cpp b/src/vm/method.cpp index 4a1660201..6e7827f2d 100644 --- a/src/vm/method.cpp +++ b/src/vm/method.cpp @@ -559,6 +559,9 @@ void method_free(methodinfo *m) CompilerStub::remove(m->stubroutine); } } + + if (m->breakpoints) + delete m->breakpoints; } diff --git a/src/vm/method.hpp b/src/vm/method.hpp index 6fbc0c153..7d3b81a47 100644 --- a/src/vm/method.hpp +++ b/src/vm/method.hpp @@ -40,6 +40,7 @@ typedef struct codeinfo codeinfo; #include "threads/mutex.hpp" +#include "vm/breakpoint.hpp" #include "vm/jit/builtin.hpp" #include "vm/descriptor.hpp" #include "vm/global.h" @@ -100,6 +101,8 @@ struct methodinfo { /* method structure */ methodinfo *overwrites; /* method that is directly overwritten */ method_assumption *assumptions; /* list of assumptions about this method */ + BreakpointTable* breakpoints; /* breakpoints in this method */ + #if defined(ENABLE_REPLACEMENT) s4 hitcountdown; /* decreased for each hit */ #endif