* src/vm/breakpoint.hpp: Added header file for breakpoint handling.
authorMichael Starzinger <michi@complang.tuwien.ac.at>
Sat, 19 Sep 2009 21:18:25 +0000 (23:18 +0200)
committerMichael Starzinger <michi@complang.tuwien.ac.at>
Sat, 19 Sep 2009 21:18:25 +0000 (23:18 +0200)
* 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.

12 files changed:
src/vm/Makefile.am
src/vm/breakpoint.hpp [new file with mode: 0644]
src/vm/jit/allocator/simplereg.c
src/vm/jit/codegen-common.cpp
src/vm/jit/ir/icmd.hpp
src/vm/jit/ir/icmdtable.inc
src/vm/jit/parse.cpp
src/vm/jit/patcher-common.cpp
src/vm/jit/patcher-common.hpp
src/vm/jit/stack.c
src/vm/method.cpp
src/vm/method.hpp

index 7830a5a19c566886a09d5b37f318c04a3d420c58..f443c78cd29ae33b26822dbd801abeb94ad08b04 100644 (file)
@@ -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 (file)
index 0000000..2b6db25
--- /dev/null
@@ -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 <map>
+
+
+/**
+ * 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<int32_t, Breakpoint> _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:
+ */
index ed0b5736e245501b8ec1f3c83188304c7a06ee3b..0d386b8086495a53a9e0f00bf57edc1b4ab00e84 100644 (file)
@@ -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:
index 9920715b1c8d52b982c87f1cebc4db25c39afada..62ee9aecdda1f8cf582f5c8535bd9e4c2f00ab78 100644 (file)
@@ -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:
 
index 34557be37b86cca6828bb6130f0f928bb44f3e82..613f76289ceb13ccdf82b06089df07e9adb6d4f9 100644 (file)
@@ -300,7 +300,8 @@ enum {
 
        /* 200 */
        /* 201 */
-       /* 202 */
+
+       ICMD_BREAKPOINT       = BC_breakpoint,
 
        ICMD_IASTORECONST     = 204,
        ICMD_LASTORECONST     = 205,
index 4b0639cdcacf46728e7e4f977dba6e6d24b2a534..2d2dadc263f1288a116c1687e48a1f6f33434aef 100644 (file)
 /*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--)               */},
index 49fa5c2bcd570c4c86b609b12327a378b35c6059..c894d47d9b436f36f01722a5a926f9ae440c7321 100644 (file)
@@ -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
index 5992bea1f0c4d067639d6344ede5dd03407b884a..216b4fc856f6cb3e7acef6d458c5703146ca262f 100644 (file)
@@ -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.
 
 #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
index 159c6f5aa9e9ad53fdb023836c0ce21c8a153732..d4a920339111437721b1703e801d809fc5f3d8ec 100644 (file)
@@ -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);
index 592ce154418c99a0939ffeac01444d4b21555090..3b3828cf5bbb83448900ee0b941a6684903b0e2f 100644 (file)
@@ -2337,6 +2337,10 @@ icmd_NOP:
                                                sd.jd->returnblock = sd.bptr;
                                                break;
 
+                                       case ICMD_BREAKPOINT:
+                                               OP0_0;
+                                               break;
+
 
                                                /* pop 0 push 1 const */
 
index 4a166020146d006377d38f33694cbeffd02b347e..6e7827f2d8a75d9645b78e8ebcb87f632ac7ea2f 100644 (file)
@@ -559,6 +559,9 @@ void method_free(methodinfo *m)
                        CompilerStub::remove(m->stubroutine);
                }
        }
+
+       if (m->breakpoints)
+               delete m->breakpoints;
 }
 
 
index 6fbc0c153d9a71e6d6020230a41eae21fcee2965..7d3b81a475b9bea710b62779a1812bcd2d4ab3a0 100644 (file)
@@ -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