# HG changeset patch # User Gary Benson # Date 1222778530 14400 # Node ID 28523a4d7bd62a36b27c25220206ba9d88242ed3 # Parent 9ff3417e28cc80b40fde38781dc77acf509d2eb7 2008-09-30 Gary Benson * patches/icedtea-shark.patch: Updated to latest Shark. * ports/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.hpp: Likewise. * ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp: Likewise. * ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp: Likewise. * ports/hotspot/src/cpu/zero/vm/disassembler_zero.cpp: Likewise. * ports/hotspot/src/cpu/zero/vm/frame_zero.cpp: Likewise. * ports/hotspot/src/cpu/zero/vm/frame_zero.hpp: Likewise. * ports/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp: Likewise. * ports/hotspot/src/cpu/zero/vm/interpreterFrame_zero.hpp: Likewise. * ports/hotspot/src/cpu/zero/vm/interpreter_zero.cpp: Likewise. * ports/hotspot/src/cpu/zero/vm/nativeInst_zero.cpp: Likewise. * ports/hotspot/src/cpu/zero/vm/nativeInst_zero.hpp: Likewise. * ports/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp: Likewise. * ports/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp: Likewise. * ports/hotspot/src/cpu/zero/vm/stackPrinter_zero.hpp: Likewise. * ports/hotspot/src/cpu/zero/vm/stack_zero.hpp: Likewise. * ports/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp: Likewise. * ports/hotspot/src/share/vm/includeDB_shark: Likewise. * ports/hotspot/src/share/vm/shark/sharkBlock.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkBlock.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkBuilder.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkBuilder.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkCompiler.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkCompiler.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkEntry.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkFunction.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkFunction.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkMonitor.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkMonitor.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkRuntime.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkRuntime.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkState.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkState.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkState.inline.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkType.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkValue.hpp: Likewise. * ports/hotspot/src/cpu/zero/vm/deoptimizerFrame_zero.hpp: New file. * ports/hotspot/src/share/vm/shark/sharkBytecodeTracer.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkBytecodeTracer.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkCacheDecache.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkCacheDecache.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkStateScanner.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkStateScanner.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkValue.inline.hpp: Likewise. diff -r 9ff3417e28cc -r 28523a4d7bd6 ChangeLog --- a/ChangeLog Mon Sep 29 12:04:41 2008 -0400 +++ b/ChangeLog Tue Sep 30 08:42:10 2008 -0400 @@ -1,3 +1,52 @@ +2008-09-30 Gary Benson + + * patches/icedtea-shark.patch: Updated to latest Shark. + * ports/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.hpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/disassembler_zero.cpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/frame_zero.cpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/frame_zero.hpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/interpreterFrame_zero.hpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/interpreter_zero.cpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/nativeInst_zero.cpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/nativeInst_zero.hpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/stackPrinter_zero.hpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/stack_zero.hpp: Likewise. + * ports/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp: Likewise. + * ports/hotspot/src/share/vm/includeDB_shark: Likewise. + * ports/hotspot/src/share/vm/shark/sharkBlock.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkBlock.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkBuilder.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkBuilder.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkCompiler.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkCompiler.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkEntry.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkFunction.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkFunction.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkMonitor.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkMonitor.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkRuntime.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkRuntime.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkState.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkState.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkState.inline.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkType.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkValue.hpp: Likewise. + * ports/hotspot/src/cpu/zero/vm/deoptimizerFrame_zero.hpp: New file. + * ports/hotspot/src/share/vm/shark/sharkBytecodeTracer.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkBytecodeTracer.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkCacheDecache.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkCacheDecache.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkStateScanner.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkStateScanner.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkValue.inline.hpp: Likewise. + 2008-09-26 Mark Wielaard * patches/icedtea-6712835-ifnode.patch: New patch. diff -r 9ff3417e28cc -r 28523a4d7bd6 patches/icedtea-shark.patch --- a/patches/icedtea-shark.patch Mon Sep 29 12:04:41 2008 -0400 +++ b/patches/icedtea-shark.patch Tue Sep 30 08:42:10 2008 -0400 @@ -303,3 +303,118 @@ } +diff -r 70711eb56d8e openjdk/hotspot/src/share/vm/ci/ciTypeFlow.hpp +--- openjdk/hotspot/src/share/vm/ci/ciTypeFlow.hpp Mon Sep 29 08:47:58 2008 +0100 ++++ openjdk/hotspot/src/share/vm/ci/ciTypeFlow.hpp Mon Sep 29 08:51:58 2008 +0100 +@@ -94,9 +94,17 @@ public: + private: + GrowableArray* _set; + ++#ifdef SHARK ++ // XXX This can be removed if it turns out we have to deal ++ // with T_ADDRESS values the same as everything else. ++ public: ++#endif // SHARK + JsrRecord* record_at(int i) { + return _set->at(i); + } ++#ifdef SHARK ++ private: ++#endif // SHARK + + // Insert the given JsrRecord into the JsrSet, maintaining the order + // of the set and replacing any element with the same entry address. +@@ -515,6 +523,13 @@ public: + ciType* local_type_at(int i) const { return _state->local_type_at(i); } + ciType* stack_type_at(int i) const { return _state->stack_type_at(i); } + ++ // access to the JSRs ++#ifdef SHARK ++ // XXX This can be removed if it turns out we have to deal ++ // with T_ADDRESS values the same as everything else. ++ JsrSet* jsrset() const { return _jsrs; } ++#endif // SHARK ++ + // Get the successors for this Block. + GrowableArray* successors(ciBytecodeStream* str, + StateVector* state, +diff -r 70711eb56d8e openjdk/hotspot/src/share/vm/runtime/deoptimization.cpp +--- openjdk/hotspot/src/share/vm/runtime/deoptimization.cpp Mon Sep 29 08:47:58 2008 +0100 ++++ openjdk/hotspot/src/share/vm/runtime/deoptimization.cpp Mon Sep 29 08:54:36 2008 +0100 +@@ -217,6 +217,7 @@ Deoptimization::UnrollBlock* Deoptimizat + + } + ++#ifndef SHARK + // Compute the caller frame based on the sender sp of stub_frame and stored frame sizes info. + CodeBlob* cb = stub_frame.cb(); + // Verify we have the right vframeArray +@@ -227,6 +228,10 @@ Deoptimization::UnrollBlock* Deoptimizat + assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking"); + Events::log("fetch unroll sp " INTPTR_FORMAT, unpack_sp); + #endif ++#else ++ intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp(); ++#endif // !SHARK ++ + // This is a guarantee instead of an assert because if vframe doesn't match + // we will unpack the wrong deoptimized frame and wind up in strange places + // where it will be very difficult to figure out what went wrong. Better +@@ -337,7 +342,9 @@ Deoptimization::UnrollBlock* Deoptimizat + + frame_pcs[0] = deopt_sender.raw_pc(); + ++#ifndef SHARK + assert(CodeCache::find_blob_unsafe(frame_pcs[0]) != NULL, "bad pc"); ++#endif // SHARK + + UnrollBlock* info = new UnrollBlock(array->frame_size() * BytesPerWord, + caller_adjustment * BytesPerWord, +@@ -832,7 +839,20 @@ vframeArray* Deoptimization::create_vfra + // stuff a C2I adapter we can properly fill in the callee-save + // register locations. + frame caller = fr.sender(reg_map); ++#ifdef ZERO ++ int frame_size; ++ { ++ // In zero, frame::sp() is the *end* of the frame, so ++ // caller.sp() - fr.sp() is the size of the *caller*. ++ RegisterMap dummy_map(thread, false); ++ frame frame_1 = thread->last_frame(); ++ frame frame_2 = frame_1.sender(&dummy_map); ++ assert(frame_2.sp() == fr.sp(), "should be"); ++ frame_size = frame_2.sp() - frame_1.sp(); ++ } ++#else + int frame_size = caller.sp() - fr.sp(); ++#endif // ZERO + + frame sender = caller; + +diff -r 70711eb56d8e openjdk/hotspot/src/share/vm/runtime/vframeArray.cpp +--- openjdk/hotspot/src/share/vm/runtime/vframeArray.cpp Mon Sep 29 08:47:58 2008 +0100 ++++ openjdk/hotspot/src/share/vm/runtime/vframeArray.cpp Mon Sep 29 08:56:26 2008 +0100 +@@ -64,6 +64,11 @@ void vframeArrayElement::fill_in(compile + assert(monitor->owner() == NULL || (!monitor->owner()->is_unlocked() && !monitor->owner()->has_bias_pattern()), "object must be null or locked, and unbiased"); + BasicObjectLock* dest = _monitors->at(index); + dest->set_obj(monitor->owner()); ++#ifdef SHARK ++ // XXX This can be removed when Shark knows ++ // which monitors are in use. ++ if (monitor->owner()) ++#endif // SHARK + monitor->lock()->move_to(monitor->owner(), dest->lock()); + } + } +@@ -262,6 +267,11 @@ void vframeArrayElement::unpack_on_stack + top = iframe()->previous_monitor_in_interpreter_frame(top); + BasicObjectLock* src = _monitors->at(index); + top->set_obj(src->obj()); ++#ifdef SHARK ++ // XXX This can be removed when Shark knows ++ // which monitors are in use. ++ if (src->obj()) ++#endif // SHARK + src->lock()->move_to(src->obj(), top->lock()); + } + if (ProfileInterpreter) { diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.hpp --- a/ports/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -43,6 +43,10 @@ { _method = new_method; } + inline interpreterState self_link() + { + return _self_link; + } inline void set_self_link(interpreterState new_self_link) { _self_link = new_self_link; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -56,7 +56,24 @@ // Allocate and initialize our frame. InterpreterFrame *frame = InterpreterFrame::build(stack, method, thread); thread->push_zero_frame(frame); + + // Execute those bytecodes! + main_loop(0, THREAD); +} + +void CppInterpreter::main_loop(int recurse, TRAPS) +{ + JavaThread *thread = (JavaThread *) THREAD; + ZeroStack *stack = thread->zero_stack(); + + // If we are entering from a deopt we may need to call + // ourself a few times in order to get to our frame. + if (recurse) + main_loop(recurse - 1, THREAD); + + InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame(); interpreterState istate = frame->interpreter_state(); + methodOop method = istate->method(); intptr_t *result = NULL; int result_slots = 0; @@ -79,13 +96,13 @@ // Examine the message from the interpreter to decide what to do if (istate->msg() == BytecodeInterpreter::call_method) { - method = istate->callee(); + methodOop callee = istate->callee(); // Trim back the stack to put the parameters at the top stack->set_sp(istate->stack() + 1); // Make the call - Interpreter::invoke_method(method, istate->callee_entry_point(), THREAD); + Interpreter::invoke_method(callee, istate->callee_entry_point(), THREAD); fixup_after_potential_safepoint(); // Convert the result @@ -95,7 +112,6 @@ stack->set_sp(istate->stack_limit() + 1); // Resume the interpreter - method = istate->method(); istate->set_msg(BytecodeInterpreter::method_resume); } else if (istate->msg() == BytecodeInterpreter::more_monitors) { @@ -689,26 +705,123 @@ generate_all(); } -// Helper for (runtime) stack overflow checks +// Deoptimization helpers -int AbstractInterpreter::size_top_interpreter_activation(methodOop method) +InterpreterFrame *InterpreterFrame::build(ZeroStack* stack, int size) { - return 0; + int size_in_words = size >> LogBytesPerWord; + assert(size_in_words * wordSize == size, "unaligned"); + assert(size_in_words >= header_words, "too small"); + + if (size_in_words > stack->available_words()) { + Unimplemented(); + } + + stack->push(0); // next_frame, filled in later + intptr_t *fp = stack->sp(); + assert(fp - stack->sp() == next_frame_off, "should be"); + + stack->push(INTERPRETER_FRAME); + assert(fp - stack->sp() == frame_type_off, "should be"); + + interpreterState istate = + (interpreterState) stack->alloc(sizeof(BytecodeInterpreter)); + assert(fp - stack->sp() == istate_off, "should be"); + istate->set_self_link(NULL); // mark invalid + + stack->alloc((size_in_words - header_words) * wordSize); + + return (InterpreterFrame *) fp; } -// Deoptimization helpers for C++ interpreter - int AbstractInterpreter::layout_activation(methodOop method, - int tempcount, - int popframe_extra_args, - int moncount, - int callee_param_count, - int callee_locals, - frame* caller, - frame* interpreter_frame, - bool is_top_frame) + int tempcount, + int popframe_extra_args, + int moncount, + int callee_param_count, + int callee_locals, + frame* caller, + frame* interpreter_frame, + bool is_top_frame) { - Unimplemented(); + assert(popframe_extra_args == 0, "what to do?"); + assert(!is_top_frame || (!callee_locals && !callee_param_count), + "top frame should have no caller") + + // This code must exactly match what InterpreterFrame::build + // does (the full InterpreterFrame::build, that is, not the + // one that creates empty frames for the deoptimizer). + // + // If interpreter_frame is not NULL then it will be filled in. + // It's size is determined by a previous call to this method, + // so it should be correct. + // + // Note that tempcount is the current size of the expression + // stack. For top most frames we will allocate a full sized + // expression stack and not the trimmed version that non-top + // frames have. + + int header_words = InterpreterFrame::header_words; + int monitor_words = moncount * frame::interpreter_frame_monitor_size(); + int stack_words = is_top_frame ? method->max_stack() : tempcount; + int callee_extra_locals = callee_locals - callee_param_count; + + if (interpreter_frame) { + intptr_t *locals = interpreter_frame->sp() + method->max_locals(); + interpreterState istate = interpreter_frame->get_interpreterState(); + intptr_t *monitor_base = (intptr_t*) istate; + intptr_t *stack_base = monitor_base - monitor_words; + intptr_t *stack = stack_base - tempcount - 1; + + BytecodeInterpreter::layout_interpreterState(istate, + caller, + NULL, + method, + locals, + stack, + stack_base, + monitor_base, + NULL, + is_top_frame); + } + return header_words + monitor_words + stack_words + callee_extra_locals; +} + +void BytecodeInterpreter::layout_interpreterState(interpreterState istate, + frame* caller, + frame* current, + methodOop method, + intptr_t* locals, + intptr_t* stack, + intptr_t* stack_base, + intptr_t* monitor_base, + intptr_t* frame_bottom, + bool is_top_frame) +{ + istate->set_locals(locals); + istate->set_method(method); + istate->set_self_link(istate); + istate->set_prev_link(NULL); + // thread will be set by a hacky repurposing of frame::patch_pc() + // bcp will be set by vframeArrayElement::unpack_on_stack() + istate->set_constants(method->constants()->cache()); + istate->set_msg(BytecodeInterpreter::method_resume); + istate->set_bcp_advance(0); + istate->set_oop_temp(NULL); + istate->set_mdx(NULL); + if (caller->is_interpreted_frame()) { + interpreterState prev = caller->get_interpreterState(); + prev->set_callee(method); + if (*prev->bcp() == Bytecodes::_invokeinterface) + prev->set_bcp_advance(5); + else + prev->set_bcp_advance(3); + } + istate->set_callee(NULL); + istate->set_monitor_base((BasicObjectLock *) monitor_base); + istate->set_stack_base(stack_base); + istate->set_stack(stack); + istate->set_stack_limit(stack_base - method->max_stack() - 1); } address CppInterpreter::return_entry(TosState state, int length) @@ -718,12 +831,29 @@ address CppInterpreter::deopt_entry(TosState state, int length) { +#ifdef SHARK + return NULL; +#else Unimplemented(); +#endif // SHARK } +// Helper for (runtime) stack overflow checks + +int AbstractInterpreter::size_top_interpreter_activation(methodOop method) +{ + return 0; +} + +// Helper for figuring out if frames are interpreter frames + bool CppInterpreter::contains(address pc) { +#ifdef PRODUCT ShouldNotCallThis(); +#else + return false; // make frame::print_value_on work +#endif // !PRODUCT } // Result handlers and convertors diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp --- a/ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -28,9 +28,13 @@ // Size of interpreter code const static int InterpreterCodeSize = 6 * K; - private: + public: // Method entries static void normal_entry(methodOop method, intptr_t UNUSED, TRAPS); static void native_entry(methodOop method, intptr_t UNUSED, TRAPS); static void accessor_entry(methodOop method, intptr_t UNUSED, TRAPS); static void empty_entry(methodOop method, intptr_t UNUSED, TRAPS); + + public: + // Main loop of normal_entry + static void main_loop(int recurse, TRAPS); diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/deoptimizerFrame_zero.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/cpu/zero/vm/deoptimizerFrame_zero.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -0,0 +1,49 @@ +/* + * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +// | ... | +// +--------------------+ ------------------ +// | frame_type | low addresses +// | next_frame | high addresses +// +--------------------+ ------------------ +// | ... | + +class DeoptimizerFrame : public ZeroFrame { + friend class ZeroStackPrinter; + + private: + DeoptimizerFrame() : ZeroFrame() + { + ShouldNotCallThis(); + } + + protected: + enum Layout { + header_words = jf_header_words + }; + + public: + static DeoptimizerFrame *build(ZeroStack* stack); +}; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/disassembler_zero.cpp --- a/ports/hotspot/src/cpu/zero/vm/disassembler_zero.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/disassembler_zero.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -36,12 +36,7 @@ { #ifdef SHARK assert(st == NULL, "it's all going to stderr anyway"); - - intptr_t *method_entry_addr = (intptr_t *) nm->instructions_begin(); - intptr_t *function_addr = method_entry_addr + 1; - llvm::Function *function = *(llvm::Function **) function_addr; - - function->dump(); + ((SharkEntry *) nm->instructions_begin())->llvm_function()->dump(); #else Unimplemented(); #endif // SHARK diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/frame_zero.cpp --- a/ports/hotspot/src/cpu/zero/vm/frame_zero.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/frame_zero.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -38,6 +38,11 @@ return zeroframe()->is_interpreter_frame(); } +bool frame::is_deoptimizer_frame() const +{ + return zeroframe()->is_deoptimizer_frame(); +} + frame frame::sender_for_entry_frame(RegisterMap *map) const { assert(map != NULL, "map must be set"); @@ -59,6 +64,11 @@ return frame(sender_sp()); } +frame frame::sender_for_deoptimizer_frame(RegisterMap *map) const +{ + return frame(sender_sp()); +} + frame frame::sender(RegisterMap* map) const { // Default is not to follow arguments; the various @@ -76,6 +86,9 @@ return sender_for_compiled_frame(map); } + if (is_deoptimizer_frame()) + return sender_for_deoptimizer_frame(map); + Unimplemented(); } @@ -93,7 +106,14 @@ void frame::patch_pc(Thread* thread, address pc) { +#ifdef SHARK + // We borrow this call to set the thread pointer in the interpreter + // state; the hook to set up deoptimized frames isn't supplied it. + assert(pc == NULL, "should be"); + get_interpreterState()->set_thread((JavaThread *) thread); +#else Unimplemented(); +#endif // SHARK } bool frame::safe_for_sender(JavaThread *thread) @@ -118,7 +138,11 @@ int frame::frame_size() const { - Unimplemented(); +#ifdef PRODUCT + ShouldNotCallThis(); +#else + return 0; // make javaVFrame::print_value work +#endif // PRODUCT } intptr_t* frame::interpreter_frame_tos_at(jint offset) const diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/frame_zero.hpp --- a/ports/hotspot/src/cpu/zero/vm/frame_zero.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/frame_zero.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -41,7 +41,11 @@ // accessors for the instance variables intptr_t* fp() const { - Unimplemented(); +#ifdef PRODUCT + ShouldNotCallThis(); +#else + return (intptr_t *) -1; // make frame::print_value_on work +#endif // !PRODUCT } #ifdef CC_INTERP @@ -56,16 +60,19 @@ const EntryFrame *zero_entryframe() const { - assert(zeroframe()->is_entry_frame(), "must be"); - return (EntryFrame *) zeroframe(); + return zeroframe()->as_entry_frame(); } const InterpreterFrame *zero_interpreterframe() const { - assert(zeroframe()->is_interpreter_frame(), "must be"); - return (InterpreterFrame *) zeroframe(); + return zeroframe()->as_interpreter_frame(); } const SharkFrame *zero_sharkframe() const { - assert(zeroframe()->is_shark_frame(), "must be"); - return (SharkFrame *) zeroframe(); + return zeroframe()->as_shark_frame(); } + + public: + bool is_deoptimizer_frame() const; + + public: + frame sender_for_deoptimizer_frame(RegisterMap* map) const; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp --- a/ports/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -26,6 +26,7 @@ #include #include #include +#include // Constructors @@ -56,6 +57,11 @@ _cb = CodeCache::find_blob(pc()); break; + case ZeroFrame::DEOPTIMIZER_FRAME: + _pc = NULL; + _cb = NULL; + break; + default: ShouldNotReachHere(); } @@ -162,5 +168,8 @@ inline intptr_t* frame::unextended_sp() const { - return zero_sharkframe()->unextended_sp(); + if (zeroframe()->is_shark_frame()) + return zero_sharkframe()->unextended_sp(); + else + return (intptr_t *) -1; } diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/interpreterFrame_zero.hpp --- a/ports/hotspot/src/cpu/zero/vm/interpreterFrame_zero.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/interpreterFrame_zero.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -40,6 +40,7 @@ class InterpreterFrame : public ZeroFrame { friend class ZeroStackPrinter; + friend class AbstractInterpreter; private: InterpreterFrame() : ZeroFrame() @@ -56,9 +57,11 @@ }; public: - static InterpreterFrame *build(ZeroStack* stack, - const methodOop method, - JavaThread* thread); + static InterpreterFrame *build(ZeroStack* stack, + const methodOop method, + JavaThread* thread); + static InterpreterFrame *build(ZeroStack* stack, int size); + public: interpreterState interpreter_state() const { diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/interpreter_zero.cpp --- a/ports/hotspot/src/cpu/zero/vm/interpreter_zero.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/interpreter_zero.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -54,11 +54,21 @@ int callee_locals, bool is_top_frame) { - Unimplemented(); + return layout_activation(method, + tempcount, + popframe_extra_args, + moncount, + callee_param_count, + callee_locals, + (frame*) NULL, + (frame*) NULL, + is_top_frame); } void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) { +#ifndef SHARK Unimplemented(); +#endif // !SHARK } diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/nativeInst_zero.cpp --- a/ports/hotspot/src/cpu/zero/vm/nativeInst_zero.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/nativeInst_zero.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -0,0 +1,54 @@ +/* + * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_nativeInst_zero.cpp.incl" + +// This method is called by nmethod::make_not_entrant_or_zombie to +// insert a jump to SharedRuntime::get_handle_wrong_method_stub() +// (dest) at the start of a compiled method (verified_entry) to avoid +// a race where a method is invoked while being made non-entrant. +// +// In Shark, verified_entry is a pointer to a SharkEntry. We can +// handle this simply by changing it's entry point to point at the +// interpreter. This only works because the interpreter and Shark +// calling conventions are the same. + +void NativeJump::patch_verified_entry(address entry, + address verified_entry, + address dest) +{ +#ifdef SHARK + assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "should be"); + +#ifdef CC_INTERP + ((ZeroEntry*) verified_entry)->set_entry_point(CppInterpreter::normal_entry); +#else + Unimplemented(); +#endif // CC_INTERP +#else + Unimplemented(); +#endif // SHARK +} diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/nativeInst_zero.hpp --- a/ports/hotspot/src/cpu/zero/vm/nativeInst_zero.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/nativeInst_zero.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -189,9 +189,7 @@ static void patch_verified_entry(address entry, address verified_entry, - address dest) { - Unimplemented(); - } + address dest); }; inline NativeJump* nativeJump_at(address address) diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp --- a/ports/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -69,7 +69,11 @@ int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) { +#ifdef SHARK + return 0; +#else Unimplemented(); +#endif // SHARK } uint SharedRuntime::out_preserve_stack_slots() diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp --- a/ports/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -31,6 +31,7 @@ // | monitor m-1 | // | ... | // | monitor 0 | +// | exception | // | method | // | unextended_sp | // | pc | @@ -54,6 +55,7 @@ pc_off = jf_header_words, unextended_sp_off, method_off, + exception_off, header_words }; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/stackPrinter_zero.hpp --- a/ports/hotspot/src/cpu/zero/vm/stackPrinter_zero.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/stackPrinter_zero.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -84,6 +84,9 @@ case ZeroFrame::SHARK_FRAME: value = "SHARK_FRAME"; break; + case ZeroFrame::DEOPTIMIZER_FRAME: + value = "DEOPTIMIZER_FRAME"; + break; } break; } @@ -101,11 +104,12 @@ if (frame->is_interpreter_frame()) { interpreterState istate = ((InterpreterFrame *) frame)->interpreter_state(); - intptr_t *monitor_base = (intptr_t *) istate->monitor_base(); + bool is_valid = istate->self_link() == istate; + if (addr >= (intptr_t *) istate) { field = istate->name_of_field_at_address((address) addr); if (field) { - if (!strcmp(field, "_method")) { + if (is_valid && !strcmp(field, "_method")) { value = istate->method()->name_and_sig_as_C_string(_buf,_buflen); field = "istate->_method"; } @@ -119,66 +123,69 @@ field = "(vtable for istate)"; } } - else if (addr >= istate->stack_base() && addr < monitor_base) { - int monitor_size = frame::interpreter_frame_monitor_size(); - int last_index = - (monitor_base - istate->stack_base()) / monitor_size - 1; - int index = - last_index - (addr - istate->stack_base()) / monitor_size; - intptr_t monitor = (intptr_t) (istate->monitor_base() - 1 - index); - intptr_t offset = (intptr_t) addr - monitor; - - if (offset == BasicObjectLock::obj_offset_in_bytes()) { - snprintf(_buf, _buflen, "monitor[%d]->_obj", index); - field = _buf; - } - else if (offset == BasicObjectLock::lock_offset_in_bytes()) { - snprintf(_buf, _buflen, "monitor[%d]->_lock", index); - field = _buf; + else if (is_valid) { + intptr_t *monitor_base = (intptr_t *) istate->monitor_base(); + if (addr >= istate->stack_base() && addr < monitor_base) { + int monitor_size = frame::interpreter_frame_monitor_size(); + int last_index = + (monitor_base - istate->stack_base()) / monitor_size - 1; + int index = + last_index - (addr - istate->stack_base()) / monitor_size; + intptr_t monitor = (intptr_t) (istate->monitor_base() - 1 - index); + intptr_t offset = (intptr_t) addr - monitor; + + if (offset == BasicObjectLock::obj_offset_in_bytes()) { + snprintf(_buf, _buflen, "monitor[%d]->_obj", index); + field = _buf; + } + else if (offset == BasicObjectLock::lock_offset_in_bytes()) { + snprintf(_buf, _buflen, "monitor[%d]->_lock", index); + field = _buf; + } } - } - else if (addr < istate->stack_base()) { - if (istate->method()->is_native()) { - address hA = istate->method()->signature_handler(); - if (hA != NULL) { - if (hA != (address) InterpreterRuntime::slow_signature_handler) { - InterpreterRuntime::SignatureHandler *handler = - InterpreterRuntime::SignatureHandler::from_handlerAddr(hA); - - intptr_t *params = - istate->stack_base() - handler->argument_count(); - - if (addr >= params) { - int param = addr - params; - const char *desc = ""; - if (param == 0) - desc = " (JNIEnv)"; - else if (param == 1) { - if (istate->method()->is_static()) - desc = " (mirror)"; - else - desc = " (this)"; + else if (addr < istate->stack_base()) { + if (istate->method()->is_native()) { + address hA = istate->method()->signature_handler(); + if (hA != NULL) { + if (hA != (address)InterpreterRuntime::slow_signature_handler){ + InterpreterRuntime::SignatureHandler *handler = + InterpreterRuntime::SignatureHandler::from_handlerAddr(hA); + + intptr_t *params = + istate->stack_base() - handler->argument_count(); + + if (addr >= params) { + int param = addr - params; + const char *desc = ""; + if (param == 0) + desc = " (JNIEnv)"; + else if (param == 1) { + if (istate->method()->is_static()) + desc = " (mirror)"; + else + desc = " (this)"; + } + snprintf(_buf, _buflen, "parameter[%d]%s", param, desc); + field = _buf; } - snprintf(_buf, _buflen, "parameter[%d]%s", param, desc); - field = _buf; - } - else { - for (int i = 0; i < handler->argument_count(); i++) { - if (params[i] == (intptr_t) addr) { - snprintf(_buf, _buflen, "unboxed parameter[%d]", i); - field = _buf; - break; - } - } + else { + for (int i = 0; i < handler->argument_count(); i++) { + if (params[i] == (intptr_t) addr) { + snprintf(_buf, _buflen, "unboxed parameter[%d]", i); + field = _buf; + break; + } + } + } } } } - } - else { - snprintf(_buf, _buflen, "%s[%d]", - top_frame ? "stack_word" : "local", - istate->stack_base() - addr - 1); - field = _buf; + else { + snprintf(_buf, _buflen, "%s[%d]", + top_frame ? "stack_word" : "local", + istate->stack_base() - addr - 1); + field = _buf; + } } } } @@ -195,6 +202,9 @@ if (method->is_oop()) value = method->name_and_sig_as_C_string(_buf, _buflen); } + else if (word == SharkFrame::exception_off) { + field = "exception"; + } else { SharkFrame *sf = (SharkFrame *) frame; intptr_t *monitor_base = diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/cpu/zero/vm/stack_zero.hpp --- a/ports/hotspot/src/cpu/zero/vm/stack_zero.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/cpu/zero/vm/stack_zero.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -110,6 +110,12 @@ } }; + +class EntryFrame; +class InterpreterFrame; +class SharkFrame; +class DeoptimizerFrame; + // // | ... | // +--------------------+ ------------------ @@ -138,7 +144,8 @@ enum FrameType { ENTRY_FRAME = 1, INTERPRETER_FRAME, - SHARK_FRAME + SHARK_FRAME, + DEOPTIMIZER_FRAME }; protected: @@ -179,8 +186,34 @@ { return type() == SHARK_FRAME; } -}; + + bool is_deoptimizer_frame() const + { + return type() == DEOPTIMIZER_FRAME; + } + + public: + EntryFrame *as_entry_frame() const + { + assert(is_entry_frame(), "should be"); + return (EntryFrame *) this; + } -class EntryFrame; -class InterpreterFrame; -class SharkFrame; + InterpreterFrame *as_interpreter_frame() const + { + assert(is_interpreter_frame(), "should be"); + return (InterpreterFrame *) this; + } + + SharkFrame *as_shark_frame() const + { + assert(is_shark_frame(), "should be"); + return (SharkFrame *) this; + } + + DeoptimizerFrame *as_deoptimizer_frame() const + { + assert(is_deoptimizer_frame(), "should be"); + return (DeoptimizerFrame *) this; + } +}; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp --- a/ports/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -47,7 +47,14 @@ // Must never look like an address returned by reserve_memory, // even in its subfields (as defined by the CPU immediate fields, // if the CPU splits constants across multiple instructions). - Unimplemented(); +#ifdef SPARC + // On SPARC, 0 != %hi(any real address), because there is no + // allocation in the first 1Kb of the virtual address space. + return (char *) 0; +#else + // This is the value for x86; works pretty well for PPC too. + return (char *) -1; +#endif // SPARC } void os::initialize_thread() diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/includeDB_shark --- a/ports/hotspot/src/share/vm/includeDB_shark Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/includeDB_shark Tue Sep 30 08:42:10 2008 -0400 @@ -50,7 +50,7 @@ compileBroker.cpp sharkCompiler.hpp -disassembler_.cpp llvmHeaders.hpp +disassembler_.cpp sharkEntry.hpp globals.hpp shark_globals_.hpp @@ -74,10 +74,11 @@ sharkBlock.cpp shark_globals.hpp sharkBlock.cpp sharkBlock.hpp sharkBlock.cpp sharkBuilder.hpp +sharkBlock.cpp sharkBytecodeTracer.hpp sharkBlock.cpp sharkConstantPool.hpp sharkBlock.cpp sharkRuntime.hpp sharkBlock.cpp sharkState.inline.hpp -sharkBlock.cpp sharkValue.hpp +sharkBlock.cpp sharkValue.inline.hpp sharkBlock.hpp allocation.hpp sharkBlock.hpp bytecodes.hpp @@ -89,7 +90,7 @@ sharkBlock.hpp sharkFunction.hpp sharkBlock.hpp sharkMonitor.hpp sharkBlock.hpp sharkState.hpp -sharkBlock.hpp sharkValue.hpp +sharkBlock.hpp sharkValue.inline.hpp sharkBuilder.cpp ciMethod.hpp sharkBuilder.cpp debug.hpp @@ -110,7 +111,28 @@ sharkBuilder.hpp llvmHeaders.hpp sharkBuilder.hpp sizes.hpp sharkBuilder.hpp sharkType.hpp -sharkBuilder.hpp sharkValue.hpp +sharkBuilder.hpp sharkValue.inline.hpp + +sharkBytecodeTracer.cpp sharkBytecodeTracer.hpp +sharkBytecodeTracer.cpp sharkState.inline.hpp +sharkBytecodeTracer.cpp sharkValue.hpp + +sharkBytecodeTracer.hpp allocation.hpp +sharkBytecodeTracer.hpp llvmHeaders.hpp +sharkBytecodeTracer.hpp sharkState.hpp + +sharkCacheDecache.cpp ciMethod.hpp +sharkCacheDecache.cpp debugInfoRec.hpp +sharkCacheDecache.cpp sharkBuilder.hpp +sharkCacheDecache.cpp sharkCacheDecache.hpp +sharkCacheDecache.cpp sharkFunction.hpp +sharkCacheDecache.cpp sharkState.inline.hpp + +sharkCacheDecache.hpp ciMethod.hpp +sharkCacheDecache.hpp debugInfoRec.hpp +sharkCacheDecache.hpp sharkBuilder.hpp +sharkCacheDecache.hpp sharkFunction.hpp +sharkCacheDecache.hpp sharkStateScanner.hpp sharkCompiler.cpp ciEnv.hpp sharkCompiler.cpp ciMethod.hpp @@ -145,7 +167,7 @@ sharkConstantPool.cpp sharkRuntime.hpp sharkConstantPool.cpp sharkState.inline.hpp sharkConstantPool.cpp sharkType.hpp -sharkConstantPool.cpp sharkValue.hpp +sharkConstantPool.cpp sharkValue.inline.hpp sharkConstantPool.hpp allocation.hpp sharkConstantPool.hpp llvmHeaders.hpp @@ -175,14 +197,19 @@ sharkFunction.hpp llvmHeaders.hpp sharkFunction.hpp sharkBuilder.hpp +sharkMonitor.cpp llvmHeaders.hpp +sharkMonitor.cpp sharkBlock.hpp sharkMonitor.cpp sharkMonitor.hpp -sharkMonitor.cpp llvmHeaders.hpp +sharkMonitor.cpp sharkRuntime.hpp +sharkMonitor.cpp sharkState.inline.hpp sharkMonitor.hpp allocation.hpp sharkMonitor.hpp llvmHeaders.hpp sharkMonitor.hpp sharkBuilder.hpp sharkMonitor.hpp sharkFunction.hpp +sharkRuntime.cpp biasedLocking.hpp +sharkRuntime.cpp deoptimization.hpp sharkRuntime.cpp llvmHeaders.hpp sharkRuntime.cpp klassOop.hpp sharkRuntime.cpp sharkBuilder.hpp @@ -203,14 +230,24 @@ sharkState.cpp sharkBuilder.hpp sharkState.cpp sharkState.inline.hpp sharkState.cpp sharkType.hpp -sharkState.cpp sharkValue.hpp +sharkState.cpp sharkValue.inline.hpp sharkState.hpp allocation.hpp -sharkState.hpp sharkValue.hpp +sharkState.hpp sharkBuilder.hpp +sharkState.hpp sharkFunction.hpp +sharkState.hpp sharkValue.inline.hpp sharkState.hpp vmreg.hpp sharkState.inline.hpp sharkBlock.hpp sharkState.inline.hpp sharkState.hpp +sharkState.inline.hpp sharkCacheDecache.hpp + +sharkStateScanner.cpp sharkState.inline.hpp +sharkStateScanner.cpp sharkStateScanner.hpp + +sharkStateScanner.hpp allocation.hpp +sharkStateScanner.hpp llvmHeaders.hpp +sharkStateScanner.hpp sharkFunction.hpp sharkType.cpp arrayOop.hpp sharkType.cpp globalDefinitions.hpp @@ -228,3 +265,7 @@ sharkValue.hpp ciType.hpp sharkValue.hpp llvmHeaders.hpp sharkValue.hpp sharkType.hpp + +sharkValue.inline.hpp ciType.hpp +sharkValue.inline.hpp llvmHeaders.hpp +sharkValue.inline.hpp sharkValue.hpp diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkBlock.cpp --- a/ports/hotspot/src/share/vm/shark/sharkBlock.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkBlock.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -26,19 +26,77 @@ #include "incls/_precompiled.incl" #include "incls/_sharkBlock.cpp.incl" #include "ciArrayKlass.hpp" // XXX fuck you makeDeps +#include "ciObjArrayKlass.hpp" // XXX likewise using namespace llvm; +void SharkBlock::enter(SharkBlock* predecessor, bool is_exception) +{ + // This block requires phis: + // - if it is entered more than once + // - if it is an exception handler, because in which + // case we assume it's entered more than once. + // - if the predecessor will be compiled after this + // block, in which case we can't simple propagate + // the state forward. + if (!needs_phis() && + (entered() || + is_exception || + (predecessor && predecessor->index() >= index()))) + _needs_phis = true; + + // Recurse into the tree + if (!entered()) { + _entered = true; + + if (!has_trap()) { + for (int i = 0; i < num_successors(); i++) { + successor(i)->enter(this, false); + } + for (int i = 0; i < num_exceptions(); i++) { + exception(i)->enter(this, true); + } + } + } +} + void SharkBlock::initialize() { char name[28]; snprintf(name, sizeof(name), "bci_%d%s", - ciblock()->start(), - ciblock()->is_private_copy() ? "_private_copy" : ""); + start(), is_private_copy() ? "_private_copy" : ""); _entry_block = function()->CreateBlock(name); } +void SharkBlock::acquire_method_lock() +{ + Value *object; + if (target()->is_static()) { + SharkConstantPool constants(this); + object = constants.java_mirror(); + } + else { + object = local(0)->jobject_value(); + } + iter()->force_bci(start()); // for the decache + function()->monitor(0)->acquire(this, object); + check_pending_exception(false); +} + +void SharkBlock::release_method_lock() +{ + function()->monitor(0)->release(this); + + // We neither need nor want to check for pending exceptions here. + // This method is only called by handle_return, which copes with + // them implicitly: + // - if a value is being returned then we just carry on as normal; + // the caller will see the pending exception and handle it. + // - if an exception is being thrown then that exception takes + // priority and ours will be ignored. +} + void SharkBlock::parse() { SharkValue *a, *b, *c, *d; @@ -46,25 +104,30 @@ builder()->SetInsertPoint(entry_block()); - if (never_entered()) { - NOT_PRODUCT(warning("skipping unentered block")); - builder()->CreateShouldNotReachHere(__FILE__, __LINE__); - builder()->CreateUnreachable(); - return; - } - - if (ciblock()->has_trap()) { - current_state()->decache(); - builder()->CreateDump(LLVMValue::jint_constant(start())); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); + if (has_trap()) { + current_state()->decache_for_trap(); + builder()->CreateCall2( + SharkRuntime::uncommon_trap(), + thread(), + LLVMValue::jint_constant(trap_index())); + builder()->CreateRetVoid(); return; } iter()->reset_to_bci(start()); + bool successors_done = false; while (iter()->next() != ciBytecodeStream::EOBC() && bci() < limit()) { NOT_PRODUCT(a = b = c = d = NULL); + if (TraceBytecodes) { + Value *tos, *tos2; + SharkBytecodeTracer::decode(builder(), current_state(), &tos, &tos2); + call_vm( + SharkRuntime::trace_bytecode(), + LLVMValue::jint_constant(bci()), + tos, tos2); + } + if (SharkTraceBytecodes) tty->print_cr("%4d: %s", bci(), Bytecodes::name(bc())); @@ -99,13 +162,16 @@ break; case Bytecodes::_tableswitch: - len = iter()->get_int_table(2) - iter()->get_int_table(1) + 1; - for (i = 0; i < len + 3; i++) { - if (i != 1 && i != 2) { - if (iter()->get_dest_table(i) <= bci()) { - add_safepoint(); - break; - } + case Bytecodes::_lookupswitch: + if (switch_default_dest() <= bci()) { + add_safepoint(); + break; + } + len = switch_table_length(); + for (i = 0; i < len; i++) { + if (switch_dest(i) <= bci()) { + add_safepoint(); + break; } } break; @@ -302,130 +368,68 @@ break; case Bytecodes::_pop: - pop_and_assert_one_word(); + xpop(); break; case Bytecodes::_pop2: - if (stack(0)->is_two_word()) { - pop_and_assert_two_word(); - } - else { - pop_and_assert_one_word(); - pop_and_assert_one_word(); - } + xpop(); + xpop(); break; case Bytecodes::_swap: - a = pop_and_assert_one_word(); - b = pop_and_assert_one_word(); - push(a); - push(b); + a = xpop(); + b = xpop(); + xpush(a); + xpush(b); break; case Bytecodes::_dup: - a = pop_and_assert_one_word(); - push(a); - push(a); + a = xpop(); + xpush(a); + xpush(a); break; case Bytecodes::_dup_x1: - a = pop_and_assert_one_word(); - b = pop_and_assert_one_word(); - push(a); - push(b); - push(a); + a = xpop(); + b = xpop(); + xpush(a); + xpush(b); + xpush(a); break; case Bytecodes::_dup_x2: - if (stack(1)->is_two_word()) { - a = pop_and_assert_one_word(); - b = pop_and_assert_two_word(); - push(a); - push(b); - push(a); - } - else { - a = pop_and_assert_one_word(); - b = pop_and_assert_one_word(); - c = pop_and_assert_one_word(); - push(a); - push(c); - push(b); - push(a); - } + a = xpop(); + b = xpop(); + c = xpop(); + xpush(a); + xpush(c); + xpush(b); + xpush(a); break; case Bytecodes::_dup2: - if (stack(0)->is_two_word()) { - a = pop_and_assert_two_word(); - push(a); - push(a); - } - else { - a = pop_and_assert_one_word(); - b = pop_and_assert_one_word(); - push(b); - push(a); - push(b); - push(a); - } + a = xpop(); + b = xpop(); + xpush(b); + xpush(a); + xpush(b); + xpush(a); break; case Bytecodes::_dup2_x1: - if (stack(0)->is_two_word()) { - a = pop_and_assert_two_word(); - b = pop_and_assert_one_word(); - push(a); - push(b); - push(a); - } - else { - a = pop_and_assert_one_word(); - b = pop_and_assert_one_word(); - c = pop_and_assert_one_word(); - push(b); - push(a); - push(c); - push(b); - push(a); - } + a = xpop(); + b = xpop(); + c = xpop(); + xpush(b); + xpush(a); + xpush(c); + xpush(b); + xpush(a); break; case Bytecodes::_dup2_x2: - if (stack(0)->is_one_word()) { - if (stack(2)->is_one_word()) { - a = pop_and_assert_one_word(); - b = pop_and_assert_one_word(); - c = pop_and_assert_one_word(); - d = pop_and_assert_one_word(); - push(b); - push(a); - push(d); - push(c); - push(b); - push(a); - } - else { - a = pop_and_assert_one_word(); - b = pop_and_assert_one_word(); - c = pop_and_assert_two_word(); - push(b); - push(a); - push(c); - push(b); - push(a); - } - } - else { - if (stack(1)->is_one_word()) { - a = pop_and_assert_two_word(); - b = pop_and_assert_one_word(); - c = pop_and_assert_one_word(); - push(a); - push(c); - push(b); - push(a); - } - else { - a = pop_and_assert_two_word(); - b = pop_and_assert_two_word(); - push(a); - push(b); - push(a); - } - } + a = xpop(); + b = xpop(); + c = xpop(); + d = xpop(); + xpush(b); + xpush(a); + xpush(d); + xpush(c); + xpush(b); + xpush(a); break; case Bytecodes::_arraylength: @@ -672,6 +676,19 @@ do_lcmp(); break; + case Bytecodes::_fcmpl: + do_fcmp(false, false); + break; + case Bytecodes::_fcmpg: + do_fcmp(false, true); + break; + case Bytecodes::_dcmpl: + do_fcmp(true, false); + break; + case Bytecodes::_dcmpg: + do_fcmp(true, true); + break; + case Bytecodes::_i2l: push(SharkValue::create_jlong( builder()->CreateIntCast( @@ -779,8 +796,7 @@ break; case Bytecodes::_athrow: - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); + do_athrow(); break; case Bytecodes::_goto: @@ -788,6 +804,18 @@ builder()->CreateBr(successor(ciTypeFlow::GOTO_TARGET)->entry_block()); break; + case Bytecodes::_jsr: + case Bytecodes::_jsr_w: + push(SharkValue::create_returnAddress(iter()->next_bci())); + builder()->CreateBr(successor(ciTypeFlow::GOTO_TARGET)->entry_block()); + break; + + case Bytecodes::_ret: + assert(local(iter()->get_index())->returnAddress_value() == + successor(ciTypeFlow::GOTO_TARGET)->start(), "should be"); + builder()->CreateBr(successor(ciTypeFlow::GOTO_TARGET)->entry_block()); + break; + case Bytecodes::_ifnull: do_if(ICmpInst::ICMP_EQ, SharkValue::null(), pop()); break; @@ -838,7 +866,9 @@ break; case Bytecodes::_tableswitch: - do_tableswitch(); + case Bytecodes::_lookupswitch: + do_switch(); + successors_done = true; break; case Bytecodes::_invokestatic: @@ -859,6 +889,12 @@ case Bytecodes::_newarray: do_newarray(); break; + case Bytecodes::_anewarray: + do_anewarray(); + break; + case Bytecodes::_multianewarray: + do_multianewarray(); + break; case Bytecodes::_monitorenter: do_monitorenter(); @@ -868,25 +904,18 @@ break; default: - { - const char *code = Bytecodes::name(bc()); - int buflen = 19 + strlen(code) + 1; - char *buf = (char *) function()->env()->arena()->Amalloc(buflen); - snprintf(buf, buflen, "Unhandled bytecode %s", code); - record_method_not_compilable(buf); - } + ShouldNotReachHere(); } - - if (failing()) - return; } if (falls_through()) { builder()->CreateBr(successor(ciTypeFlow::FALL_THROUGH)->entry_block()); } - for (int i = 0; i < num_successors(); i++) - successor(i)->add_incoming(current_state()); + if (!successors_done) { + for (int i = 0; i < num_successors(); i++) + successor(i)->add_incoming(current_state()); + } } SharkBlock* SharkBlock::bci_successor(int bci) const @@ -910,6 +939,9 @@ Value *a, *b; switch (value->basic_type()) { + case T_BYTE: + case T_CHAR: + case T_SHORT: case T_INT: a = value->jint_value(); b = LLVMValue::jint_constant(0); @@ -924,14 +956,25 @@ b = LLVMValue::LLVMValue::null(); break; default: + tty->print_cr("Unhandled type %s", type2name(value->basic_type())); ShouldNotReachHere(); } builder()->CreateCondBr(builder()->CreateICmpNE(a, b), not_zero, zero); builder()->SetInsertPoint(zero); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); + SharkTrackingState *saved_state = current_state()->copy(); + if (value->is_jobject()) { + call_vm_nocheck( + SharkRuntime::throw_NullPointerException(), + LLVMValue::intptr_constant((intptr_t) __FILE__), + LLVMValue::jint_constant(__LINE__)); + } + else { + builder()->CreateUnimplemented(__FILE__, __LINE__); + } + handle_exception(function()->CreateGetPendingException()); + set_current_state(saved_state); builder()->SetInsertPoint(not_zero); @@ -944,39 +987,130 @@ BasicBlock *in_bounds = function()->CreateBlock("in_bounds"); Value *length = builder()->CreateArrayLength(array->jarray_value()); + // we use an unsigned comparison to catch negative values builder()->CreateCondBr( - builder()->CreateICmpSLT(index->jint_value(), length), + builder()->CreateICmpULT(index->jint_value(), length), in_bounds, out_of_bounds); builder()->SetInsertPoint(out_of_bounds); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); + SharkTrackingState *saved_state = current_state()->copy(); + call_vm_nocheck( + SharkRuntime::throw_ArrayIndexOutOfBoundsException(), + LLVMValue::intptr_constant((intptr_t) __FILE__), + LLVMValue::jint_constant(__LINE__), + index->jint_value()); + handle_exception(function()->CreateGetPendingException()); + set_current_state(saved_state); builder()->SetInsertPoint(in_bounds); } -void SharkBlock::check_pending_exception() +void SharkBlock::check_pending_exception(bool attempt_catch) { BasicBlock *exception = function()->CreateBlock("exception"); BasicBlock *no_exception = function()->CreateBlock("no_exception"); - Value *pending_exception = builder()->CreateValueOfStructEntry( - thread(), Thread::pending_exception_offset(), - SharkType::jobject_type(), "pending_exception"); + Value *pending_exception_addr = function()->pending_exception_address(); + Value *pending_exception = builder()->CreateLoad( + pending_exception_addr, "pending_exception"); builder()->CreateCondBr( builder()->CreateICmpEQ(pending_exception, LLVMValue::null()), no_exception, exception); builder()->SetInsertPoint(exception); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); + builder()->CreateStore(LLVMValue::null(), pending_exception_addr); + SharkTrackingState *saved_state = current_state()->copy(); + handle_exception(pending_exception, attempt_catch); + set_current_state(saved_state); builder()->SetInsertPoint(no_exception); } +void SharkBlock::handle_exception(Value* exception, bool attempt_catch) +{ + if (attempt_catch && num_exceptions() != 0) { + // Clear the stack and push the exception onto it. + // We do this now to protect it across the VM call + // we may be about to make. + while (xstack_depth()) + pop(); + push(SharkValue::create_jobject(exception)); + + int *indexes = NEW_RESOURCE_ARRAY(int, num_exceptions()); + bool has_catch_all = false; + + ciExceptionHandlerStream eh_iter(target(), bci()); + for (int i = 0; i < num_exceptions(); i++, eh_iter.next()) { + ciExceptionHandler* handler = eh_iter.handler(); + + if (handler->is_catch_all()) { + assert(i == num_exceptions() - 1, "catch-all should be last"); + has_catch_all = true; + } + else { + indexes[i] = handler->catch_klass_index(); + } + } + + int num_options = num_exceptions(); + if (has_catch_all) + num_options--; + + // Drop into the runtime if there are non-catch-all options + if (num_options > 0) { + Value *options = builder()->CreateAlloca( + ArrayType::get(SharkType::jint_type(), num_options), + LLVMValue::jint_constant(1)); + + for (int i = 0; i < num_options; i++) + builder()->CreateStore( + LLVMValue::jint_constant(indexes[i]), + builder()->CreateStructGEP(options, i)); + + Value *index = call_vm_nocheck( + SharkRuntime::find_exception_handler(), + builder()->CreateStructGEP(options, 0), + LLVMValue::jint_constant(num_options)); + check_pending_exception(false); + + // Jump to the exception handler, if found + BasicBlock *no_handler = function()->CreateBlock("no_handler"); + SwitchInst *switchinst = builder()->CreateSwitch( + index, no_handler, num_options); + + for (int i = 0; i < num_options; i++) { + SharkBlock* handler = this->exception(i); + + switchinst->addCase( + LLVMValue::jint_constant(i), + handler->entry_block()); + + handler->add_incoming(current_state()); + } + + builder()->SetInsertPoint(no_handler); + } + + // No specific handler exists, but maybe there's a catch-all + if (has_catch_all) { + SharkBlock* handler = this->exception(num_options); + + builder()->CreateBr(handler->entry_block()); + handler->add_incoming(current_state()); + return; + } + } + + // No exception handler was found; unwind and return + handle_return(T_VOID, exception); +} + void SharkBlock::add_safepoint() { + BasicBlock *orig_block = builder()->GetInsertBlock(); + SharkState *orig_state = current_state()->copy(); + BasicBlock *do_safepoint = function()->CreateBlock("do_safepoint"); BasicBlock *safepointed = function()->CreateBlock("safepointed"); @@ -994,42 +1128,80 @@ do_safepoint, safepointed); builder()->SetInsertPoint(do_safepoint); - // XXX decache_state - // XXX call whatever - // XXX cache_state - // XXX THEN MERGE (need phis...) - // XXX (if it's call_VM then call_VM should do the decache/cache) - // XXX shouldn't ever need a fixup_after_potential_safepoint - // XXX since anything that might safepoint needs a decache/cache - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); + call_vm(SharkRuntime::safepoint()); + BasicBlock *safepointed_block = builder()->GetInsertBlock(); + builder()->CreateBr(safepointed); builder()->SetInsertPoint(safepointed); + current_state()->merge(orig_state, orig_block, safepointed_block); } -CallInst* SharkBlock::call_vm_base(Constant* callee, - Value** args_start, - Value** args_end) +void SharkBlock::handle_return(BasicType type, Value* exception) { - // Decache the state - current_state()->decache(); + assert (exception == NULL || type == T_VOID, "exception OR result, please"); + + if (exception) + builder()->CreateStore(exception, function()->exception_slot()); + + release_locked_monitors(); + if (target()->is_synchronized()) + release_method_lock(); + + if (exception) { + exception = builder()->CreateLoad(function()->exception_slot()); + builder()->CreateStore(exception, function()->pending_exception_address()); + } - // Set up the Java frame anchor - function()->set_last_Java_frame(); + Value *result_addr = function()->CreatePopFrame(type2size[type]); + if (type != T_VOID) { + SharkValue *result = pop(); + +#ifdef ASSERT + switch (result->basic_type()) { + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + assert(type == T_INT, "type mismatch"); + break; + + case T_ARRAY: + assert(type == T_OBJECT, "type mismatch"); + break; - // Make the call - CallInst *result = builder()->CreateCall(callee, args_start, args_end); + default: + assert(result->basic_type() == type, "type mismatch"); + } +#endif // ASSERT - // Clear the frame anchor - function()->reset_last_Java_frame(); + builder()->CreateStore( + result->generic_value(), + builder()->CreateIntToPtr( + result_addr, + PointerType::getUnqual(SharkType::to_stackType(type)))); + } + + builder()->CreateRetVoid(); +} - // Recache the state - current_state()->cache(); +void SharkBlock::release_locked_monitors() +{ + int base = target()->is_synchronized(); + for (int i = function()->monitor_count() - 1; i >= base; i--) { + BasicBlock *locked = function()->CreateBlock("locked"); + BasicBlock *unlocked = function()->CreateBlock("unlocked"); - // Check for pending exceptions - check_pending_exception(); + Value *object = function()->monitor(i)->object(); + builder()->CreateCondBr( + builder()->CreateICmpNE(object, LLVMValue::null()), + locked, unlocked); + + builder()->SetInsertPoint(locked); + builder()->CreateUnimplemented(__FILE__, __LINE__); + builder()->CreateUnreachable(); - return result; + builder()->SetInsertPoint(unlocked); + } } void SharkBlock::do_ldc() @@ -1038,8 +1210,7 @@ if (value == NULL) { SharkConstantPool constants(this); - BasicBlock *string = function()->CreateBlock("string"); - BasicBlock *klass = function()->CreateBlock("klass"); + BasicBlock *resolved = function()->CreateBlock("resolved"); BasicBlock *unresolved = function()->CreateBlock("unresolved"); BasicBlock *unknown = function()->CreateBlock("unknown"); BasicBlock *done = function()->CreateBlock("done"); @@ -1049,9 +1220,9 @@ unknown, 5); switchinst->addCase( - LLVMValue::jbyte_constant(JVM_CONSTANT_String), string); + LLVMValue::jbyte_constant(JVM_CONSTANT_String), resolved); switchinst->addCase( - LLVMValue::jbyte_constant(JVM_CONSTANT_Class), klass); + LLVMValue::jbyte_constant(JVM_CONSTANT_Class), resolved); switchinst->addCase( LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedString), unresolved); switchinst->addCase( @@ -1060,13 +1231,8 @@ LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClassInError), unresolved); - builder()->SetInsertPoint(string); - Value *string_value = constants.object_at(iter()->get_constant_index()); - builder()->CreateBr(done); - - builder()->SetInsertPoint(klass); - builder()->CreateUnimplemented(__FILE__, __LINE__); - Value *klass_value = LLVMValue::null(); + builder()->SetInsertPoint(resolved); + Value *resolved_value = constants.object_at(iter()->get_constant_index()); builder()->CreateBr(done); builder()->SetInsertPoint(unresolved); @@ -1080,8 +1246,7 @@ builder()->SetInsertPoint(done); PHINode *phi = builder()->CreatePHI(SharkType::jobject_type(), "constant"); - phi->addIncoming(string_value, string); - phi->addIncoming(klass_value, klass); + phi->addIncoming(resolved_value, resolved); phi->addIncoming(unresolved_value, unresolved); value = SharkValue::create_jobject(phi); } @@ -1103,7 +1268,9 @@ assert(array->type()->is_array_klass(), "should be"); ciType *element_type = ((ciArrayKlass *) array->type())->element_type(); - assert(element_type->basic_type() == basic_type, "type mismatch"); + assert((element_type->basic_type() == T_BOOLEAN && basic_type == T_BYTE) || + (element_type->basic_type() == T_ARRAY && basic_type == T_OBJECT) || + (element_type->basic_type() == basic_type), "type mismatch"); check_null(array); check_bounds(array, index); @@ -1117,7 +1284,6 @@ value = builder()->CreateIntCast(value, stack_type, basic_type != T_CHAR); switch (basic_type) { - case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT: @@ -1138,7 +1304,7 @@ break; case T_OBJECT: - push(SharkValue::create_jobject(value)); + push(SharkValue::create_generic(element_type, value)); break; default: @@ -1155,7 +1321,9 @@ assert(array->type()->is_array_klass(), "should be"); ciType *element_type = ((ciArrayKlass *) array->type())->element_type(); - assert(element_type->basic_type() == basic_type, "type mismatch"); + assert((element_type->basic_type() == T_BOOLEAN && basic_type == T_BYTE) || + (element_type->basic_type() == T_ARRAY && basic_type == T_OBJECT) || + (element_type->basic_type() == basic_type), "type mismatch"); check_null(array); check_bounds(array, index); @@ -1338,12 +1506,8 @@ if (!field->type()->is_primitive_type()) builder()->CreateUpdateBarrierSet(oopDesc::bs(), addr); - if (field->is_volatile()) { + if (field->is_volatile()) builder()->CreateMemoryBarrier(SharkBuilder::BARRIER_STORELOAD); -#ifdef PPC - record_method_not_compilable("Missing memory barrier"); -#endif // PPC - } } } @@ -1383,43 +1547,51 @@ push(SharkValue::create_jint(result)); } -void SharkBlock::do_return(BasicType basic_type) +void SharkBlock::do_fcmp(bool is_double, bool unordered_is_greater) { - add_safepoint(); - - if (target()->is_synchronized()) - function()->monitor(0)->release(); - - Value *result_addr = function()->CreatePopFrame(type2size[basic_type]); - if (basic_type != T_VOID) { - SharkValue *result = pop(); - -#ifdef ASSERT - switch (result->basic_type()) { - case T_BOOLEAN: - case T_BYTE: - case T_CHAR: - case T_SHORT: - assert(basic_type == T_INT, "type mismatch"); - break; - - case T_ARRAY: - assert(basic_type == T_OBJECT, "type mismatch"); - break; - - default: - assert(result->basic_type() == basic_type, "type mismatch"); - } -#endif // ASSERT - - builder()->CreateStore( - result->generic_value(), - builder()->CreateIntToPtr( - result_addr, - PointerType::getUnqual(SharkType::to_stackType(basic_type)))); + Value *a, *b; + if (is_double) { + b = pop()->jdouble_value(); + a = pop()->jdouble_value(); + } + else { + b = pop()->jfloat_value(); + a = pop()->jfloat_value(); } - builder()->CreateRetVoid(); + BasicBlock *ordered = function()->CreateBlock("ordered"); + BasicBlock *ge = function()->CreateBlock("fcmp_ge"); + BasicBlock *lt = function()->CreateBlock("fcmp_lt"); + BasicBlock *eq = function()->CreateBlock("fcmp_eq"); + BasicBlock *gt = function()->CreateBlock("fcmp_gt"); + BasicBlock *done = function()->CreateBlock("done"); + + builder()->CreateCondBr( + builder()->CreateFCmpUNO(a, b), + unordered_is_greater ? gt : lt, ordered); + + builder()->SetInsertPoint(ordered); + builder()->CreateCondBr(builder()->CreateFCmpULT(a, b), lt, ge); + + builder()->SetInsertPoint(ge); + builder()->CreateCondBr(builder()->CreateFCmpUGT(a, b), gt, eq); + + builder()->SetInsertPoint(lt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(gt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(eq); + builder()->CreateBr(done); + + builder()->SetInsertPoint(done); + PHINode *result = builder()->CreatePHI(SharkType::jint_type(), "result"); + result->addIncoming(LLVMValue::jint_constant(-1), lt); + result->addIncoming(LLVMValue::jint_constant(0), eq); + result->addIncoming(LLVMValue::jint_constant(1), gt); + + push(SharkValue::create_jint(result)); } void SharkBlock::do_if(ICmpInst::Predicate p, SharkValue *b, SharkValue *a) @@ -1440,21 +1612,306 @@ successor(ciTypeFlow::IF_NOT_TAKEN)->entry_block()); } -void SharkBlock::do_tableswitch() +int SharkBlock::switch_default_dest() +{ + return iter()->get_dest_table(0); +} + +int SharkBlock::switch_table_length() +{ + switch(bc()) { + case Bytecodes::_tableswitch: + return iter()->get_int_table(2) - iter()->get_int_table(1) + 1; + + case Bytecodes::_lookupswitch: + return iter()->get_int_table(1); + + default: + ShouldNotReachHere(); + } +} + +int SharkBlock::switch_key(int i) { - int low = iter()->get_int_table(1); - int high = iter()->get_int_table(2); - int len = high - low + 1; + switch(bc()) { + case Bytecodes::_tableswitch: + return iter()->get_int_table(1) + i; + + case Bytecodes::_lookupswitch: + return iter()->get_int_table(2 + 2 * i); + + default: + ShouldNotReachHere(); + } +} +int SharkBlock::switch_dest(int i) +{ + switch(bc()) { + case Bytecodes::_tableswitch: + return iter()->get_dest_table(i + 3); + + case Bytecodes::_lookupswitch: + return iter()->get_dest_table(2 + 2 * i + 1); + + default: + ShouldNotReachHere(); + } +} + +void SharkBlock::do_switch() +{ + int len = switch_table_length(); + + SharkBlock *dest_block = successor(ciTypeFlow::SWITCH_DEFAULT); SwitchInst *switchinst = builder()->CreateSwitch( - pop()->jint_value(), - successor(ciTypeFlow::SWITCH_DEFAULT)->entry_block(), - len); + pop()->jint_value(), dest_block->entry_block(), len); + dest_block->add_incoming(current_state()); for (int i = 0; i < len; i++) { - switchinst->addCase( - LLVMValue::jint_constant(i + low), - bci_successor(iter()->get_dest_table(i + 3))->entry_block()); + int dest_bci = switch_dest(i); + if (dest_bci != switch_default_dest()) { + dest_block = bci_successor(dest_bci); + switchinst->addCase( + LLVMValue::jint_constant(switch_key(i)), + dest_block->entry_block()); + dest_block->add_incoming(current_state()); + } + } +} + +Value* SharkBlock::get_basic_callee(Value *cache) +{ + return builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f1_offset(), + SharkType::methodOop_type(), + "callee"); +} + +Value* SharkBlock::get_virtual_callee(Value *cache, SharkValue *receiver) +{ + BasicBlock *final = function()->CreateBlock("final"); + BasicBlock *not_final = function()->CreateBlock("not_final"); + BasicBlock *got_callee = function()->CreateBlock("got_callee"); + + Value *flags = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::flags_offset(), + SharkType::intptr_type(), + "flags"); + + const int mask = 1 << ConstantPoolCacheEntry::vfinalMethod; + builder()->CreateCondBr( + builder()->CreateICmpNE( + builder()->CreateAnd(flags, LLVMValue::intptr_constant(mask)), + LLVMValue::intptr_constant(0)), + final, not_final); + + // For final methods f2 is the actual address of the method + builder()->SetInsertPoint(final); + Value *final_callee = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f2_offset(), + SharkType::methodOop_type(), + "final_callee"); + builder()->CreateBr(got_callee); + + // For non-final methods f2 is the index into the vtable + builder()->SetInsertPoint(not_final); + Value *klass = builder()->CreateValueOfStructEntry( + receiver->jobject_value(), + in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::jobject_type(), + "klass"); + + Value *index = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f2_offset(), + SharkType::intptr_type(), + "index"); + + Value *nonfinal_callee = builder()->CreateLoad( + builder()->CreateArrayAddress( + klass, + SharkType::methodOop_type(), + vtableEntry::size() * wordSize, + in_ByteSize(instanceKlass::vtable_start_offset() * wordSize), + index), + "nonfinal_callee"); + builder()->CreateBr(got_callee); + + builder()->SetInsertPoint(got_callee); + PHINode *callee = builder()->CreatePHI( + SharkType::methodOop_type(), "callee"); + callee->addIncoming(final_callee, final); + callee->addIncoming(nonfinal_callee, not_final); + + return callee; +} + +Value* SharkBlock::get_interface_callee(Value *cache, SharkValue *receiver) +{ + BasicBlock *hacky = function()->CreateBlock("hacky"); + BasicBlock *normal = function()->CreateBlock("normal"); + BasicBlock *loop = function()->CreateBlock("loop"); + BasicBlock *got_null = function()->CreateBlock("got_null"); + BasicBlock *not_null = function()->CreateBlock("not_null"); + BasicBlock *next = function()->CreateBlock("next"); + BasicBlock *got_entry = function()->CreateBlock("got_entry"); + BasicBlock *got_callee = function()->CreateBlock("got_callee"); + + Value *flags = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::flags_offset(), + SharkType::intptr_type(), + "flags"); + + const int mask = 1 << ConstantPoolCacheEntry::methodInterface; + builder()->CreateCondBr( + builder()->CreateICmpNE( + builder()->CreateAnd(flags, LLVMValue::intptr_constant(mask)), + LLVMValue::intptr_constant(0)), + hacky, normal); + + // Workaround for the case where we encounter an invokeinterface, + // but should really have an invokevirtual since the resolved + // method is a virtual method in java.lang.Object. This is a + // corner case in the spec but is presumably legal, and while + // javac does not generate this code there's no reason it could + // not be produced by a compliant java compiler. See + // cpCacheOop.cpp for more details. + builder()->SetInsertPoint(hacky); + Value *hacky_callee = get_virtual_callee(cache, receiver); + BasicBlock *got_hacky = builder()->GetInsertBlock(); + builder()->CreateBr(got_callee); + + // Locate the receiver's itable + builder()->SetInsertPoint(normal); + Value *object_klass = builder()->CreateValueOfStructEntry( + receiver->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::jobject_type(), + "object_klass"); + + Value *vtable_start = builder()->CreateAdd( + builder()->CreatePtrToInt(object_klass, SharkType::intptr_type()), + LLVMValue::intptr_constant( + instanceKlass::vtable_start_offset() * HeapWordSize), + "vtable_start"); + + Value *vtable_length = builder()->CreateValueOfStructEntry( + object_klass, + in_ByteSize(instanceKlass::vtable_length_offset() * HeapWordSize), + SharkType::jint_type(), + "vtable_length"); + + bool needs_aligning = HeapWordsPerLong > 1; + const char *itable_start_name = "itable_start"; + Value *itable_start = builder()->CreateAdd( + vtable_start, + builder()->CreateShl( + vtable_length, + LLVMValue::jint_constant(exact_log2(vtableEntry::size() * wordSize))), + needs_aligning ? "" : itable_start_name); + if (needs_aligning) + itable_start = builder()->CreateAlign( + itable_start, BytesPerLong, itable_start_name); + + // Locate this interface's entry in the table + Value *iklass = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f1_offset(), + SharkType::jobject_type(), + "iklass"); + + builder()->CreateBr(loop); + builder()->SetInsertPoint(loop); + PHINode *itable_entry_addr = builder()->CreatePHI( + SharkType::intptr_type(), "itable_entry_addr"); + itable_entry_addr->addIncoming(itable_start, normal); + + Value *itable_entry = builder()->CreateIntToPtr( + itable_entry_addr, SharkType::itableOffsetEntry_type(), "itable_entry"); + + Value *itable_iklass = builder()->CreateValueOfStructEntry( + itable_entry, + in_ByteSize(itableOffsetEntry::interface_offset_in_bytes()), + SharkType::jobject_type(), + "itable_iklass"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ(itable_iklass, LLVMValue::null()), + got_null, not_null); + + // A null entry means that the class doesn't implement the + // interface, and wasn't the same as the class checked when + // the interface was resolved. + builder()->SetInsertPoint(got_null); + builder()->CreateUnimplemented(__FILE__, __LINE__); + builder()->CreateUnreachable(); + + builder()->SetInsertPoint(not_null); + builder()->CreateCondBr( + builder()->CreateICmpEQ(itable_iklass, iklass), + got_entry, next); + + builder()->SetInsertPoint(next); + Value *next_entry = builder()->CreateAdd( + itable_entry_addr, + LLVMValue::intptr_constant(itableOffsetEntry::size() * wordSize)); + builder()->CreateBr(loop); + itable_entry_addr->addIncoming(next_entry, next); + + // Locate the method pointer + builder()->SetInsertPoint(got_entry); + Value *offset = builder()->CreateValueOfStructEntry( + itable_entry, + in_ByteSize(itableOffsetEntry::offset_offset_in_bytes()), + SharkType::jint_type(), + "offset"); + + Value *index = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f2_offset(), + SharkType::intptr_type(), + "index"); + + Value *normal_callee = builder()->CreateLoad( + builder()->CreateIntToPtr( + builder()->CreateAdd( + builder()->CreateAdd( + builder()->CreateAdd( + builder()->CreatePtrToInt( + object_klass, SharkType::intptr_type()), + offset), + builder()->CreateShl( + index, + LLVMValue::jint_constant( + exact_log2(itableMethodEntry::size() * wordSize)))), + LLVMValue::intptr_constant( + itableMethodEntry::method_offset_in_bytes())), + PointerType::getUnqual(SharkType::methodOop_type())), + "normal_callee"); + BasicBlock *got_normal = builder()->GetInsertBlock(); + builder()->CreateBr(got_callee); + + builder()->SetInsertPoint(got_callee); + PHINode *callee = builder()->CreatePHI( + SharkType::methodOop_type(), "callee"); + callee->addIncoming(hacky_callee, got_hacky); + callee->addIncoming(normal_callee, got_normal); + + return callee; +} + +Value* SharkBlock::get_callee(Value *cache, SharkValue *receiver) +{ + switch (bc()) { + case Bytecodes::_invokestatic: + case Bytecodes::_invokespecial: + return get_basic_callee(cache); + + case Bytecodes::_invokevirtual: + return get_virtual_callee(cache, receiver); + + case Bytecodes::_invokeinterface: + return get_interface_callee(cache, receiver); + + default: + ShouldNotReachHere(); } } @@ -1467,223 +1924,14 @@ // Find the receiver in the stack SharkValue *receiver = NULL; if (bc() != Bytecodes::_invokestatic) { - int shark_slot = 0, java_slot = 0; - while (java_slot < method->arg_size() - 1) - java_slot += stack(shark_slot++)->type()->size(); - receiver = stack(shark_slot); + receiver = xstack(method->arg_size() - 1); check_null(receiver); } // Find the method we are calling - Value *callee = NULL; SharkConstantPool constants(this); Value *cache = constants.cache_entry_at(iter()->get_method_index()); - - if (bc() == Bytecodes::_invokevirtual) { - BasicBlock *final = function()->CreateBlock("final"); - BasicBlock *not_final = function()->CreateBlock("not_final"); - BasicBlock *invoke = function()->CreateBlock("invoke"); - - Value *flags = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::flags_offset(), - SharkType::intptr_type(), - "flags"); - - const int mask = 1 << ConstantPoolCacheEntry::vfinalMethod; - builder()->CreateCondBr( - builder()->CreateICmpNE( - builder()->CreateAnd(flags, LLVMValue::intptr_constant(mask)), - LLVMValue::intptr_constant(0)), - final, not_final); - - // For final methods f2 is the actual address of the method - builder()->SetInsertPoint(final); - Value *final_callee = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f2_offset(), - SharkType::methodOop_type(), - "final_callee"); - builder()->CreateBr(invoke); - - // For non-final methods f2 is the index into the vtable - builder()->SetInsertPoint(not_final); - Value *klass = builder()->CreateValueOfStructEntry( - receiver->jobject_value(), - in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::jobject_type(), - "klass"); - - Value *index = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f2_offset(), - SharkType::intptr_type(), - "index"); - - Value *nonfinal_callee = builder()->CreateLoad( - builder()->CreateArrayAddress( - klass, - SharkType::methodOop_type(), - vtableEntry::size() * wordSize, - in_ByteSize(instanceKlass::vtable_start_offset() * wordSize), - index), - "nonfinal_callee"); - builder()->CreateBr(invoke); - - builder()->SetInsertPoint(invoke); - callee = builder()->CreatePHI(SharkType::methodOop_type(), "callee"); - ((PHINode *) callee)->addIncoming(final_callee, final); - ((PHINode *) callee)->addIncoming(nonfinal_callee, not_final); - } - else if (bc() == Bytecodes::_invokeinterface) { - BasicBlock *hacky = function()->CreateBlock("hacky"); - BasicBlock *normal = function()->CreateBlock("normal"); - BasicBlock *loop = function()->CreateBlock("loop"); - BasicBlock *got_null = function()->CreateBlock("got_null"); - BasicBlock *not_null = function()->CreateBlock("not_null"); - BasicBlock *next = function()->CreateBlock("next"); - BasicBlock *got_entry = function()->CreateBlock("got_entry"); - BasicBlock *invoke = function()->CreateBlock("invoke"); - - Value *flags = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::flags_offset(), - SharkType::intptr_type(), - "flags"); - - const int mask = 1 << ConstantPoolCacheEntry::methodInterface; - builder()->CreateCondBr( - builder()->CreateICmpNE( - builder()->CreateAnd(flags, LLVMValue::intptr_constant(mask)), - LLVMValue::intptr_constant(0)), - hacky, normal); - - // Workaround for the case where we encounter an invokeinterface, - // but should really have an invokevirtual since the resolved - // method is a virtual method in java.lang.Object. This is a - // corner case in the spec but is presumably legal, and while - // javac does not generate this code there's no reason it could - // not be produced by a compliant java compiler. See - // cpCacheOop.cpp for more details. - builder()->SetInsertPoint(hacky); - builder()->CreateUnimplemented(__FILE__, __LINE__); - Value *hacky_callee = - ConstantPointerNull::get(SharkType::methodOop_type()); - builder()->CreateBr(invoke); - - // Locate the receiver's itable - builder()->SetInsertPoint(normal); - Value *object_klass = builder()->CreateValueOfStructEntry( - receiver->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::jobject_type(), - "object_klass"); - - Value *vtable_start = builder()->CreateAdd( - builder()->CreatePtrToInt(object_klass, SharkType::intptr_type()), - LLVMValue::intptr_constant( - instanceKlass::vtable_start_offset() * HeapWordSize), - "vtable_start"); - - Value *vtable_length = builder()->CreateValueOfStructEntry( - object_klass, - in_ByteSize(instanceKlass::vtable_length_offset() * HeapWordSize), - SharkType::jint_type(), - "vtable_length"); - - bool needs_aligning = HeapWordsPerLong > 1; - const char *itable_start_name = "itable_start"; - Value *itable_start = builder()->CreateAdd( - vtable_start, - builder()->CreateShl( - vtable_length, - LLVMValue::jint_constant(exact_log2(vtableEntry::size() * wordSize))), - needs_aligning ? "" : itable_start_name); - if (needs_aligning) - itable_start = builder()->CreateAlign( - itable_start, BytesPerLong, itable_start_name); - - // Locate this interface's entry in the table - Value *iklass = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f1_offset(), - SharkType::jobject_type(), - "iklass"); - - builder()->CreateBr(loop); - builder()->SetInsertPoint(loop); - PHINode *itable_entry_addr = builder()->CreatePHI( - SharkType::intptr_type(), "itable_entry_addr"); - itable_entry_addr->addIncoming(itable_start, normal); - - Value *itable_entry = builder()->CreateIntToPtr( - itable_entry_addr, SharkType::itableOffsetEntry_type(), "itable_entry"); - - Value *itable_iklass = builder()->CreateValueOfStructEntry( - itable_entry, - in_ByteSize(itableOffsetEntry::interface_offset_in_bytes()), - SharkType::jobject_type(), - "itable_iklass"); - - builder()->CreateCondBr( - builder()->CreateICmpEQ(itable_iklass, LLVMValue::null()), - got_null, not_null); - - // A null entry means that the class doesn't implement the - // interface, and wasn't the same as the class checked when - // the interface was resolved. - builder()->SetInsertPoint(got_null); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); - - builder()->SetInsertPoint(not_null); - builder()->CreateCondBr( - builder()->CreateICmpEQ(itable_iklass, iklass), - got_entry, next); - - builder()->SetInsertPoint(next); - Value *next_entry = builder()->CreateAdd( - itable_entry_addr, - LLVMValue::intptr_constant(itableOffsetEntry::size() * wordSize)); - builder()->CreateBr(loop); - itable_entry_addr->addIncoming(next_entry, next); - - // Locate the method pointer - builder()->SetInsertPoint(got_entry); - Value *offset = builder()->CreateValueOfStructEntry( - itable_entry, - in_ByteSize(itableOffsetEntry::offset_offset_in_bytes()), - SharkType::jint_type(), - "offset"); - - Value *index = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f2_offset(), - SharkType::intptr_type(), - "index"); - - Value *normal_callee = builder()->CreateLoad( - builder()->CreateIntToPtr( - builder()->CreateAdd( - builder()->CreateAdd( - builder()->CreateAdd( - builder()->CreatePtrToInt( - object_klass, SharkType::intptr_type()), - offset), - builder()->CreateShl( - index, - LLVMValue::jint_constant( - exact_log2(itableMethodEntry::size() * wordSize)))), - LLVMValue::intptr_constant( - itableMethodEntry::method_offset_in_bytes())), - PointerType::getUnqual(SharkType::methodOop_type())), - "normal_callee"); - builder()->CreateBr(invoke); - - builder()->SetInsertPoint(invoke); - callee = builder()->CreatePHI(SharkType::methodOop_type(), "callee"); - ((PHINode *) callee)->addIncoming(hacky_callee, hacky); - ((PHINode *) callee)->addIncoming(normal_callee, got_entry); - } - else { - callee = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f1_offset(), - SharkType::methodOop_type(), - "callee"); - } + Value *callee = get_callee(cache, receiver); Value *base_pc = builder()->CreateValueOfStructEntry( callee, methodOopDesc::from_interpreted_offset(), @@ -1700,9 +1948,9 @@ "entry_point"); // Make the call - current_state()->decache(method); + current_state()->decache_for_Java_call(method); builder()->CreateCall3(entry_point, callee, base_pc, thread()); - current_state()->cache(method); + current_state()->cache_after_Java_call(method); // Check for pending exceptions check_pending_exception(); @@ -1710,23 +1958,45 @@ void SharkBlock::do_instance_check() { + // Leave the object on the stack until after all the VM calls + assert(xstack(0)->is_jobject(), "should be"); + + ciKlass *klass = NULL; + if (bc() == Bytecodes::_checkcast) { + bool will_link; + klass = iter()->get_klass(will_link); + if (!will_link) { + // XXX why is this not typeflow's responsibility? + NOT_PRODUCT(warning("unresolved checkcast in %s", function()->name())); + klass = (ciKlass *) xstack(0)->type(); + } + } + BasicBlock *not_null = function()->CreateBlock("not_null"); - BasicBlock *resolve = function()->CreateBlock("resolve"); - BasicBlock *resolved = function()->CreateBlock("resolved"); + BasicBlock *fast_path = function()->CreateBlock("fast_path"); + BasicBlock *slow_path = function()->CreateBlock("slow_path"); + BasicBlock *got_klass = function()->CreateBlock("got_klass"); BasicBlock *subtype_check = function()->CreateBlock("subtype_check"); - BasicBlock *failure = function()->CreateBlock("failure"); - BasicBlock *success = function()->CreateBlock("success"); + BasicBlock *is_instance = function()->CreateBlock("is_instance"); + BasicBlock *not_instance = function()->CreateBlock("not_instance"); + BasicBlock *merge1 = function()->CreateBlock("merge1"); + BasicBlock *merge2 = function()->CreateBlock("merge2"); - SharkValue *sharkobject = pop(); - Value *object = sharkobject->jobject_value(); + enum InstanceCheckStates { + IC_IS_NULL, + IC_IS_INSTANCE, + IC_NOT_INSTANCE, + }; // Null objects aren't instances of anything builder()->CreateCondBr( - builder()->CreateICmpEQ(object, LLVMValue::null()), - bc() == Bytecodes::_checkcast ? success : failure, not_null); - builder()->SetInsertPoint(not_null); + builder()->CreateICmpEQ(xstack(0)->jobject_value(), LLVMValue::null()), + merge2, not_null); + BasicBlock *null_block = builder()->GetInsertBlock(); + SharkState *null_state = current_state()->copy(); // Get the class we're checking against + builder()->SetInsertPoint(not_null); SharkConstantPool constants(this); Value *tag = constants.tag_at(iter()->get_klass_index()); builder()->CreateCondBr( @@ -1735,63 +2005,103 @@ tag, LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClass)), builder()->CreateICmpEQ( tag, LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClassInError))), - resolve, resolved); + slow_path, fast_path); + + // The fast path + builder()->SetInsertPoint(fast_path); + BasicBlock *fast_block = builder()->GetInsertBlock(); + SharkState *fast_state = current_state()->copy(); + Value *fast_klass = constants.object_at(iter()->get_klass_index()); + builder()->CreateBr(got_klass); - // If the class is unresolved we must resolve it - builder()->SetInsertPoint(resolve); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); // XXX builder()->CreateBr(resolved); + // The slow path + builder()->SetInsertPoint(slow_path); + call_vm( + SharkRuntime::resolve_klass(), + LLVMValue::jint_constant(iter()->get_klass_index())); + Value *slow_klass = function()->CreateGetVMResult(); + BasicBlock *slow_block = builder()->GetInsertBlock(); + builder()->CreateBr(got_klass); - builder()->SetInsertPoint(resolved); - Value *check_klass = constants.object_at(iter()->get_klass_index()); + // We have the class to test against + builder()->SetInsertPoint(got_klass); + current_state()->merge(fast_state, fast_block, slow_block); + PHINode *check_klass = builder()->CreatePHI( + SharkType::jobject_type(), "check_klass"); + check_klass->addIncoming(fast_klass, fast_block); + check_klass->addIncoming(slow_klass, slow_block); // Get the class of the object being tested Value *object_klass = builder()->CreateValueOfStructEntry( - object, in_ByteSize(oopDesc::klass_offset_in_bytes()), + xstack(0)->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), SharkType::jobject_type(), "object_klass"); // Perform the check builder()->CreateCondBr( builder()->CreateICmpEQ(check_klass, object_klass), - success, subtype_check); - + is_instance, subtype_check); + builder()->SetInsertPoint(subtype_check); builder()->CreateCondBr( builder()->CreateICmpNE( builder()->CreateCall2( SharkRuntime::is_subtype_of(), check_klass, object_klass), LLVMValue::jbyte_constant(0)), - success, failure); + is_instance, not_instance); + + builder()->SetInsertPoint(is_instance); + builder()->CreateBr(merge1); + + builder()->SetInsertPoint(not_instance); + builder()->CreateBr(merge1); + + // First merge + builder()->SetInsertPoint(merge1); + PHINode *nonnull_result = builder()->CreatePHI( + SharkType::jint_type(), "nonnull_result"); + nonnull_result->addIncoming( + LLVMValue::jint_constant(IC_IS_INSTANCE), is_instance); + nonnull_result->addIncoming( + LLVMValue::jint_constant(IC_NOT_INSTANCE), not_instance); + BasicBlock *nonnull_block = builder()->GetInsertBlock(); + builder()->CreateBr(merge2); + + // Second merge + builder()->SetInsertPoint(merge2); + current_state()->merge(null_state, null_block, nonnull_block); + PHINode *result = builder()->CreatePHI( + SharkType::jint_type(), "result"); + result->addIncoming(LLVMValue::jint_constant(IC_IS_NULL), null_block); + result->addIncoming(nonnull_result, nonnull_block); + + // We can finally pop the object! + Value *object = pop()->jobject_value(); // Handle the result if (bc() == Bytecodes::_checkcast) { + BasicBlock *failure = function()->CreateBlock("failure"); + BasicBlock *success = function()->CreateBlock("success"); + + builder()->CreateCondBr( + builder()->CreateICmpNE( + result, LLVMValue::jint_constant(IC_NOT_INSTANCE)), + success, failure); + builder()->SetInsertPoint(failure); builder()->CreateUnimplemented(__FILE__, __LINE__); builder()->CreateUnreachable(); builder()->SetInsertPoint(success); - push(sharkobject); - } - else if (bc() == Bytecodes::_instanceof) { - BasicBlock *done = function()->CreateBlock("done"); - - builder()->SetInsertPoint(success); - builder()->CreateBr(done); - - builder()->SetInsertPoint(failure); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - PHINode *result = builder()->CreatePHI(SharkType::jint_type(), "result"); - result->addIncoming(LLVMValue::jint_constant(1), success); - result->addIncoming(LLVMValue::jint_constant(0), failure); - - push(SharkValue::create_jint(result)); + push(SharkValue::create_generic(klass, object)); } else { - tty->print_cr("Unhandled bytecode %s", Bytecodes::name(bc())); - ShouldNotReachHere(); + push( + SharkValue::create_jint( + builder()->CreateIntCast( + builder()->CreateICmpEQ( + result, LLVMValue::jint_constant(IC_IS_INSTANCE)), + SharkType::jint_type(), false))); } } @@ -1801,11 +2111,13 @@ ciInstanceKlass* klass = iter()->get_klass(will_link)->as_instance_klass(); assert(will_link, "typeflow responsibility"); + BasicBlock *tlab_alloc = NULL; BasicBlock *got_tlab = NULL; BasicBlock *heap_alloc = NULL; BasicBlock *retry = NULL; BasicBlock *got_heap = NULL; BasicBlock *initialize = NULL; + BasicBlock *got_fast = NULL; BasicBlock *slow_alloc_and_init = NULL; BasicBlock *got_slow = NULL; BasicBlock *push_object = NULL; @@ -1818,22 +2130,33 @@ Value *slow_object = NULL; Value *object = NULL; + SharkConstantPool constants(this); + // The fast path if (!Klass::layout_helper_needs_slow_path(klass->layout_helper())) { if (UseTLAB) { + tlab_alloc = function()->CreateBlock("tlab_alloc"); got_tlab = function()->CreateBlock("got_tlab"); - heap_alloc = function()->CreateBlock("heap_alloc"); } + heap_alloc = function()->CreateBlock("heap_alloc"); retry = function()->CreateBlock("retry"); got_heap = function()->CreateBlock("got_heap"); initialize = function()->CreateBlock("initialize"); slow_alloc_and_init = function()->CreateBlock("slow_alloc_and_init"); push_object = function()->CreateBlock("push_object"); + builder()->CreateCondBr( + builder()->CreateICmpEQ( + constants.tag_at(iter()->get_klass_index()), + LLVMValue::jbyte_constant(JVM_CONSTANT_Class)), + UseTLAB ? tlab_alloc : heap_alloc, slow_alloc_and_init); + size_t size_in_bytes = klass->size_helper() << LogHeapWordSize; // Thread local allocation if (UseTLAB) { + builder()->SetInsertPoint(tlab_alloc); + Value *top_addr = builder()->CreateAddressOfStructEntry( thread(), Thread::tlab_top_offset(), PointerType::getUnqual(SharkType::intptr_type()), @@ -1858,11 +2181,11 @@ builder()->CreateStore(new_top, top_addr); builder()->CreateBr(initialize); - - builder()->SetInsertPoint(heap_alloc); } // Heap allocation + builder()->SetInsertPoint(heap_alloc); + Value *top_addr = builder()->CreateIntToPtr( LLVMValue::intptr_constant((intptr_t) Universe::heap()->top_addr()), PointerType::getUnqual(SharkType::intptr_type()), @@ -1935,9 +2258,9 @@ builder()->CreateStore(LLVMValue::intptr_constant(mark), mark_addr); // Set the class - SharkConstantPool constants(this); Value *rtklass = constants.object_at(iter()->get_klass_index()); builder()->CreateStore(rtklass, klass_addr); + got_fast = builder()->GetInsertBlock(); builder()->CreateBr(push_object); builder()->SetInsertPoint(slow_alloc_and_init); @@ -1945,10 +2268,9 @@ } // The slow path - SharkConstantPool constants(this); call_vm( SharkRuntime::new_instance(), - constants.object_at(iter()->get_klass_index())); + LLVMValue::jint_constant(iter()->get_klass_index())); slow_object = function()->CreateGetVMResult(); got_slow = builder()->GetInsertBlock(); @@ -1959,10 +2281,10 @@ } if (fast_object) { PHINode *phi = builder()->CreatePHI(SharkType::jobject_type(), "object"); - phi->addIncoming(fast_object, initialize); + phi->addIncoming(fast_object, got_fast); phi->addIncoming(slow_object, got_slow); object = phi; - current_state()->merge(fast_state, initialize, got_slow); + current_state()->merge(fast_state, got_fast, got_slow); } else { object = slow_object; @@ -1989,6 +2311,66 @@ push(result); } +void SharkBlock::do_anewarray() +{ + bool will_link; + ciKlass *klass = iter()->get_klass(will_link); + assert(will_link, "typeflow responsibility"); + + ciObjArrayKlass *array_klass = ciObjArrayKlass::make(klass); + if (!array_klass->is_loaded()) { + Unimplemented(); + } + + call_vm( + SharkRuntime::anewarray(), + LLVMValue::jint_constant(iter()->get_klass_index()), + pop()->jint_value()); + + SharkValue *result = SharkValue::create_generic( + array_klass, function()->CreateGetVMResult()); + result->set_zero_checked(true); + push(result); +} + +void SharkBlock::do_multianewarray() +{ + bool will_link; + ciArrayKlass *array_klass = iter()->get_klass(will_link)->as_array_klass(); + assert(will_link, "typeflow responsibility"); + + // The dimensions are stack values, so we use their slots for the + // dimensions array. Note that we are storing them in the reverse + // of normal stack order. + int ndims = iter()->get_dimensions(); + + Value *dimensions = function()->CreateAddressOfFrameEntry( + function()->stack_slots_offset() + max_stack() - xstack_depth(), + ArrayType::get(SharkType::jint_type(), ndims), + "dimensions"); + + for (int i = 0; i < ndims; i++) { + builder()->CreateStore( + xstack(ndims - 1 - i)->jint_value(), + builder()->CreateStructGEP(dimensions, i)); + } + + call_vm( + SharkRuntime::multianewarray(), + LLVMValue::jint_constant(iter()->get_klass_index()), + LLVMValue::jint_constant(ndims), + builder()->CreateStructGEP(dimensions, 0)); + + // Now we can pop the dimensions off the stack + for (int i = 0; i < ndims; i++) + pop(); + + SharkValue *result = SharkValue::create_generic( + array_klass, function()->CreateGetVMResult()); + result->set_zero_checked(true); + push(result); +} + void SharkBlock::do_monitorenter() { SharkValue *lockee = pop(); @@ -2033,7 +2415,8 @@ // Acquire the lock builder()->SetInsertPoint(got_monitor); - monitor->acquire(object); + monitor->acquire(this, object); + check_pending_exception(); } void SharkBlock::do_monitorexit() @@ -2078,5 +2461,6 @@ // Release the lock builder()->SetInsertPoint(got_monitor); - monitor->release(); + monitor->release(this); + check_pending_exception(); } diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkBlock.hpp --- a/ports/hotspot/src/share/vm/shark/sharkBlock.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkBlock.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -28,19 +28,15 @@ SharkBlock(SharkFunction* function, ciTypeFlow::Block* ciblock) : _function(function), _ciblock(ciblock), - _num_predecessors(0), - _entered_backwards(false), + _entered(false), + _needs_phis(false), _entry_state(NULL), - _current_state(NULL) - { initialize(); } - - private: - void initialize(); + _entry_block(NULL), + _current_state(NULL) {} private: SharkFunction* _function; ciTypeFlow::Block* _ciblock; - llvm::BasicBlock* _entry_block; public: SharkFunction* function() const @@ -51,24 +47,12 @@ { return _ciblock; } - llvm::BasicBlock* entry_block() const - { - return _entry_block; - } public: SharkBuilder* builder() const { return function()->builder(); } - bool failing() const - { - return function()->failing(); - } - void record_method_not_compilable(const char* reason) const - { - function()->record_method_not_compilable(reason); - } ciMethod* target() const { return function()->target(); @@ -88,6 +72,10 @@ { return ciblock()->has_trap(); } + int trap_index() const + { + return ciblock()->trap_index(); + } bool is_private_copy() const { return ciblock()->is_private_copy(); @@ -124,6 +112,14 @@ { return ciblock()->control() == ciBlock::fall_through_bci; } + int num_exceptions() const + { + return ciblock()->exceptions()->length(); + } + SharkBlock* exception(int index) const + { + return function()->block(ciblock()->exceptions()->at(index)->pre_order()); + } int num_successors() const { return ciblock()->successors()->length(); @@ -132,6 +128,12 @@ { return function()->block(ciblock()->successors()->at(index)->pre_order()); } + int jsr_ret_bci() const + { + int jsr_level = ciblock()->jsrset()->size(); + assert(jsr_level > 0, "should be"); + return ciblock()->jsrset()->record_at(jsr_level - 1)->return_address(); + } SharkBlock* bci_successor(int bci) const; // Bytecode stream @@ -151,28 +153,32 @@ // Entry state private: - int _num_predecessors; - bool _entered_backwards; - SharkState* _entry_state; + bool _entered; + bool _needs_phis; public: - void add_predecessor(SharkBlock* predecessor) + bool entered() const { - _num_predecessors++; - if (predecessor && !_entered_backwards) { - if (predecessor->index() >= this->index()) - _entered_backwards = true; - } - } - private: - bool never_entered() const - { - return _num_predecessors == 0; + return _entered; } bool needs_phis() const { - return _entered_backwards || (_num_predecessors > 1); + return _needs_phis; } + + private: + void enter(SharkBlock* predecessor, bool is_exception); + + public: + void enter() + { + enter(NULL, false); + } + + private: + SharkState* _entry_state; + + private: SharkState* entry_state() { if (_entry_state == NULL) { @@ -182,13 +188,25 @@ return _entry_state; } + private: + llvm::BasicBlock* _entry_block; + + public: + llvm::BasicBlock* entry_block() const + { + return _entry_block; + } + + public: + void initialize(); + public: void add_incoming(SharkState* incoming_state) { if (needs_phis()) { ((SharkPHIState *) entry_state())->add_incoming(incoming_state); } - else { + else if (_entry_state != incoming_state) { assert(_entry_state == NULL, "should be"); _entry_state = incoming_state; } @@ -197,80 +215,131 @@ // Current state private: SharkTrackingState* _current_state; - + + private: + void set_current_state(SharkTrackingState* current_state) + { + _current_state = current_state; + } + public: SharkTrackingState* current_state() { if (_current_state == NULL) - _current_state = new SharkTrackingState(entry_state()); + set_current_state(new SharkTrackingState(entry_state())); return _current_state; } + // Method public: llvm::Value* method() { return current_state()->method(); } + + // Local variables private: SharkValue* local(int index) { - return current_state()->local(index); + SharkValue *value = current_state()->local(index); + assert(value != NULL, "shouldn't be"); + assert(value->is_one_word() || + (index + 1 < max_locals() && + current_state()->local(index + 1) == NULL), "should be"); + return value; } void set_local(int index, SharkValue* value) { + assert(value != NULL, "shouldn't be"); current_state()->set_local(index, value); + if (value->is_two_word()) + current_state()->set_local(index + 1, NULL); } - void push(SharkValue* value) + + // Expression stack (raw) + private: + void xpush(SharkValue* value) { current_state()->push(value); } - SharkValue* pop() + SharkValue* xpop() { return current_state()->pop(); } - int stack_depth() + SharkValue* xstack(int slot) + { + SharkValue *value = current_state()->stack(slot); + assert(value != NULL, "shouldn't be"); + assert(value->is_one_word() || + (slot > 0 && + current_state()->stack(slot - 1) == NULL), "should be"); + return value; + } + int xstack_depth() { return current_state()->stack_depth(); } - SharkValue* stack(int slot) - { - return current_state()->stack(slot); - } - // Handy macros for the various pop, swap and dup bytecodes + // Expression stack (cooked) private: - SharkValue* pop_and_assert_one_word() + void push(SharkValue* value) { - SharkValue* result = pop(); - assert(result->is_one_word(), "should be"); - return result; + assert(value != NULL, "shouldn't be"); + xpush(value); + if (value->is_two_word()) + xpush(NULL); } - SharkValue* pop_and_assert_two_word() + SharkValue* pop() { - SharkValue* result = pop(); - assert(result->is_two_word(), "should be"); - return result; + int size = current_state()->stack(0) == NULL ? 2 : 1; + if (size == 2) + xpop(); + SharkValue *value = xpop(); + assert(value && value->size() == size, "should be"); + return value; } // VM calls private: - llvm::CallInst* call_vm_base(llvm::Constant* callee, - llvm::Value** args_start, - llvm::Value** args_end); + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, + llvm::Value** args_start, + llvm::Value** args_end) + { + current_state()->decache_for_VM_call(); + function()->set_last_Java_frame(); + llvm::CallInst *res = builder()->CreateCall(callee, args_start, args_end); + function()->reset_last_Java_frame(); + current_state()->cache_after_VM_call(); + return res; + } + + llvm::CallInst* call_vm(llvm::Constant* callee, + llvm::Value** args_start, + llvm::Value** args_end) + { + llvm::CallInst* res = call_vm_nocheck(callee, args_start, args_end); + check_pending_exception(); + return res; + } public: + llvm::CallInst* call_vm(llvm::Constant* callee) + { + llvm::Value *args[] = {thread()}; + return call_vm(callee, args, args + 1); + } llvm::CallInst* call_vm(llvm::Constant* callee, llvm::Value* arg1) { llvm::Value *args[] = {thread(), arg1}; - return call_vm_base(callee, args, args + 2); + return call_vm(callee, args, args + 2); } llvm::CallInst* call_vm(llvm::Constant* callee, llvm::Value* arg1, llvm::Value* arg2) { llvm::Value *args[] = {thread(), arg1, arg2}; - return call_vm_base(callee, args, args + 3); + return call_vm(callee, args, args + 3); } llvm::CallInst* call_vm(llvm::Constant* callee, llvm::Value* arg1, @@ -278,12 +347,40 @@ llvm::Value* arg3) { llvm::Value *args[] = {thread(), arg1, arg2, arg3}; - return call_vm_base(callee, args, args + 4); + return call_vm(callee, args, args + 4); } - // Code generation + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee) + { + llvm::Value *args[] = {thread()}; + return call_vm_nocheck(callee, args, args + 1); + } + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, + llvm::Value* arg1) + { + llvm::Value *args[] = {thread(), arg1}; + return call_vm_nocheck(callee, args, args + 2); + } + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, + llvm::Value* arg1, + llvm::Value* arg2) + { + llvm::Value *args[] = {thread(), arg1, arg2}; + return call_vm_nocheck(callee, args, args + 3); + } + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, + llvm::Value* arg1, + llvm::Value* arg2, + llvm::Value* arg3) + { + llvm::Value *args[] = {thread(), arg1, arg2, arg3}; + return call_vm_nocheck(callee, args, args + 4); + } + + // Whole-method synchronization public: - void parse(); + void acquire_method_lock(); + void release_method_lock(); // Error checking private: @@ -297,12 +394,18 @@ } void check_zero(SharkValue* value); void check_bounds(SharkValue* array, SharkValue* index); - void check_pending_exception(); - + void check_pending_exception(bool attempt_catch = true); + void handle_exception(llvm::Value* exception, bool attempt_catch = true); + // Safepoints private: void add_safepoint(); + // Returns + private: + void handle_return(BasicType type, llvm::Value* exception); + void release_locked_monitors(); + // ldc* private: void do_ldc(); @@ -356,37 +459,65 @@ } void do_field_access(bool is_get, bool is_field); - // lcmp + // lcmp and [fd]cmp[lg] private: void do_lcmp(); + void do_fcmp(bool is_double, bool unordered_is_greater); - // *return + // *return and athrow private: - void do_return(BasicType basic_type); + void do_return(BasicType type) + { + add_safepoint(); + handle_return(type, NULL); + } + void do_athrow() + { + SharkValue *exception = pop(); + check_null(exception); + handle_exception(exception->jobject_value()); + } // if* private: void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a); - // *switch + // tableswitch and lookupswitch private: - void do_tableswitch(); + int switch_default_dest(); + int switch_table_length(); + int switch_key(int i); + int switch_dest(int i); + + void do_switch(); // invoke* private: + llvm::Value* get_basic_callee(llvm::Value* cache); + llvm::Value* get_virtual_callee(llvm::Value* cache, SharkValue* receiver); + llvm::Value* get_interface_callee(llvm::Value* cache, SharkValue* receiver); + + llvm::Value* get_callee(llvm::Value* cache, SharkValue* receiver); + void do_call(); // checkcast and instanceof private: void do_instance_check(); - // new and newarray + // new and *newarray private: void do_new(); void do_newarray(); + void do_anewarray(); + void do_multianewarray(); // monitorenter and monitorexit private: void do_monitorenter(); void do_monitorexit(); + + // The big one + public: + void parse(); }; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkBuilder.cpp --- a/ports/hotspot/src/share/vm/shark/sharkBuilder.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkBuilder.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -29,7 +29,7 @@ using namespace llvm; SharkBuilder::SharkBuilder() - : IRBuilder<>(), + : IRBuilder(), _module("shark"), _module_provider(module()), _execution_engine(ExecutionEngine::create(&_module_provider)) diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkBuilder.hpp --- a/ports/hotspot/src/share/vm/shark/sharkBuilder.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkBuilder.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -23,7 +23,7 @@ * */ -class SharkBuilder : public llvm::IRBuilder<> { +class SharkBuilder : public llvm::IRBuilder { public: SharkBuilder(); diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkBytecodeTracer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkBytecodeTracer.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -0,0 +1,114 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkBytecodeTracer.cpp.incl" + +using namespace llvm; + +void SharkBytecodeTracer::decode(SharkBuilder* builder, + const SharkState* state, + Value** tos, + Value** tos2) +{ + if (state->stack_depth() == 0) { + // nothing on the stack + *tos = *tos2 = LLVMValue::intptr_constant(EMPTY_SLOT); + } + else if (state->stack_depth() == 1) { + // one item on the stack + decode_one_word(builder, state, 0, tos); + *tos2 = LLVMValue::intptr_constant(EMPTY_SLOT); + } + else if (state->stack(0) == NULL) { + // two words of a two-word type + decode_two_word(builder, state, 0, tos, tos2); + } + else if (state->stack(1) == NULL) { + // a one-word type followed by half of a two-word type + decode_one_word(builder, state, 0, tos); + decode_two_word(builder, state, 1, tos2, NULL); + } + else { + // two one-word types + decode_one_word(builder, state, 0, tos); + decode_one_word(builder, state, 1, tos2); + } +} + +void SharkBytecodeTracer::decode_one_word(SharkBuilder* builder, + const SharkState* state, + int index, + Value** dst) +{ + SharkValue *value = state->stack(index); + assert(value && value->is_one_word(), "should be"); + switch (value->basic_type()) { + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: +#ifdef _LP64 + *dst = builder->CreateIntCast( + value->jint_value(), SharkType::intptr_type(), false); +#else + *dst = value->jint_value(); +#endif // _LP64 + break; + + case T_FLOAT: + *dst = LLVMValue::intptr_constant(UNDECODABLE_SLOT); + break; + + case T_OBJECT: + case T_ARRAY: + *dst = value->intptr_value(builder); + break; + + case T_ADDRESS: + *dst = LLVMValue::intptr_constant(value->returnAddress_value()); + break; + + default: + tty->print_cr("Unhandled type %s", type2name(value->basic_type())); + ShouldNotReachHere(); + } +} + +void SharkBytecodeTracer::decode_two_word(SharkBuilder* builder, + const SharkState* state, + int index, + Value** dst, + Value** dst2) +{ + assert(state->stack(index) == NULL, "should be"); + SharkValue *value = state->stack(index + 1); + assert(value && value->is_two_word(), "should be"); + + *dst = LLVMValue::intptr_constant(UNDECODABLE_SLOT); + if (dst2) + *dst2 = LLVMValue::intptr_constant(UNDECODABLE_SLOT); +} diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkBytecodeTracer.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkBytecodeTracer.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +class SharkBytecodeTracer : public AllStatic { + public: + static void decode(SharkBuilder* builder, + const SharkState* state, + llvm::Value** tos, + llvm::Value** tos2); + public: + static const intptr_t EMPTY_SLOT = + NOT_LP64(0x23232323) LP64_ONLY(0x2323232323232323); + + static const intptr_t UNDECODABLE_SLOT = + NOT_LP64(0xdeadbabe) LP64_ONLY(0xdeadbabedeadbabe); + + private: + static void decode_one_word(SharkBuilder* builder, + const SharkState* state, + int index, + llvm::Value** dst); + static void decode_two_word(SharkBuilder* builder, + const SharkState* state, + int index, + llvm::Value** dst, + llvm::Value** dst2); +}; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkCacheDecache.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkCacheDecache.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -0,0 +1,225 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkCacheDecache.cpp.incl" + +using namespace llvm; + +void SharkDecacher::start_frame() +{ + // Start recording the debug information + _pc_offset = function()->code_offset(); + _oopmap = new OopMap( + oopmap_slot_munge(function()->oopmap_frame_size()), + oopmap_slot_munge(function()->arg_size())); + debug_info()->add_safepoint(pc_offset(), oopmap()); +} + +void SharkDecacher::start_stack(int num_slots, int max_slots) +{ + // Create the array we'll record our stack slots in + _exparray = new GrowableArray(num_slots); + + // Trim back the stack if necessary + if (num_slots != max_slots) { + function()->CreateStoreZeroStackPointer( + builder()->CreatePtrToInt( + function()->CreateAddressOfFrameEntry( + function()->stack_slots_offset() + max_slots - num_slots), + SharkType::intptr_type())); + } +} + +void SharkDecacher::process_stack_slot(int index, + SharkValue** addr, + int offset) +{ + SharkValue *value = *addr; + + // Write the value to the frame if necessary + if (stack_slot_needs_write(index, value)) { + builder()->CreateStore( + value->generic_value(), + function()->CreateAddressOfFrameEntry( + adjusted_offset(value, offset), + SharkType::to_stackType(value->basic_type()))); + } + + // Record the value in the oopmap if necessary + if (stack_slot_needs_oopmap(index, value)) { + oopmap()->set_oop(slot2reg(offset)); + } + + // Record the value in the debuginfo if necessary + if (stack_slot_needs_debuginfo(index, value)) { + exparray()->append(slot2lv(offset, stack_location_type(index, addr))); + } +} + +void SharkDecacher::start_monitors(int num_monitors) +{ + // Create the array we'll record our monitors in + _monarray = new GrowableArray(num_monitors); +} + +void SharkDecacher::process_monitor(int index, int box_offset) +{ + int obj_offset = + box_offset + (BasicObjectLock::obj_offset_in_bytes() >> LogBytesPerWord); + + oopmap()->set_oop(slot2reg(obj_offset)); + + monarray()->append(new MonitorValue( + slot2lv (obj_offset, Location::oop), + slot2loc(box_offset, Location::normal))); +} + +void SharkDecacher::process_exception_slot(int offset) +{ + // Record the exception slot + oopmap()->set_oop(slot2reg(offset)); +} + +void SharkDecacher::process_method_slot(llvm::Value** value, int offset) +{ + // Decache the method pointer + builder()->CreateStore( + *value, + function()->CreateAddressOfFrameEntry( + offset, + SharkType::methodOop_type())); + oopmap()->set_oop(slot2reg(offset)); +} + +void SharkDecacher::process_pc_slot(int offset) +{ + // Record the PC + builder()->CreateStore( + builder()->CreateAdd( + function()->base_pc(), LLVMValue::intptr_constant(pc_offset())), + function()->CreateAddressOfFrameEntry(offset)); +} + +void SharkDecacher::start_locals(int num_locals) +{ + // Create the array we'll record our local variables in + _locarray = new GrowableArray(num_locals);} + +void SharkDecacher::process_local_slot(int index, + SharkValue** addr, + int offset) +{ + SharkValue *value = *addr; + + // Write the value to the frame if necessary + if (local_slot_needs_write(index, value)) { + builder()->CreateStore( + value->generic_value(), + function()->CreateAddressOfFrameEntry( + adjusted_offset(value, offset), + SharkType::to_stackType(value->basic_type()))); + } + + // Record the value in the oopmap if necessary + if (local_slot_needs_oopmap(index, value)) { + oopmap()->set_oop(slot2reg(offset)); + } + + // Record the value in the debuginfo if necessary + if (local_slot_needs_debuginfo(index, value)) { + locarray()->append(slot2lv(offset, local_location_type(index, addr))); + } +} + +void SharkDecacher::end_frame() +{ + // Record the scope + debug_info()->describe_scope( + pc_offset(), + function()->target(), + bci(), + debug_info()->create_scope_values(locarray()), + debug_info()->create_scope_values(exparray()), + debug_info()->create_monitor_values(monarray())); + + // Finish recording the debug information + debug_info()->end_safepoint(pc_offset()); +} + +void SharkCacher::start_stack(int num_slots, int max_slots) +{ + // Restore the stack if necessary + if (num_slots != max_slots) { + function()->CreateStoreZeroStackPointer( + builder()->CreatePtrToInt( + function()->CreateAddressOfFrameEntry( + function()->stack_slots_offset()), + SharkType::intptr_type())); + } +} + +void SharkCacher::process_stack_slot(int index, + SharkValue** addr, + int offset) +{ + SharkValue *value = *addr; + + // Read the value from the frame if necessary + if (stack_slot_needs_read(index, value)) { + *addr = SharkValue::create_generic( + value->type(), + builder()->CreateLoad( + function()->CreateAddressOfFrameEntry( + adjusted_offset(value, offset), + SharkType::to_stackType(value->basic_type())))); + } +} + +void SharkCacher::process_method_slot(llvm::Value** value, int offset) +{ + // Cache the method pointer + *value = builder()->CreateLoad( + function()->CreateAddressOfFrameEntry( + offset, + SharkType::methodOop_type())); +} + +void SharkCacher::process_local_slot(int index, + SharkValue** addr, + int offset) +{ + SharkValue *value = *addr; + + // Read the value from the frame if necessary + if (local_slot_needs_read(index, value)) { + *addr = SharkValue::create_generic( + value->type(), + builder()->CreateLoad( + function()->CreateAddressOfFrameEntry( + adjusted_offset(value, offset), + SharkType::to_stackType(value->basic_type())))); + } +} diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkCacheDecache.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkCacheDecache.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -0,0 +1,353 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +// Class hierarchy: +// - SharkStateScanner +// - SharkCacherDecacher +// - SharkDecacher +// - SharkJavaCallDecacher +// - SharkVMCallDecacher +// - SharkTrapDecacher +// - SharkCacher +// - SharkJavaCallCacher +// - SharkVMCallCacher + +class SharkCacherDecacher : public SharkStateScanner { + protected: + SharkCacherDecacher(SharkFunction* function, int bci) + : SharkStateScanner(function), _bci(bci) {} + + protected: + SharkBuilder* builder() const + { + return function()->builder(); + } + + private: + int _bci; + + protected: + int bci() const + { + return _bci; + } + + // Helper + protected: + static int adjusted_offset(SharkValue* value, int offset) + { + if (value->is_two_word()) + offset--; + return offset; + } +}; + +class SharkDecacher : public SharkCacherDecacher { + protected: + SharkDecacher(SharkFunction* function, int bci) + : SharkCacherDecacher(function, bci) {} + + private: + DebugInformationRecorder* debug_info() const + { + return function()->debug_info(); + } + + private: + int _pc_offset; + OopMap* _oopmap; + GrowableArray* _exparray; + GrowableArray* _monarray; + GrowableArray* _locarray; + + private: + int pc_offset() const + { + return _pc_offset; + } + OopMap* oopmap() const + { + return _oopmap; + } + GrowableArray* exparray() const + { + return _exparray; + } + GrowableArray* monarray() const + { + return _monarray; + } + GrowableArray* locarray() const + { + return _locarray; + } + + // Callbacks + protected: + void start_frame(); + + void start_stack(int num_slots, int max_slots); + void process_stack_slot(int index, SharkValue** value, int offset); + + void start_monitors(int num_monitors); + void process_monitor(int index, int offset); + + void process_exception_slot(int offset); + void process_method_slot(llvm::Value** value, int offset); + void process_pc_slot(int offset); + + void start_locals(int num_locals); + void process_local_slot(int index, SharkValue** value, int offset); + + void end_frame(); + + // oopmap and debuginfo helpers + private: + static int oopmap_slot_munge(int x) + { + return x << (LogBytesPerWord - LogBytesPerInt); + } + static VMReg slot2reg(int offset) + { + return VMRegImpl::stack2reg(oopmap_slot_munge(offset)); + } + static Location slot2loc(int offset, Location::Type type) + { + return Location::new_stk_loc(type, offset * wordSize); + } + static LocationValue* slot2lv(int offset, Location::Type type) + { + return new LocationValue(slot2loc(offset, type)); + } + + // Stack slot helpers + protected: + virtual bool stack_slot_needs_write(int index, SharkValue* value) = 0; + virtual bool stack_slot_needs_oopmap(int index, SharkValue* value) = 0; + virtual bool stack_slot_needs_debuginfo(int index, SharkValue* value) = 0; + + static Location::Type stack_location_type(int index, SharkValue** addr) + { + if (addr[0] && addr[0]->is_jobject()) + return Location::oop; + return Location::normal; + } + + // Local slot helpers + protected: + virtual bool local_slot_needs_write(int index, SharkValue* value) = 0; + virtual bool local_slot_needs_oopmap(int index, SharkValue* value) = 0; + virtual bool local_slot_needs_debuginfo(int index, SharkValue* value) = 0; + + static Location::Type local_location_type(int index, SharkValue** addr) + { + if (addr[0] && addr[0]->is_jobject()) + return Location::oop; + if (addr[0]) + return Location::normal; + if (index > 0 && addr[-1] && addr[-1]->is_two_word()) + return Location::normal; + return Location::invalid; + } +}; + +class SharkJavaCallDecacher : public SharkDecacher { + public: + SharkJavaCallDecacher(SharkFunction* function, int bci, ciMethod* callee) + : SharkDecacher(function, bci), _callee(callee) {} + + private: + ciMethod* _callee; + + protected: + ciMethod* callee() const + { + return _callee; + } + + // Stack slot helpers + protected: + bool stack_slot_needs_write(int index, SharkValue* value) + { + return value && (index < callee()->arg_size() || value->is_jobject()); + } + bool stack_slot_needs_oopmap(int index, SharkValue* value) + { + return value && value->is_jobject() && index >= callee()->arg_size(); + } + bool stack_slot_needs_debuginfo(int index, SharkValue* value) + { + return index >= callee()->arg_size(); + } + + // Local slot helpers + protected: + bool local_slot_needs_write(int index, SharkValue* value) + { + return value && value->is_jobject(); + } + bool local_slot_needs_oopmap(int index, SharkValue* value) + { + return value && value->is_jobject(); + } + bool local_slot_needs_debuginfo(int index, SharkValue* value) + { + return true; + } +}; + +class SharkVMCallDecacher : public SharkDecacher { + public: + SharkVMCallDecacher(SharkFunction* function, int bci) + : SharkDecacher(function, bci) {} + + // Stack slot helpers + protected: + bool stack_slot_needs_write(int index, SharkValue* value) + { + return value && value->is_jobject(); + } + bool stack_slot_needs_oopmap(int index, SharkValue* value) + { + return value && value->is_jobject(); + } + bool stack_slot_needs_debuginfo(int index, SharkValue* value) + { + return true; + } + + // Local slot helpers + protected: + bool local_slot_needs_write(int index, SharkValue* value) + { + return value && value->is_jobject(); + } + bool local_slot_needs_oopmap(int index, SharkValue* value) + { + return value && value->is_jobject(); + } + bool local_slot_needs_debuginfo(int index, SharkValue* value) + { + return true; + } +}; + +class SharkTrapDecacher : public SharkDecacher { + public: + SharkTrapDecacher(SharkFunction* function, int bci) + : SharkDecacher(function, bci) {} + + // Stack slot helpers + protected: + bool stack_slot_needs_write(int index, SharkValue* value) + { + return value != NULL; + } + bool stack_slot_needs_oopmap(int index, SharkValue* value) + { + return value && value->is_jobject(); + } + bool stack_slot_needs_debuginfo(int index, SharkValue* value) + { + return true; + } + + // Local slot helpers + protected: + bool local_slot_needs_write(int index, SharkValue* value) + { + return value != NULL; + } + bool local_slot_needs_oopmap(int index, SharkValue* value) + { + return value && value->is_jobject(); + } + bool local_slot_needs_debuginfo(int index, SharkValue* value) + { + return true; + } +}; + +class SharkCacher : public SharkCacherDecacher { + protected: + SharkCacher(SharkFunction* function, int bci) + : SharkCacherDecacher(function, bci) {} + + // Callbacks + protected: + void start_stack(int num_slots, int max_slots); + void process_stack_slot(int index, SharkValue** value, int offset); + + void process_method_slot(llvm::Value** value, int offset); + + void process_local_slot(int index, SharkValue** value, int offset); + + // Stack slot helper + protected: + virtual bool stack_slot_needs_read(int index, SharkValue* value) = 0; + + // Local slot helper + protected: + bool local_slot_needs_read(int index, SharkValue* value) + { + return value && value->is_jobject(); + } +}; + +class SharkJavaCallCacher : public SharkCacher { + public: + SharkJavaCallCacher(SharkFunction* function, int bci, ciMethod* callee) + : SharkCacher(function, bci), _callee(callee) {} + + private: + ciMethod* _callee; + + protected: + ciMethod* callee() const + { + return _callee; + } + + // Stack slot helper + protected: + bool stack_slot_needs_read(int index, SharkValue* value) + { + return value && (index < callee()->return_type()->size() || + value->is_jobject()); + } +}; + +class SharkVMCallCacher : public SharkCacher { + public: + SharkVMCallCacher(SharkFunction* function, int bci) + : SharkCacher(function, bci) {} + + // Stack slot helper + protected: + bool stack_slot_needs_read(int index, SharkValue* value) + { + return value && value->is_jobject(); + } +}; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkCompiler.cpp --- a/ports/hotspot/src/share/vm/shark/sharkCompiler.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkCompiler.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -80,49 +80,31 @@ flow->print_on(tty); } - // Create the CodeBuffer and OopMapSet - BufferBlob *bb = BufferBlob::create( - "shark_temp", sizeof(SharkEntry) + target->code_size()); + // Create the recorders + Arena arena; + env->set_oop_recorder(new OopRecorder(&arena)); + OopMapSet oopmaps; + env->set_debug_info(new DebugInformationRecorder(env->oop_recorder())); + env->debug_info()->set_oopmaps(&oopmaps); + env->set_dependencies(new Dependencies(env)); + + // Create the CodeBuffer and MacroAssembler + BufferBlob *bb = BufferBlob::create("shark_temp", 256 * K); CodeBuffer cb(bb->instructions_begin(), bb->instructions_size()); - OopMapSet oopmaps; + cb.initialize_oop_recorder(env->oop_recorder()); + MacroAssembler *masm = new MacroAssembler(&cb); // Compile the method into the CodeBuffer ciBytecodeStream iter(target); - SharkFunction function(builder(), name, flow, &iter, &cb, &oopmaps); - if (env->failing()) - return; + SharkFunction function(builder(), name, flow, &iter, masm); // Install the method into the VM - install_method(env, target, entry_bci, &cb, &oopmaps); -} - -void SharkCompiler::install_method(ciEnv* env, - ciMethod* target, - int entry_bci, - CodeBuffer* cb, - OopMapSet* oopmaps) -{ - // Pretty much everything in this method is junk to stop - // ciEnv::register_method() from failing assertions. - - OopRecorder oop_recorder(env->arena()); - env->set_oop_recorder(&oop_recorder); - - DebugInformationRecorder debug_info(&oop_recorder); - debug_info.set_oopmaps(oopmaps); - env->set_debug_info(&debug_info); - - Dependencies deps(env); - env->set_dependencies(&deps); - CodeOffsets offsets; offsets.set_value(CodeOffsets::Deopt, 0); offsets.set_value(CodeOffsets::Exceptions, 0); offsets.set_value(CodeOffsets::Verified_Entry, target->is_static() ? 0 : wordSize); - cb->initialize_oop_recorder(&oop_recorder); - ExceptionHandlerTable handler_table; ImplicitExceptionTable inc_table; @@ -130,15 +112,18 @@ entry_bci, &offsets, 0, - cb, + &cb, 0, - oopmaps, + &oopmaps, &handler_table, &inc_table, this, env->comp_level(), false, false); + + // Free the BufferBlob + BufferBlob::free(bb); } const char* SharkCompiler::methodname(const ciMethod* target) diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkCompiler.hpp --- a/ports/hotspot/src/share/vm/shark/sharkCompiler.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkCompiler.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -57,13 +57,7 @@ return &_builder; } - // Helpers + // Helper private: - void install_method(ciEnv* env, - ciMethod* target, - int entry_bci, - CodeBuffer* cb, - OopMapSet* oopmaps); - static const char *methodname(const ciMethod* target); }; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp --- a/ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -156,3 +156,26 @@ return entry; } + +Value *SharkConstantPool::java_mirror() +{ + Value *cp = constants(); + + Value *pool_holder = builder()->CreateValueOfStructEntry( + cp, + in_ByteSize(constantPoolOopDesc::pool_holder_offset_in_bytes()), + SharkType::oop_type(), + "pool_holder"); + + Value *klass_part = builder()->CreateAddressOfStructEntry( + pool_holder, + in_ByteSize(klassOopDesc::klass_part_offset_in_bytes()), + SharkType::klass_type(), + "klass_part"); + + return builder()->CreateValueOfStructEntry( + klass_part, + in_ByteSize(Klass::java_mirror_offset_in_bytes()), + SharkType::oop_type(), + "java_mirror"); +} diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp --- a/ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -67,4 +67,5 @@ llvm::Value* object_at(int which); llvm::Value* tag_at(int which); llvm::Value* cache_entry_at(int which); + llvm::Value* java_mirror(); }; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkEntry.cpp --- a/ports/hotspot/src/share/vm/shark/sharkEntry.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkEntry.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -76,6 +76,19 @@ assert (instr == 0x7c0802a6, "expecting 'mflr r0'"); instr = *(pc++); + bool has_locals = (instr == NOT_LP64(0x93e1fffc) LP64_ONLY(0xf9e1fffc)); + if (has_locals) { + // 0xd04f3a60: mflr r0 + // 0xd04f3a64: stw r31,-4(r1) + // 0xd04f3a68: stw r0,4(r1) + // 0xd04f3a6c: stwu r1,-112(r1) + // 0xd04f3a70: mr r31,r1 + // 0xd04f3a74: stw r14,104(r31) + // ... + // 0xd04f3ab4: stw r30,40(r31) + return; + } + assert (instr == NOT_LP64(0x90010004) LP64_ONLY(0xf8010004), "expecting st" NOT_LP64("w") LP64_ONLY("d") " r0,4(r1)"); @@ -128,8 +141,6 @@ tty->print(", 1 register"); else tty->print(", %d registers", num_registers); - if (num_registers >= 19) - tty->print("!"); } #endif // PPC } diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkFunction.cpp --- a/ports/hotspot/src/share/vm/shark/sharkFunction.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkFunction.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -30,29 +30,30 @@ void SharkFunction::initialize() { - // Create the assembler and emit the entry point - _assembler = new MacroAssembler(cb()); - SharkEntry *entry = (SharkEntry *) assembler()->pc(); - assembler()->advance(sizeof(SharkEntry)); + // Emit the entry point + SharkEntry *entry = (SharkEntry *) masm()->pc(); + masm()->advance(sizeof(SharkEntry)); // Create the function _function = builder()->CreateFunction(); entry->set_llvm_function(function()); - // Initialize the blocks + // Create the list of blocks set_block_insertion_point(NULL); _blocks = NEW_RESOURCE_ARRAY(SharkBlock*, flow()->block_count()); for (int i = 0; i < block_count(); i++) _blocks[i] = new SharkBlock(this, flow()->pre_order_at(i)); - assert(block(0)->start() == 0, "blocks out of order"); + // Walk the tree from the start block to determine which + // blocks are entered and which blocks require phis SharkBlock *start_block = block(0); + assert(start_block->start() == 0, "blocks out of order"); + start_block->enter(); - start_block->add_predecessor(NULL); + // Initialize all entered blocks for (int i = 0; i < block_count(); i++) { - for (int j = 0; j < block(i)->num_successors(); j++) { - block(i)->successor(j)->add_predecessor(block(i)); - } + if (block(i)->entered()) + block(i)->initialize(); } // Initialize the monitors @@ -77,64 +78,40 @@ builder()->SetInsertPoint(CreateBlock()); CreateInitZeroStack(); CreatePushFrame(CreateBuildFrame()); - NOT_PRODUCT(builder()->CreateStore(method, method_slot())); + NOT_PRODUCT(builder()->CreateStore( + method, + CreateAddressOfFrameEntry( + method_slot_offset(), + SharkType::methodOop_type(), + "method_slot"))); // Lock if necessary + SharkState *entry_state = new SharkEntryState(method, start_block); if (target()->is_synchronized()) { - Value *object; - if (target()->is_static()) { - Value *constants = builder()->CreateValueOfStructEntry( - method, - methodOopDesc::constants_offset(), - SharkType::oop_type(), - "constants"); - - Value *pool_holder = builder()->CreateValueOfStructEntry( - constants, - in_ByteSize(constantPoolOopDesc::pool_holder_offset_in_bytes()), - SharkType::oop_type(), - "pool_holder"); + SharkBlock *locker = new SharkBlock(this, start_block->ciblock()); + locker->add_incoming(entry_state); - Value *klass_part = builder()->CreateAddressOfStructEntry( - pool_holder, - in_ByteSize(klassOopDesc::klass_part_offset_in_bytes()), - SharkType::klass_type(), - "klass_part"); + set_block_insertion_point(start_block->entry_block()); + locker->acquire_method_lock(); - object = builder()->CreateValueOfStructEntry( - klass_part, - in_ByteSize(Klass::java_mirror_offset_in_bytes()), - SharkType::oop_type(), - "java_mirror"); - } - else { - object = builder()->CreateLoad( - builder()->CreateBitCast( - builder()->CreateStructGEP(locals_slots(), max_locals() - 1), - PointerType::getUnqual(SharkType::oop_type()))); - } - monitor(0)->acquire(object); + entry_state = locker->current_state(); } // Transition into the method proper - start_block->add_incoming(new SharkEntryState(method, start_block)); + start_block->add_incoming(entry_state); builder()->CreateBr(start_block->entry_block()); // Parse the blocks for (int i = 0; i < block_count(); i++) { + if (!block(i)->entered()) + continue; + if (i + 1 < block_count()) set_block_insertion_point(block(i + 1)->entry_block()); else set_block_insertion_point(NULL); block(i)->parse(); - if (failing()) { - // XXX should delete function() here, but that breaks - // -XX:SharkPrintBitcodeOf. I guess some of the things - // we're sharing via SharkBuilder or SharkRuntime or - // SharkType are being freed - return; - } } // Dump the bitcode, if requested @@ -239,32 +216,21 @@ CreateStoreZeroStackPointer(zero_stack_pointer); // Create the frame - Value *frame = builder()->CreateIntToPtr( + _frame = builder()->CreateIntToPtr( zero_stack_pointer, PointerType::getUnqual( ArrayType::get(SharkType::intptr_type(), frame_words + locals_words)), "frame"); int offset = 0; - // Java stack + // Expression stack _stack_slots_offset = offset; - _stack_slots = builder()->CreateBitCast( - builder()->CreateStructGEP(frame, stack_slots_offset()), - PointerType::getUnqual( - ArrayType::get(SharkType::intptr_type(), stack_words)), - "stack_slots"); offset += stack_words; // Monitors if (monitor_count()) { _monitors_slots_offset = offset; - _monitors_slots = builder()->CreateBitCast( - builder()->CreateStructGEP(frame, monitors_slots_offset()), - PointerType::getUnqual( - ArrayType::get(SharkType::monitor_type(), monitor_count())), - "monitors"); - for (int i = 0; i < monitor_count(); i++) { if (i != 0 || !target()->is_synchronized()) monitor(i)->mark_free(); @@ -272,43 +238,51 @@ } offset += monitor_words; + // Exception pointer + _exception_slot_offset = offset++; + builder()->CreateStore(LLVMValue::null(), exception_slot()); + // Method pointer _method_slot_offset = offset++; - _method_slot = builder()->CreateBitCast( - builder()->CreateStructGEP(frame, method_slot_offset()), - PointerType::getUnqual(SharkType::methodOop_type()), - "method_slot"); // Unextended SP builder()->CreateStore( zero_stack_pointer, - builder()->CreateStructGEP(frame, offset++)); + CreateAddressOfFrameEntry(offset++)); // PC - _pc_slot = builder()->CreateBitCast( - builder()->CreateStructGEP(frame, offset++), - PointerType::getUnqual(SharkType::intptr_type()), - "pc_slot"); + _pc_slot_offset = offset++; // Frame header builder()->CreateStore( LLVMValue::intptr_constant(ZeroFrame::SHARK_FRAME), - builder()->CreateStructGEP(frame, offset++)); - Value *fp = builder()->CreateStructGEP(frame, offset++, "fp"); + CreateAddressOfFrameEntry(offset++)); + Value *fp = CreateAddressOfFrameEntry(offset++); // Local variables _locals_slots_offset = offset; - _locals_slots = builder()->CreateBitCast( - builder()->CreateStructGEP(frame, locals_slots_offset()), - PointerType::getUnqual( - ArrayType::get(SharkType::intptr_type(), locals_words)), - "locals_slots"); offset += locals_words; assert(offset == frame_words + locals_words, "should do"); return fp; } +Value* SharkFunction::CreateAddressOfFrameEntry(int offset, + const llvm::Type* type, + const char* name) const +{ + bool needs_cast = type && type != SharkType::intptr_type(); + + Value* result = builder()->CreateStructGEP( + _frame, offset, needs_cast ? "" : name); + + if (needs_cast) { + result = builder()->CreateBitCast( + result, PointerType::getUnqual(type), name); + } + return result; +} + SharkMonitor* SharkFunction::monitor(Value *index) const { Value *indexes[] = { diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkFunction.hpp --- a/ports/hotspot/src/share/vm/shark/sharkFunction.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkFunction.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -32,14 +32,12 @@ const char* name, ciTypeFlow* flow, ciBytecodeStream* iter, - CodeBuffer* cb, - OopMapSet* oopmaps) + MacroAssembler* masm) : _builder(builder), _name(name), _flow(flow), _iter(iter), - _cb(cb), - _oopmaps(oopmaps) + _masm(masm) { initialize(); } private: @@ -50,9 +48,7 @@ const char* _name; ciTypeFlow* _flow; ciBytecodeStream* _iter; - CodeBuffer* _cb; - OopMapSet* _oopmaps; - MacroAssembler* _assembler; + MacroAssembler* _masm; llvm::Function* _function; SharkBlock** _blocks; llvm::Value* _base_pc; @@ -76,17 +72,9 @@ { return _iter; } - CodeBuffer* cb() const - { - return _cb; - } - OopMapSet* oopmaps() const + MacroAssembler* masm() const { - return _oopmaps; - } - MacroAssembler* assembler() const - { - return _assembler; + return _masm; } llvm::Function* function() const { @@ -118,6 +106,14 @@ { return flow()->block_count(); } + DebugInformationRecorder *debug_info() const + { + return env()->debug_info(); + } + ciEnv* env() const + { + return flow()->env(); + } int max_locals() const { return flow()->max_locals(); @@ -131,20 +127,6 @@ return flow()->method(); } - public: - ciEnv* env() const - { - return flow()->env(); - } - bool failing() const - { - return env()->failing(); - } - void record_method_not_compilable(const char* reason) const - { - env()->record_method_not_compilable(reason); - } - // Block management private: llvm::BasicBlock* _block_insertion_point; @@ -216,32 +198,26 @@ // Frame management private: - llvm::Value* _pc_slot; - llvm::Value* _method_slot; - llvm::Value* _locals_slots; - llvm::Value* _monitors_slots; - llvm::Value* _stack_slots; + llvm::Value* _frame; public: - llvm::Value* pc_slot() const - { - return _pc_slot; - } - llvm::Value* method_slot() const + llvm::Value* CreateAddressOfFrameEntry(int offset, + const llvm::Type* type = NULL, + const char* name = "") const; + public: + llvm::Value* exception_slot() const { - return _method_slot; - } - llvm::Value* locals_slots() const - { - return _locals_slots; - } + return CreateAddressOfFrameEntry( + exception_slot_offset(), + SharkType::oop_type(), + "exception_slot"); + } llvm::Value* monitors_slots() const { - return _monitors_slots; - } - llvm::Value* stack_slots() const - { - return _stack_slots; + return CreateAddressOfFrameEntry( + monitors_slots_offset(), + llvm::ArrayType::get(SharkType::monitor_type(), monitor_count()), + "monitors"); } public: @@ -258,20 +234,18 @@ public: int code_offset() const { - int offset = assembler()->offset(); - assembler()->advance(1); // keeps PCs unique + int offset = masm()->offset(); + masm()->advance(1); // keeps PCs unique return offset; } - void add_gc_map(int offset, OopMap* oopmap) - { - oopmaps()->add_gc_map(offset, oopmap); - } private: int _oopmap_frame_size; int _stack_slots_offset; int _monitors_slots_offset; + int _exception_slot_offset; int _method_slot_offset; + int _pc_slot_offset; int _locals_slots_offset; public: @@ -287,10 +261,18 @@ { return _monitors_slots_offset; } + int exception_slot_offset() const + { + return _exception_slot_offset; + } int method_slot_offset() const { return _method_slot_offset; } + int pc_slot_offset() const + { + return _pc_slot_offset; + } int locals_slots_offset() const { return _locals_slots_offset; @@ -329,4 +311,20 @@ builder()->CreateStore(LLVMValue::null(), addr); return result; } + + public: + llvm::Value* pending_exception_address() const + { + return builder()->CreateAddressOfStructEntry( + thread(), Thread::pending_exception_offset(), + llvm::PointerType::getUnqual(SharkType::jobject_type()), + "pending_exception_addr"); + } + llvm::LoadInst* CreateGetPendingException() const + { + llvm::Value *addr = pending_exception_address(); + llvm::LoadInst *result = builder()->CreateLoad(addr, "pending_exception"); + builder()->CreateStore(LLVMValue::null(), addr); + return result; + } }; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkMonitor.cpp --- a/ports/hotspot/src/share/vm/shark/sharkMonitor.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkMonitor.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -43,11 +43,12 @@ "displaced_header_addr"); } -void SharkMonitor::acquire(Value *lockee) const +void SharkMonitor::acquire(SharkBlock* block, Value *lockee) const { BasicBlock *try_recursive = function()->CreateBlock("try_recursive"); BasicBlock *got_recursive = function()->CreateBlock("got_recursive"); BasicBlock *not_recursive = function()->CreateBlock("not_recursive"); + BasicBlock *acquired_fast = function()->CreateBlock("acquired_fast"); BasicBlock *lock_acquired = function()->CreateBlock("lock_acquired"); set_object(lockee); @@ -69,7 +70,7 @@ Value *check = builder()->CreateCmpxchgPtr(lock, mark_addr, disp); builder()->CreateCondBr( builder()->CreateICmpEQ(disp, check), - lock_acquired, try_recursive); + acquired_fast, try_recursive); // Locking failed, but maybe this thread already owns it builder()->SetInsertPoint(try_recursive); @@ -101,21 +102,29 @@ builder()->SetInsertPoint(got_recursive); set_displaced_header(LLVMValue::intptr_constant(0)); + builder()->CreateBr(acquired_fast); + + // Create an edge for the state merge + builder()->SetInsertPoint(acquired_fast); + SharkState *fast_state = block->current_state()->copy(); builder()->CreateBr(lock_acquired); // It's not a recursive case so we need to drop into the runtime builder()->SetInsertPoint(not_recursive); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); + block->call_vm_nocheck(SharkRuntime::monitorenter(), monitor()); + BasicBlock *acquired_slow = builder()->GetInsertBlock(); + builder()->CreateBr(lock_acquired); // All done - builder()->SetInsertPoint(lock_acquired); + builder()->SetInsertPoint(lock_acquired); + block->current_state()->merge(fast_state, acquired_fast, acquired_slow); } -void SharkMonitor::release() const +void SharkMonitor::release(SharkBlock* block) const { BasicBlock *not_recursive = function()->CreateBlock("not_recursive"); - BasicBlock *call_runtime = function()->CreateBlock("call_runtime"); + BasicBlock *released_fast = function()->CreateBlock("released_fast"); + BasicBlock *slow_path = function()->CreateBlock("slow_path"); BasicBlock *lock_released = function()->CreateBlock("lock_released"); Value *disp = displaced_header(); @@ -125,7 +134,7 @@ // If it is recursive then we're already done builder()->CreateCondBr( builder()->CreateICmpEQ(disp, LLVMValue::intptr_constant(0)), - lock_released, not_recursive); + released_fast, not_recursive); // Try a simple unlock builder()->SetInsertPoint(not_recursive); @@ -141,14 +150,21 @@ Value *check = builder()->CreateCmpxchgPtr(disp, mark_addr, lock); builder()->CreateCondBr( builder()->CreateICmpEQ(lock, check), - lock_released, call_runtime); + released_fast, slow_path); + + // Create an edge for the state merge + builder()->SetInsertPoint(released_fast); + SharkState *fast_state = block->current_state()->copy(); + builder()->CreateBr(lock_released); // Need to drop into the runtime to release this one - builder()->SetInsertPoint(call_runtime); + builder()->SetInsertPoint(slow_path); set_object(lockee); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); + block->call_vm_nocheck(SharkRuntime::monitorexit(), monitor()); + BasicBlock *released_slow = builder()->GetInsertBlock(); + builder()->CreateBr(lock_released); // All done builder()->SetInsertPoint(lock_released); + block->current_state()->merge(fast_state, released_fast, released_slow); } diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkMonitor.hpp --- a/ports/hotspot/src/share/vm/shark/sharkMonitor.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkMonitor.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -23,6 +23,8 @@ * */ +class SharkBlock; + class SharkMonitor : public ResourceObj { public: SharkMonitor(const SharkFunction* function, llvm::Value* monitor) @@ -87,6 +89,6 @@ } public: - void acquire(llvm::Value* lockee) const; - void release() const; + void acquire(SharkBlock* block, llvm::Value* lockee) const; + void release(SharkBlock* block) const; }; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkRuntime.cpp --- a/ports/hotspot/src/share/vm/shark/sharkRuntime.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkRuntime.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -28,35 +28,85 @@ using namespace llvm; +Constant* SharkRuntime::_find_exception_handler; +Constant* SharkRuntime::_monitorenter; +Constant* SharkRuntime::_monitorexit; +Constant* SharkRuntime::_new_instance; Constant* SharkRuntime::_newarray; -Constant* SharkRuntime::_new_instance; +Constant* SharkRuntime::_anewarray; +Constant* SharkRuntime::_multianewarray; Constant* SharkRuntime::_resolve_get_put; Constant* SharkRuntime::_resolve_invoke; +Constant* SharkRuntime::_resolve_klass; +Constant* SharkRuntime::_safepoint; +Constant* SharkRuntime::_throw_ArrayIndexOutOfBoundsException; +Constant* SharkRuntime::_throw_NullPointerException; +Constant* SharkRuntime::_trace_bytecode; Constant* SharkRuntime::_dump; Constant* SharkRuntime::_is_subtype_of; Constant* SharkRuntime::_should_not_reach_here; Constant* SharkRuntime::_unimplemented; +Constant* SharkRuntime::_uncommon_trap; void SharkRuntime::initialize(SharkBuilder* builder) { // VM calls std::vector params; params.push_back(SharkType::thread_type()); + params.push_back(PointerType::getUnqual(SharkType::jint_type())); + params.push_back(SharkType::jint_type()); + _find_exception_handler = builder->make_function( + (intptr_t) find_exception_handler_C, + FunctionType::get(SharkType::jint_type(), params, false), + "SharkRuntime__find_exception_handler"); + + params.clear(); + params.push_back(SharkType::thread_type()); + params.push_back(PointerType::getUnqual(SharkType::monitor_type())); + _monitorenter = builder->make_function( + (intptr_t) monitorenter_C, + FunctionType::get(Type::VoidTy, params, false), + "SharkRuntime__monitorenter"); + _monitorexit = builder->make_function( + (intptr_t) monitorexit_C, + FunctionType::get(Type::VoidTy, params, false), + "SharkRuntime__monitorexit"); + + params.clear(); + params.push_back(SharkType::thread_type()); + params.push_back(SharkType::jint_type()); + _new_instance = builder->make_function( + (intptr_t) new_instance_C, + FunctionType::get(Type::VoidTy, params, false), + "SharkRuntime__new_instance"); + _resolve_klass = builder->make_function( + (intptr_t) resolve_klass_C, + FunctionType::get(Type::VoidTy, params, false), + "SharkRuntime__resolve_klass"); + + params.clear(); + params.push_back(SharkType::thread_type()); params.push_back(SharkType::jint_type()); params.push_back(SharkType::jint_type()); _newarray = builder->make_function( (intptr_t) newarray_C, FunctionType::get(Type::VoidTy, params, false), "SharkRuntime__newarray"); + _anewarray = builder->make_function( + (intptr_t) anewarray_C, + FunctionType::get(Type::VoidTy, params, false), + "SharkRuntime__anewarray"); params.clear(); params.push_back(SharkType::thread_type()); - params.push_back(SharkType::jobject_type()); - _new_instance = builder->make_function( - (intptr_t) new_instance_C, + params.push_back(SharkType::jint_type()); + params.push_back(SharkType::jint_type()); + params.push_back(PointerType::getUnqual(SharkType::jint_type())); + _multianewarray = builder->make_function( + (intptr_t) multianewarray_C, FunctionType::get(Type::VoidTy, params, false), - "SharkRuntime__new_instance"); + "SharkRuntime__multianewarray"); params.clear(); params.push_back(SharkType::thread_type()); @@ -72,6 +122,42 @@ FunctionType::get(Type::VoidTy, params, false), "SharkRuntime__resolve_invoke"); + params.clear(); + params.push_back(SharkType::thread_type()); + _safepoint = builder->make_function( + (intptr_t) SafepointSynchronize::block, + FunctionType::get(Type::VoidTy, params, false), + "SafepointSynchronize__block"); + + params.clear(); + params.push_back(SharkType::thread_type()); + params.push_back(SharkType::intptr_type()); + params.push_back(SharkType::jint_type()); + params.push_back(SharkType::jint_type()); + _throw_ArrayIndexOutOfBoundsException = builder->make_function( + (intptr_t) throw_ArrayIndexOutOfBoundsException_C, + FunctionType::get(Type::VoidTy, params, false), + "SharkRuntime__throw_ArrayIndexOutOfBoundsException"); + + params.clear(); + params.push_back(SharkType::thread_type()); + params.push_back(SharkType::intptr_type()); + params.push_back(SharkType::jint_type()); + _throw_NullPointerException = builder->make_function( + (intptr_t) throw_NullPointerException_C, + FunctionType::get(Type::VoidTy, params, false), + "SharkRuntime__throw_NullPointerException"); + + params.clear(); + params.push_back(SharkType::thread_type()); + params.push_back(SharkType::jint_type()); + params.push_back(SharkType::intptr_type()); + params.push_back(SharkType::intptr_type()); + _trace_bytecode = builder->make_function( + (intptr_t) trace_bytecode_C, + FunctionType::get(Type::VoidTy, params, false), + "SharkRuntime__trace_bytecode"); + // Non-VM calls params.clear(); params.push_back(SharkType::intptr_type()); @@ -101,41 +187,130 @@ (intptr_t) report_unimplemented, FunctionType::get(Type::VoidTy, params, false), "report_unimplemented"); + + params.clear(); + params.push_back(SharkType::thread_type()); + params.push_back(SharkType::jint_type()); + _uncommon_trap = builder->make_function( + (intptr_t) uncommon_trap_C, + FunctionType::get(Type::VoidTy, params, false), + "SharkRuntime__uncommon_trap"); } +JRT_ENTRY(int, SharkRuntime::find_exception_handler_C(JavaThread* thread, + int* indexes, + int num_indexes)) +{ + constantPoolHandle pool(thread, method(thread)->constants()); + KlassHandle exc_klass(thread, ((oop) tos_at(thread, 0))->klass()); + + for (int i = 0; i < num_indexes; i++) { + klassOop tmp = pool->klass_at(indexes[i], CHECK_0); + KlassHandle chk_klass(thread, tmp); + + if (exc_klass() == chk_klass()) + return i; + + if (exc_klass()->klass_part()->is_subtype_of(chk_klass())) + return i; + } + + return -1; +} +JRT_END + +JRT_ENTRY(void, SharkRuntime::monitorenter_C(JavaThread* thread, + BasicObjectLock* lock)) +{ + if (PrintBiasedLockingStatistics) + Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); + + Handle object(thread, lock->obj()); + assert(Universe::heap()->is_in_reserved_or_null(object()), "should be"); + if (UseBiasedLocking) { + // Retry fast entry if bias is revoked to avoid unnecessary inflation + ObjectSynchronizer::fast_enter(object, lock->lock(), true, CHECK); + } else { + ObjectSynchronizer::slow_enter(object, lock->lock(), CHECK); + } + assert(Universe::heap()->is_in_reserved_or_null(lock->obj()), "should be"); +} +JRT_END + +JRT_ENTRY(void, SharkRuntime::monitorexit_C(JavaThread* thread, + BasicObjectLock* lock)) +{ + Handle object(thread, lock->obj()); + assert(Universe::heap()->is_in_reserved_or_null(object()), "should be"); + if (lock == NULL || object()->is_unlocked()) { + THROW(vmSymbols::java_lang_IllegalMonitorStateException()); + } + ObjectSynchronizer::slow_exit(object(), lock->lock(), thread); + + // Free entry. This must be done here, since a pending exception + // might be installed on exit. If it is not cleared, the exception + // handling code will try to unlock the monitor again. + lock->set_obj(NULL); +} +JRT_END + +JRT_ENTRY(void, SharkRuntime::new_instance_C(JavaThread* thread, int index)) +{ + klassOop k_oop = method(thread)->constants()->klass_at(index, CHECK); + instanceKlassHandle klass(THREAD, k_oop); + + // Make sure we are not instantiating an abstract klass + klass->check_valid_for_instantiation(true, CHECK); + + // Make sure klass is initialized + klass->initialize(CHECK); + + // At this point the class may not be fully initialized + // because of recursive initialization. If it is fully + // initialized & has_finalized is not set, we rewrite + // it into its fast version (Note: no locking is needed + // here since this is an atomic byte write and can be + // done more than once). + // + // Note: In case of classes with has_finalized we don't + // rewrite since that saves us an extra check in + // the fast version which then would call the + // slow version anyway (and do a call back into + // Java). + // If we have a breakpoint, then we don't rewrite + // because the _breakpoint bytecode would be lost. + oop obj = klass->allocate_instance(CHECK); + thread->set_vm_result(obj); +} +JRT_END + JRT_ENTRY(void, SharkRuntime::newarray_C(JavaThread* thread, - BasicType type, - int size)) + BasicType type, + int size)) { oop obj = oopFactory::new_typeArray(type, size, CHECK); thread->set_vm_result(obj); } JRT_END -JRT_ENTRY(void, SharkRuntime::new_instance_C(JavaThread* thread, - klassOop klass)) +JRT_ENTRY(void, SharkRuntime::anewarray_C(JavaThread* thread, + int index, + int size)) { - // These checks are cheap to make and support reflective allocation. - int lh = Klass::cast(klass)->layout_helper(); - if (Klass::layout_helper_needs_slow_path(lh) - || !instanceKlass::cast(klass)->is_initialized()) { - KlassHandle kh(THREAD, klass); - kh->check_valid_for_instantiation(false, THREAD); - if (!HAS_PENDING_EXCEPTION) { - instanceKlass::cast(kh())->initialize(THREAD); - } - if (!HAS_PENDING_EXCEPTION) { - klass = kh(); - } else { - klass = NULL; - } - } + klassOop klass = method(thread)->constants()->klass_at(index, CHECK); + objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK); + thread->set_vm_result(obj); +} +JRT_END - if (klass != NULL) { - // Scavenge and allocate an instance. - oop result = instanceKlass::cast(klass)->allocate_instance(THREAD); - thread->set_vm_result(result); - } +JRT_ENTRY(void, SharkRuntime::multianewarray_C(JavaThread* thread, + int index, + int ndims, + int* dims)) +{ + klassOop klass = method(thread)->constants()->klass_at(index, CHECK); + oop obj = arrayKlass::cast(klass)->multi_allocate(ndims, dims, CHECK); + thread->set_vm_result(obj); } JRT_END @@ -144,7 +319,59 @@ int bci, Bytecodes::Code bytecode)) { - Unimplemented(); + // Resolve the field + FieldAccessInfo info; + { + constantPoolHandle pool(thread, method(thread)->constants()); + JvmtiHideSingleStepping jhss(thread); + LinkResolver::resolve_field( + info, pool, two_byte_index(thread, bci), bytecode, false, CHECK); + } + + // Check if link resolution caused the cache to be updated + if (entry->is_resolved(bytecode)) + return; + + // Compute auxiliary field attributes + TosState state = as_TosState(info.field_type()); + + // We need to delay resolving put instructions on final fields + // until we actually invoke one. This is required so we throw + // exceptions at the correct place. If we do not resolve completely + // in the current pass, leaving the put_code set to zero will + // cause the next put instruction to reresolve. + bool is_put = + (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_putstatic); + Bytecodes::Code put_code = (Bytecodes::Code) 0; + + // We also need to delay resolving getstatic instructions until the + // class is intitialized. This is required so that access to the + // static field will call the initialization function every time + // until the class is completely initialized as per 2.17.5 in JVM + // Specification. + instanceKlass *klass = instanceKlass::cast(info.klass()->as_klassOop()); + bool is_static = + (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic); + bool uninitialized_static = (is_static && !klass->is_initialized()); + Bytecodes::Code get_code = (Bytecodes::Code) 0; + + if (!uninitialized_static) { + get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield); + if (is_put || !info.access_flags().is_final()) { + put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield); + } + } + + // Update the cache entry + entry->set_field( + get_code, + put_code, + info.klass(), + info.field_index(), + info.field_offset(), + state, + info.access_flags().is_final(), + info.access_flags().is_volatile()); } JRT_END @@ -155,7 +382,8 @@ { // Find the receiver Handle receiver(thread, NULL); - if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) { + if (bytecode == Bytecodes::_invokevirtual || + bytecode == Bytecodes::_invokeinterface) { ResourceMark rm(thread); methodHandle mh(thread, method(thread)); Bytecode_invoke *call = Bytecode_invoke_at(mh, bci); @@ -190,22 +418,80 @@ } } - // Update the cache entry if necessary + // Check if link resolution caused the cache to be updated if (entry->is_resolved(bytecode)) return; + // Update the cache entry + methodHandle rm = info.resolved_method(); if (bytecode == Bytecodes::_invokeinterface) { - Unimplemented(); + if (rm->method_holder() == SystemDictionary::object_klass()) { + // Workaround for the case where we encounter an invokeinterface, + // but should really have an invokevirtual since the resolved + // method is a virtual method in java.lang.Object. This is a + // corner case in the spec but is presumably legal, and while + // javac does not generate this code there's no reason it could + // not be produced by a compliant java compiler. See + // cpCacheOop.cpp for more details. + assert(rm->is_final() || info.has_vtable_index(), "should be set"); + entry->set_method(bytecode, rm, info.vtable_index()); + } + else { + entry->set_interface_call(rm, klassItable::compute_itable_index(rm())); + } } else { - entry->set_method( - bytecode, - info.resolved_method(), - info.vtable_index()); + entry->set_method(bytecode, rm, info.vtable_index()); } } JRT_END +JRT_ENTRY(void, SharkRuntime::resolve_klass_C(JavaThread* thread, int index)) +{ + klassOop klass = method(thread)->constants()->klass_at(index, CHECK); + thread->set_vm_result(klass); +} +JRT_END + +JRT_ENTRY(void, SharkRuntime::throw_ArrayIndexOutOfBoundsException_C( + JavaThread* thread, + const char* file, + int line, + int index)) +{ + char msg[jintAsStringSize]; + snprintf(msg, sizeof(msg), "%d", index); + Exceptions::_throw_msg( + thread, file, line, + vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), + msg); +} +JRT_END + +JRT_ENTRY(void, SharkRuntime::throw_NullPointerException_C(JavaThread* thread, + const char* file, + int line)) +{ + Exceptions::_throw_msg( + thread, file, line, + vmSymbols::java_lang_NullPointerException(), + ""); +} +JRT_END + +JRT_ENTRY(void, SharkRuntime::trace_bytecode_C(JavaThread* thread, + int bci, + intptr_t tos, + intptr_t tos2)) +{ +#ifndef PRODUCT + methodHandle mh(thread, method(thread)); + //BytecodeCounter::_counter_value++; + BytecodeTracer::trace(mh, mh->code_base() + bci, tos, tos2); +#endif // !PRODUCT +} +JRT_END + // Non-VM calls // Nothing in these must ever GC! @@ -226,3 +512,64 @@ { return object_klass->klass_part()->is_subtype_of(check_klass); } + +void SharkRuntime::uncommon_trap_C(JavaThread* thread, int index) +{ + // In C2, uncommon_trap_blob creates a frame, so all the various + // deoptimization functions expect to find the frame of the method + // being deopted one frame down on the stack. Create a dummy frame + // to mirror this. + ZeroStack *stack = thread->zero_stack(); + thread->push_zero_frame(DeoptimizerFrame::build(stack)); + + // Initiate the trap + thread->set_last_Java_frame(); + Deoptimization::UnrollBlock *urb = + Deoptimization::uncommon_trap(thread, index); + thread->reset_last_Java_frame(); + + // Pop our dummy frame and the frame being deoptimized + thread->pop_zero_frame(); + thread->pop_zero_frame(); + + // Push skeleton frames + int number_of_frames = urb->number_of_frames(); + for (int i = 0; i < number_of_frames; i++) { + intptr_t size = urb->frame_sizes()[i]; + thread->push_zero_frame(InterpreterFrame::build(stack, size)); + } + + // Push another dummy frame + thread->push_zero_frame(DeoptimizerFrame::build(stack)); + + // Fill in the skeleton frames + thread->set_last_Java_frame(); + Deoptimization::unpack_frames(thread, Deoptimization::Unpack_uncommon_trap); + thread->reset_last_Java_frame(); + + // Pop our dummy frame + thread->pop_zero_frame(); + + // Jump into the interpreter +#ifdef CC_INTERP + CppInterpreter::main_loop(number_of_frames - 1, thread); +#else + Unimplemented(); +#endif // CC_INTERP +} + +DeoptimizerFrame* DeoptimizerFrame::build(ZeroStack* stack) +{ + if (header_words > stack->available_words()) { + Unimplemented(); + } + + stack->push(0); // next_frame, filled in later + intptr_t *fp = stack->sp(); + assert(fp - stack->sp() == next_frame_off, "should be"); + + stack->push(DEOPTIMIZER_FRAME); + assert(fp - stack->sp() == frame_type_off, "should be"); + + return (DeoptimizerFrame *) fp; +} diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkRuntime.hpp --- a/ports/hotspot/src/share/vm/shark/sharkRuntime.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkRuntime.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -29,19 +29,49 @@ // VM calls private: + static llvm::Constant* _find_exception_handler; + static llvm::Constant* _monitorenter; + static llvm::Constant* _monitorexit; + static llvm::Constant* _new_instance; static llvm::Constant* _newarray; - static llvm::Constant* _new_instance; + static llvm::Constant* _anewarray; + static llvm::Constant* _multianewarray; static llvm::Constant* _resolve_get_put; static llvm::Constant* _resolve_invoke; + static llvm::Constant* _resolve_klass; + static llvm::Constant* _safepoint; + static llvm::Constant* _throw_ArrayIndexOutOfBoundsException; + static llvm::Constant* _throw_NullPointerException; + static llvm::Constant* _trace_bytecode; public: + static llvm::Constant* find_exception_handler() + { + return _find_exception_handler; + } + static llvm::Constant* monitorenter() + { + return _monitorenter; + } + static llvm::Constant* monitorexit() + { + return _monitorexit; + } + static llvm::Constant* new_instance() + { + return _new_instance; + } static llvm::Constant* newarray() { return _newarray; } - static llvm::Constant* new_instance() + static llvm::Constant* anewarray() { - return _new_instance; + return _anewarray; + } + static llvm::Constant* multianewarray() + { + return _multianewarray; } static llvm::Constant* resolve_get_put() { @@ -51,10 +81,43 @@ { return _resolve_invoke; } + static llvm::Constant* resolve_klass() + { + return _resolve_klass; + } + static llvm::Constant* safepoint() + { + return _safepoint; + } + static llvm::Constant* throw_ArrayIndexOutOfBoundsException() + { + return _throw_ArrayIndexOutOfBoundsException; + } + static llvm::Constant* throw_NullPointerException() + { + return _throw_NullPointerException; + } + static llvm::Constant* trace_bytecode() + { + return _trace_bytecode; + } private: + static int find_exception_handler_C(JavaThread* thread, + int* indexes, + int num_indexes); + + static void monitorenter_C(JavaThread* thread, BasicObjectLock* lock); + static void monitorexit_C(JavaThread* thread, BasicObjectLock* lock); + + static void new_instance_C(JavaThread* thread, int index); static void newarray_C(JavaThread* thread, BasicType type, int size); - static void new_instance_C(JavaThread* thread, klassOop klass); + static void anewarray_C(JavaThread* thread, int index, int size); + static void multianewarray_C(JavaThread* thread, + int index, + int ndims, + int* dims); + static void resolve_get_put_C(JavaThread* thread, ConstantPoolCacheEntry* entry, int bci, @@ -63,6 +126,18 @@ ConstantPoolCacheEntry* entry, int bci, Bytecodes::Code bytecode); + static void resolve_klass_C(JavaThread* thread, int index); + static void throw_ArrayIndexOutOfBoundsException_C(JavaThread* thread, + const char* file, + int line, + int index); + static void throw_NullPointerException_C(JavaThread* thread, + const char* file, + int line); + static void trace_bytecode_C(JavaThread* thread, + int bci, + intptr_t tos, + intptr_t tos2); // Helpers for VM calls private: @@ -93,6 +168,7 @@ static llvm::Constant* _is_subtype_of; static llvm::Constant* _should_not_reach_here; static llvm::Constant* _unimplemented; + static llvm::Constant* _uncommon_trap; public: static llvm::Constant* dump() @@ -111,8 +187,13 @@ { return _unimplemented; } + static llvm::Constant* uncommon_trap() + { + return _uncommon_trap; + } private: static void dump_C(const char *name, intptr_t value); static bool is_subtype_of_C(klassOop check_klass, klassOop object_klass); + static void uncommon_trap_C(JavaThread* thread, int index); }; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkState.cpp --- a/ports/hotspot/src/share/vm/shark/sharkState.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkState.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -28,10 +28,22 @@ using namespace llvm; -void SharkState::initialize() +void SharkState::initialize(const SharkState *state) { _locals = NEW_RESOURCE_ARRAY(SharkValue*, max_locals()); _stack = NEW_RESOURCE_ARRAY(SharkValue*, max_stack()); + + if (state) { + memcpy(_locals, state->_locals, max_locals() * sizeof(SharkValue *)); + memcpy(_stack, state->_stack, max_stack() * sizeof(SharkValue *)); + _sp = _stack + state->stack_depth(); + } + else { + _sp = _stack; + + NOT_PRODUCT(memset(_locals, 23, max_locals() * sizeof(SharkValue *))); + NOT_PRODUCT(memset(_stack, 23, max_stack() * sizeof(SharkValue *))); + } } void SharkEntryState::initialize(Value* method) @@ -39,50 +51,51 @@ char name[18]; // Method - _method = method; + set_method(method); // Local variables for (int i = 0; i < max_locals(); i++) { - SharkValue *value = NULL; ciType *type = block()->local_type_at_entry(i); - switch (type->basic_type()) { - case ciTypeFlow::StateVector::T_BOTTOM: - case ciTypeFlow::StateVector::T_LONG2: - case ciTypeFlow::StateVector::T_DOUBLE2: - break; - case ciTypeFlow::StateVector::T_TOP: - Unimplemented(); - break; - - case ciTypeFlow::StateVector::T_NULL: - ShouldNotReachHere(); - break; - - default: + SharkValue *value = NULL; + switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: if (i < function()->arg_size()) { snprintf(name, sizeof(name), "local_%d_", i); value = SharkValue::create_generic( type, builder()->CreateLoad( - builder()->CreateBitCast( - builder()->CreateStructGEP( - function()->locals_slots(), - max_locals() - type->size() - i), - PointerType::getUnqual(SharkType::to_stackType(type))), + function()->CreateAddressOfFrameEntry( + function()->locals_slots_offset() + + max_locals() - type->size() - i, + SharkType::to_stackType(type)), name)); } else { Unimplemented(); } + break; + + case ciTypeFlow::StateVector::T_BOTTOM: + break; + + case ciTypeFlow::StateVector::T_LONG2: + case ciTypeFlow::StateVector::T_DOUBLE2: + break; + + default: + ShouldNotReachHere(); } - _locals[i] = value; + set_local(i, value); } // Expression stack - assert(!block()->stack_depth_at_entry(), "entry block shouldn't have stack"); - memset(_stack, 0, sizeof(SharkValue*) * max_stack()); - _sp = _stack; + assert(!stack_depth_at_entry(), "entry block shouldn't have stack"); } void SharkPHIState::initialize() @@ -92,61 +105,80 @@ char name[18]; // Method - _method = builder()->CreatePHI(SharkType::methodOop_type(), "method"); + set_method(builder()->CreatePHI(SharkType::methodOop_type(), "method")); // Local variables for (int i = 0; i < max_locals(); i++) { + ciType *type = block()->local_type_at_entry(i); + if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { + // XXX we could do all kinds of clever stuff here + type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? + } + SharkValue *value = NULL; - ciType *type = block()->local_type_at_entry(i); switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: + snprintf(name, sizeof(name), "local_%d_", i); + value = SharkValue::create_generic( + type, builder()->CreatePHI(SharkType::to_stackType(type), name)); + break; + + case T_ADDRESS: + value = SharkValue::create_returnAddress(block()->jsr_ret_bci()); + break; + case ciTypeFlow::StateVector::T_BOTTOM: + break; + case ciTypeFlow::StateVector::T_LONG2: case ciTypeFlow::StateVector::T_DOUBLE2: break; - case ciTypeFlow::StateVector::T_TOP: - Unimplemented(); - break; - - case ciTypeFlow::StateVector::T_NULL: - // XXX we could do all kinds of clever stuff here - type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? - // fall through - default: - snprintf(name, sizeof(name), "local_%d_", i); - value = SharkValue::create_generic( - type, builder()->CreatePHI(SharkType::to_stackType(type), name)); + ShouldNotReachHere(); } - _locals[i] = value; + set_local(i, value); } // Expression stack - _sp = _stack; - for (int i = 0; i < max_stack(); i++) { - if (i < block()->stack_depth_at_entry()) { - ciType *type = block()->stack_type_at_entry(i); - switch (type->basic_type()) { - case ciTypeFlow::StateVector::T_TOP: - case ciTypeFlow::StateVector::T_BOTTOM: - case ciTypeFlow::StateVector::T_NULL: - Unimplemented(); - break; + for (int i = 0; i < stack_depth_at_entry(); i++) { + ciType *type = block()->stack_type_at_entry(i); + if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { + // XXX we could do all kinds of clever stuff here + type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? + } - case ciTypeFlow::StateVector::T_LONG2: - case ciTypeFlow::StateVector::T_DOUBLE2: - break; + SharkValue *value = NULL; + switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: + snprintf(name, sizeof(name), "stack_%d_", i); + value = SharkValue::create_generic( + type, builder()->CreatePHI(SharkType::to_stackType(type), name)); + break; - default: - snprintf(name, sizeof(name), "stack_%d_", i); - *(_sp++) = SharkValue::create_generic( - type, builder()->CreatePHI(SharkType::to_stackType(type), name)); - } + case T_ADDRESS: + value = SharkValue::create_returnAddress(block()->jsr_ret_bci()); + break; + + case ciTypeFlow::StateVector::T_LONG2: + case ciTypeFlow::StateVector::T_DOUBLE2: + break; + + default: + ShouldNotReachHere(); } + push(value); } -#ifdef ASSERT - _stack_depth_at_entry = stack_depth(); -#endif // ASSERT builder()->SetInsertPoint(saved_insert_point); } @@ -160,132 +192,194 @@ // Local variables for (int i = 0; i < max_locals(); i++) { - if (local(i) != NULL) { - ((PHINode *) local(i)->generic_value())->addIncoming( - incoming_state->local(i)->generic_value(), predecessor); - } + if (local(i) != NULL) + local(i)->addIncoming(incoming_state->local(i), predecessor); } // Expression stack - assert(_stack_depth_at_entry == incoming_state->stack_depth(), "should be"); - for (int i = 0; i < incoming_state->stack_depth(); i++) { - ((PHINode *) stack(i)->generic_value())->addIncoming( - incoming_state->stack(i)->generic_value(), - predecessor); + assert(stack_depth_at_entry() == incoming_state->stack_depth(), "should be"); + for (int i = 0; i < stack_depth_at_entry(); i++) { + assert((stack(i) == NULL) == (incoming_state->stack(i) == NULL), "oops"); + if (stack(i)) + stack(i)->addIncoming(incoming_state->stack(i), predecessor); } } -void SharkTrackingState::initialize(const SharkState *initial_state) -{ - _method = initial_state->_method; - memcpy(_locals, initial_state->_locals, sizeof(SharkValue*) * max_locals()); - memcpy(_stack, initial_state->_stack, sizeof(SharkValue*) * max_stack()); - _sp = _stack + initial_state->stack_depth(); -} - -int SharkTrackingState::stack_depth_in_slots() const +#if 0 +void SharkTrackingState::decache_for(CDReason reason, ciMethod *callee) { - int depth = 0; - for (SharkValue **v = _stack; v < _sp; v++) - depth += type2size[(*v)->basic_type()]; - return depth; -} - -void SharkTrackingState::decache(ciMethod *callee) -{ - // Create the OopMap + // Start recording the debug information OopMap *oopmap = new OopMap( oopmap_slot_munge(function()->oopmap_frame_size()), oopmap_slot_munge(function()->arg_size())); + int offset = function()->code_offset(); + debug_info()->add_safepoint(offset, oopmap); // Decache expression stack slots as necessary - int stack_slots = stack_depth_in_slots(); - for (int i = 0, j = 0; i < stack_slots; i++) { - SharkValue *value; - bool write; - bool record; - int dst; + GrowableArray *exparray = + new GrowableArray(stack_depth()); + + for (int i = stack_depth() - 1; i >= 0; i--) { + SharkValue *value = stack(i); + + Location::Type type = Location::normal; + if (value && value->is_jobject()) + type = Location::oop; + + int dst = i + max_stack() - stack_depth(); + int oiwfusp = function()->stack_slots_offset() + dst; + VMReg dst_as_vmreg = slot2reg(oiwfusp); + LocationValue* dst_as_lv = slot2lv(oiwfusp, type); - if (callee && i < callee->arg_size()) { - value = pop(); - write = true; - record = false; + bool write = false; + bool record = false; + + if (reason == TRAP) { + write = value != NULL; + record = true; } - else { - value = stack(j++); - write = record = value->is_jobject(); + else if (value) { + if (reason == JAVA_CALL && i < callee->arg_size()) { + write = true; + record = false; + } + else { + write = value->is_jobject(); + record = true; + } } if (write) { - dst = i + max_stack() - stack_slots; + if (value->is_two_word()) { + assert(i > 0, "should be"); + assert(stack(i - 1) == NULL, "should be"); + dst--; + } + builder()->CreateStore( value->generic_value(), builder()->CreateBitCast( builder()->CreateStructGEP(function()->stack_slots(), dst), - PointerType::getUnqual(SharkType::to_stackType(value->type())))); + PointerType::getUnqual(SharkType::to_stackType( + value->basic_type())))); + + if (record) + oopmap->set_oop(dst_as_vmreg); } if (record) - oopmap->set_oop(slot2reg(function()->stack_slots_offset() + dst)); + exparray->append(dst_as_lv); + } - if (value->is_two_word()) - i++; - } + // If we're decaching for a call then pop the arguments + int trim_slots = max_stack() - stack_depth(); + if (reason == JAVA_CALL) + pop(callee->arg_size()); // Record any monitors + GrowableArray *monarray = + new GrowableArray(function()->monitor_count()); + for (int i = 0; i < function()->monitor_count(); i++) { - oopmap->set_oop( - slot2reg( - function()->monitors_slots_offset() + - i * frame::interpreter_frame_monitor_size() + - (BasicObjectLock::obj_offset_in_bytes() >> LogBytesPerWord))); + int box_oiwfusp = + function()->monitors_slots_offset() + + i * frame::interpreter_frame_monitor_size(); + + int obj_oiwfusp = + box_oiwfusp + + (BasicObjectLock::obj_offset_in_bytes() >> LogBytesPerWord); + + oopmap->set_oop(slot2reg(obj_oiwfusp)); + + monarray->append(new MonitorValue( + slot2lv (obj_oiwfusp, Location::oop), + slot2loc(box_oiwfusp, Location::normal))); } + // Record the exception slot + oopmap->set_oop(slot2reg(function()->exception_slot_offset())); + // Decache the method pointer builder()->CreateStore(method(), function()->method_slot()); oopmap->set_oop(slot2reg(function()->method_slot_offset())); // Decache the PC - int offset = function()->code_offset(); builder()->CreateStore( builder()->CreateAdd( function()->base_pc(), LLVMValue::intptr_constant(offset)), function()->pc_slot()); // Decache local variables as necesary - for (int i = max_locals() - 1; i >= 0; i--) { + GrowableArray *locarray = + new GrowableArray(max_locals()); + + for (int i = 0; i < max_locals(); i++) { SharkValue *value = local(i); - if (value && value->is_jobject()) { - int dst = max_locals() - 1 - i; - - builder()->CreateStore( - value->generic_value(), - builder()->CreateBitCast( - builder()->CreateStructGEP(function()->locals_slots(), dst), - PointerType::getUnqual( - SharkType::to_stackType(value->type())))); + + Location::Type type = Location::invalid; + if (value) { + if (value->is_jobject()) + type = Location::oop; + else + type = Location::normal; + } + else if (i > 0) { + SharkValue *prev = local(i - 1); + if (prev && prev->is_two_word()) + type = Location::normal; + } + + int dst = max_locals() - 1 - i; + int oiwfusp = function()->locals_slots_offset() + dst; + VMReg dst_as_vmreg = slot2reg(oiwfusp); + LocationValue* dst_as_lv = slot2lv(oiwfusp, type); - oopmap->set_oop(slot2reg(function()->locals_slots_offset() + dst)); + if (value) { + if (value->is_two_word()) { + assert(i + 1 < max_locals(), "should be"); + assert(local(i + 1) == NULL, "should be"); + dst--; + } + + if (reason == TRAP || value->is_jobject()) { + builder()->CreateStore( + value->generic_value(), + builder()->CreateBitCast( + builder()->CreateStructGEP(function()->locals_slots(), dst), + PointerType::getUnqual( + SharkType::to_stackType(value->basic_type())))); + } + + if (value->is_jobject()) + oopmap->set_oop(dst_as_vmreg); } + locarray->append(dst_as_lv); } // Trim back the stack if necessary - if (stack_slots != max_stack()) { + if (trim_slots) { function()->CreateStoreZeroStackPointer( builder()->CreatePtrToInt( builder()->CreateStructGEP( - function()->stack_slots(), max_stack() - stack_slots), + function()->stack_slots(), trim_slots), SharkType::intptr_type())); } - // Install the OopMap - function()->add_gc_map(offset, oopmap); + // Record the scope and end the block of debug information + DebugToken *locvals = debug_info()->create_scope_values(locarray); + DebugToken *expvals = debug_info()->create_scope_values(exparray); + DebugToken *monvals = debug_info()->create_monitor_values(monarray); + debug_info()->describe_scope( + offset, block()->target(), block()->bci(), locvals, expvals, monvals); + debug_info()->end_safepoint(offset); } -void SharkTrackingState::cache(ciMethod *callee) +void SharkTrackingState::cache_after(CDReason reason, ciMethod *callee) { + assert(reason != TRAP, "shouldn't be"); + // If we're caching after a call then push a dummy result to set up the stack - int result_size = callee ? callee->return_type()->size() : 0; + int result_size = reason == JAVA_CALL ? callee->return_type()->size() : 0; if (result_size) { ciType *result_type; switch (callee->return_type()->basic_type()) { @@ -299,16 +393,23 @@ default: result_type = callee->return_type(); } + push(SharkValue::create_generic(result_type, NULL)); + if (result_size == 2) + push(NULL); } // Cache expression stack slots as necessary - int stack_slots = stack_depth_in_slots(); - for (int i = 0, j = 0; i < stack_slots; i++, j++) { - SharkValue *value = stack(j); + for (int i = 0; i < stack_depth(); i++) { + SharkValue *value = stack(i); + if (value == NULL) { + set_stack(i, NULL); + continue; + } + bool read; - if (result_size && i == 0) { + if (i < result_size) { read = true; } else { @@ -316,9 +417,15 @@ } if (read) { - int src = i + max_stack() - stack_slots; + int src = i + max_stack() - stack_depth(); + if (value->is_two_word()) { + assert(i > 0, "should be"); + assert(stack(i - 1) == NULL, "should be"); + src--; + } + set_stack( - j, + i, SharkValue::create_generic( value->type(), builder()->CreateLoad( @@ -327,9 +434,6 @@ PointerType::getUnqual( SharkType::to_stackType(value->basic_type())))))); } - - if (value->is_two_word()) - i++; } // Cache the method pointer @@ -353,13 +457,14 @@ } // Restore the stack pointer if necessary - if (stack_slots != max_stack()) { + if (stack_depth() != max_stack()) { function()->CreateStoreZeroStackPointer( builder()->CreatePtrToInt( builder()->CreateStructGEP(function()->stack_slots(), 0), SharkType::intptr_type())); } } +#endif // 0 void SharkTrackingState::merge(SharkState* other, BasicBlock* other_block, @@ -375,7 +480,7 @@ phi = builder()->CreatePHI(SharkType::methodOop_type(), "method"); phi->addIncoming(this_method, this_block); phi->addIncoming(other_method, other_block); - _method = phi; + set_method(phi); } // Local variables @@ -383,9 +488,9 @@ for (int i = 0; i < max_locals(); i++) { SharkValue *this_value = this->local(i); SharkValue *other_value = other->local(i); + assert((this_value == NULL) == (other_value == NULL), "should be"); if (this_value == other_value) continue; - assert(this_value != NULL && other_value != NULL, "shouldn't be"); ciType *this_type = this_value->type(); assert(this_type == other_value->type(), "should be"); @@ -394,7 +499,7 @@ phi = builder()->CreatePHI(SharkType::to_stackType(this_type), name); phi->addIncoming(this_value->generic_value(), this_block); phi->addIncoming(other_value->generic_value(), other_block); - _locals[i] = SharkValue::create_generic(this_type, phi); + set_local(i, SharkValue::create_generic(this_type, phi)); } // Expression stack @@ -402,7 +507,7 @@ for (int i = 0; i < stack_depth(); i++) { SharkValue *this_value = this->stack(i); SharkValue *other_value = other->stack(i); - assert(this_value != NULL && other_value != NULL, "shouldn't be"); + assert((this_value == NULL) == (other_value == NULL), "should be"); if (this_value == other_value) continue; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkState.hpp --- a/ports/hotspot/src/share/vm/shark/sharkState.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkState.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -26,16 +26,14 @@ class SharkBlock; class SharkState : public ResourceObj { - friend class SharkEntryState; - friend class SharkPHIState; - friend class SharkTrackingState; - protected: SharkState(SharkBlock* block) - : _block(block) { initialize(); } + : _block(block) { initialize(NULL); } + SharkState(const SharkState* state) + : _block(state->block()) { initialize(state); } private: - void initialize(); + void initialize(const SharkState* state); private: SharkBlock* _block; @@ -49,13 +47,13 @@ protected: inline SharkBuilder* builder() const; inline SharkFunction* function() const; - + public: inline int max_locals() const; inline int max_stack() const; // The values we are tracking - protected: + private: llvm::Value* _method; SharkValue** _locals; SharkValue** _stack; @@ -63,35 +61,72 @@ // Method public: + llvm::Value** method_addr() + { + return &_method; + } llvm::Value* method() const { return _method; } + void set_method(llvm::Value* method) + { + _method = method; + } // Local variables public: + SharkValue** local_addr(int index) const + { + assert(index >= 0 && index < max_locals(), "bad local variable index"); + return &_locals[index]; + } SharkValue* local(int index) const { - assert(index >= 0 && index < max_locals(), "bad local variable index"); - return _locals[index]; + return *local_addr(index); + } + void set_local(int index, SharkValue* value) + { + *local_addr(index) = value; } // Expression stack public: - SharkValue* stack(int slot) const + SharkValue** stack_addr(int slot) const { assert(slot >= 0 && slot < stack_depth(), "bad stack slot"); - return _sp[-(slot + 1)]; + return &_sp[-(slot + 1)]; } + SharkValue* stack(int slot) const + { + return *stack_addr(slot); + } + protected: void set_stack(int slot, SharkValue* value) { - assert(slot >= 0 && slot < stack_depth(), "bad stack slot"); - _sp[-(slot + 1)] = value; + *stack_addr(slot) = value; } + public: int stack_depth() const { return _sp - _stack; } + void push(SharkValue* value) + { + assert(stack_depth() < max_stack(), "stack overrun"); + *(_sp++) = value; + } + SharkValue* pop() + { + assert(stack_depth() > 0, "stack underrun"); + return *(--_sp); + } + void pop(int slots) + { + assert(stack_depth() >= slots, "stack underrun"); + _sp -= slots; + } + inline int stack_depth_at_entry() const; }; class SharkEntryState : public SharkState { @@ -111,72 +146,22 @@ private: void initialize(); -#ifdef ASSERT - private: - int _stack_depth_at_entry; -#endif // ASSERT - public: void add_incoming(SharkState* incoming_state); }; class SharkTrackingState : public SharkState { public: - SharkTrackingState(const SharkState* initial_state) - : SharkState(initial_state->block()) { initialize(initial_state); } - - private: - void initialize(const SharkState* initial_state); - - // Method - public: - void set_method(llvm::Value* method) - { - _method = method; - } - - // Local variables - public: - void set_local(int index, SharkValue* value) - { - assert(index >= 0 && index < max_locals(), "bad local variable index"); - _locals[index] = value; - } - - // Expression stack - public: - void push(SharkValue* value) - { - assert(stack_depth() < max_stack(), "stack overrun"); - *(_sp++) = value; - } - SharkValue* pop() - { - assert(stack_depth() > 0, "stack underrun"); - return *(--_sp); - } - void set_stack(int slot, SharkValue* value) - { - assert(slot >= 0 && slot < stack_depth(), "bad stack slot"); - _sp[-(slot + 1)] = value; - } - int stack_depth_in_slots() const; + SharkTrackingState(const SharkState* state) + : SharkState(state) { set_method(state->method()); } // Cache and decache public: - void cache(ciMethod *callee = NULL); - void decache(ciMethod *callee = NULL); - - // Decache helpers - private: - static int oopmap_slot_munge(int x) - { - return x << (LogBytesPerWord - LogBytesPerInt); - } - static VMReg slot2reg(int offset) - { - return VMRegImpl::stack2reg(oopmap_slot_munge(offset)); - } + inline void decache_for_Java_call(ciMethod* callee); + inline void cache_after_Java_call(ciMethod* callee); + inline void decache_for_VM_call(); + inline void cache_after_VM_call(); + inline void decache_for_trap(); // Copy and merge public: diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkState.inline.hpp --- a/ports/hotspot/src/share/vm/shark/sharkState.inline.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkState.inline.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -42,3 +42,52 @@ { return block()->max_stack(); } + +inline int SharkState::stack_depth_at_entry() const +{ + return block()->stack_depth_at_entry(); +} + +inline void SharkTrackingState::decache_for_Java_call(ciMethod* callee) +{ + SharkJavaCallDecacher(function(), block()->bci(), callee).scan(this); + pop(callee->arg_size()); +} + +inline void SharkTrackingState::cache_after_Java_call(ciMethod* callee) +{ + if (callee->return_type()->size()) { + ciType *type; + switch (callee->return_type()->basic_type()) { + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + type = ciType::make(T_INT); + break; + + default: + type = callee->return_type(); + } + + push(SharkValue::create_generic(type, NULL)); + if (type->is_two_word()) + push(NULL); + } + SharkJavaCallCacher(function(), block()->bci(), callee).scan(this); +} + +inline void SharkTrackingState::decache_for_VM_call() +{ + SharkVMCallDecacher(function(), block()->bci()).scan(this); +} + +inline void SharkTrackingState::cache_after_VM_call() +{ + SharkVMCallCacher(function(), block()->bci()).scan(this); +} + +inline void SharkTrackingState::decache_for_trap() +{ + SharkTrapDecacher(function(), block()->bci()).scan(this); +} diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkStateScanner.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkStateScanner.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -0,0 +1,101 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkStateScanner.cpp.incl" + +using namespace llvm; + +void SharkStateScanner::scan(SharkState* state) +{ + start_frame(); + + // Expression stack + stack_integrity_checks(state); + start_stack(state->stack_depth(), state->max_stack()); + for (int i = state->stack_depth() - 1; i >= 0; i--) { + process_stack_slot( + i, + state->stack_addr(i), + function()->stack_slots_offset() + + i + state->max_stack() - state->stack_depth()); + } + end_stack(); + + // Monitors + start_monitors(function()->monitor_count()); + for (int i = 0; i < function()->monitor_count(); i++) { + process_monitor( + i, + function()->monitors_slots_offset() + + i * frame::interpreter_frame_monitor_size()); + } + end_monitors(); + + // Frame header + start_frame_header(); + process_exception_slot(function()->exception_slot_offset()); + process_method_slot(state->method_addr(), function()->method_slot_offset()); + process_pc_slot(function()->pc_slot_offset()); + end_frame_header(); + + // Local variables + locals_integrity_checks(state); + start_locals(state->max_locals()); + for (int i = 0; i < state->max_locals(); i++) { + process_local_slot( + i, + state->local_addr(i), + function()->locals_slots_offset() + state->max_locals() - 1 - i); + } + end_locals(); + + end_frame(); +} + +#ifndef PRODUCT +void SharkStateScanner::stack_integrity_checks(SharkState* state) +{ + for (int i = 0; i < state->stack_depth(); i++) { + if (state->stack(i)) { + if (state->stack(i)->is_two_word()) + assert(state->stack(i - 1) == NULL, "should be"); + } + else { + assert(state->stack(i + 1)->is_two_word(), "should be"); + } + } +} + +void SharkStateScanner::locals_integrity_checks(SharkState* state) +{ + for (int i = 0; i < state->max_locals(); i++) { + if (state->local(i)) { + if (state->local(i)->is_two_word()) + assert(state->local(i + 1) == NULL, "should be"); + } + } +} +#endif // !PRODUCT diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkStateScanner.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkStateScanner.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -0,0 +1,76 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +class SharkState; + +class SharkStateScanner : public StackObj { + protected: + SharkStateScanner(SharkFunction* function) + : _function(function) {} + + private: + SharkFunction* _function; + + protected: + SharkFunction* function() const + { + return _function; + } + + // Scan the frame + public: + void scan(SharkState* state); + + // Callbacks + // Note that the offsets supplied to the various process_* callbacks + // are specified in wordSize words from the frame's unextended_sp. + protected: + virtual void start_frame() {} + + virtual void start_stack(int num_slots, int max_slots) {} + virtual void process_stack_slot(int index, SharkValue** value, int offset) {} + virtual void end_stack() {} + + virtual void start_monitors(int num_monitors) {} + virtual void process_monitor(int index, int offset) {} + virtual void end_monitors() {} + + virtual void start_frame_header() {} + virtual void process_exception_slot(int offset) {} + virtual void process_method_slot(llvm::Value** value, int offset) {} + virtual void process_pc_slot(int offset) {} + virtual void end_frame_header() {} + + virtual void start_locals(int num_locals) {} + virtual void process_local_slot(int index, SharkValue** value, int offset) {} + virtual void end_locals() {} + + virtual void end_frame() {} + + // Integrity checks + private: + static void stack_integrity_checks(SharkState* state) PRODUCT_RETURN; + static void locals_integrity_checks(SharkState* state) PRODUCT_RETURN; +}; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkType.cpp --- a/ports/hotspot/src/share/vm/shark/sharkType.cpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkType.cpp Tue Sep 30 08:42:10 2008 -0400 @@ -123,6 +123,10 @@ _to_stackType_tab[i] = jobject_type(); _to_arrayType_tab[i] = jobject_type(); break; + + case T_ADDRESS: + _to_stackType_tab[i] = intptr_type(); + break; } } } diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkValue.hpp --- a/ports/hotspot/src/share/vm/shark/sharkValue.hpp Mon Sep 29 12:04:41 2008 -0400 +++ b/ports/hotspot/src/share/vm/shark/sharkValue.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -51,7 +51,7 @@ } public: - static llvm::ConstantInt* intptr_constant(jint value) + static llvm::ConstantInt* intptr_constant(intptr_t value) { return llvm::ConstantInt::get(SharkType::intptr_type(), value, false); } @@ -59,96 +59,113 @@ class SharkValue : public ResourceObj { protected: - SharkValue(ciType* type, llvm::Value* value) - : _type(type), _llvm_value(value), _zero_checked(false) {} + SharkValue() {} - private: - ciType* _type; - llvm::Value* _llvm_value; - bool _zero_checked; - + // Type access public: - ciType* type() const + virtual ciType* type() const { - return _type; - } - private: - llvm::Value* llvm_value() const - { - return _llvm_value; + ShouldNotCallThis(); } - public: - BasicType basic_type() const + virtual BasicType basic_type() const { - return type()->basic_type(); + ShouldNotCallThis(); + } + virtual int size() const + { + ShouldNotCallThis(); } bool is_one_word() const { - return type()->size() == 1; + return size() == 1; } bool is_two_word() const { - return type()->size() == 2; + return size() == 2; } - public: - bool is_jint() const + virtual bool is_jint() const { - return llvm_value()->getType() == SharkType::jint_type(); + return false; } - bool is_jlong() const + virtual bool is_jlong() const { - return llvm_value()->getType() == SharkType::jlong_type(); + return false; } - bool is_jfloat() const + virtual bool is_jfloat() const + { + return false; + } + virtual bool is_jdouble() const { - return llvm_value()->getType() == SharkType::jfloat_type(); + return false; } - bool is_jdouble() const + virtual bool is_jobject() const { - return llvm_value()->getType() == SharkType::jdouble_type(); + return false; } - bool is_jobject() const + virtual bool is_jarray() const { - return llvm_value()->getType() == SharkType::jobject_type(); + return false; } - bool is_jarray() const + virtual bool is_returnAddress() const { - return basic_type() == T_ARRAY; + return false; } // Typed conversions to LLVM values public: - llvm::Value* jint_value() const + virtual llvm::Value* jint_value() const { - assert(is_jint(), "should be"); - return llvm_value(); + ShouldNotCallThis(); } - llvm::Value* jlong_value() const + virtual llvm::Value* jlong_value() const + { + ShouldNotCallThis(); + } + virtual llvm::Value* jfloat_value() const { - assert(is_jlong(), "should be"); - return llvm_value(); + ShouldNotCallThis(); + } + virtual llvm::Value* jdouble_value() const + { + ShouldNotCallThis(); } - llvm::Value* jfloat_value() const + virtual llvm::Value* jobject_value() const { - assert(is_jfloat(), "should be"); - return llvm_value(); + ShouldNotCallThis(); + } + virtual llvm::Value* jarray_value() const + { + ShouldNotCallThis(); } - llvm::Value* jdouble_value() const + virtual int returnAddress_value() const { - assert(is_jdouble(), "should be"); - return llvm_value(); + ShouldNotCallThis(); } - llvm::Value* jobject_value() const + + // Constants of various types + public: + static SharkValue* jint_constant(jint value) + { + return create_jint(LLVMValue::jint_constant(value)); + } + static SharkValue* jlong_constant(jlong value) { - assert(is_jobject(), "should be"); - return llvm_value(); + return create_jlong(LLVMValue::jlong_constant(value)); + } + static SharkValue* jfloat_constant(jfloat value) + { + return create_jfloat(LLVMValue::jfloat_constant(value)); } - llvm::Value* jarray_value() const + static SharkValue* jdouble_constant(jdouble value) { - assert(is_jarray(), "should be"); - return llvm_value(); + return create_jdouble(LLVMValue::jdouble_constant(value)); + } + static SharkValue* null() + { + return create_jobject(LLVMValue::null()); } // Typed conversion from LLVM values @@ -218,43 +235,154 @@ ShouldNotReachHere(); } - // Type-losing conversions, to be avoided where possible + // Typed "conversion" from return address + public: + static inline SharkValue* create_returnAddress(int bci); + + // Type-losing conversions, use with care + public: + static inline SharkValue* create_generic(ciType* type, llvm::Value* value); + virtual llvm::Value* generic_value() const + { + ShouldNotCallThis(); + } + virtual llvm::Value* intptr_value(llvm::IRBuilder* builder) const + { + ShouldNotCallThis(); + } + + // Phi-style stuff + public: + virtual void addIncoming(SharkValue *value, llvm::BasicBlock* block) + { + ShouldNotCallThis(); + } + + // Repeated null and divide-by-zero check removal + public: + virtual bool zero_checked() const + { + ShouldNotCallThis(); + } + virtual void set_zero_checked(bool zero_checked) + { + ShouldNotCallThis(); + } +}; + +class SharkComputableValue : public SharkValue { + friend class SharkValue; + + protected: + SharkComputableValue(ciType* type, llvm::Value* value) + : _type(type), _llvm_value(value), _zero_checked(false) {} + + private: + ciType* _type; + llvm::Value* _llvm_value; + bool _zero_checked; + + private: + llvm::Value* llvm_value() const + { + return _llvm_value; + } + + // Type access public: - static SharkValue* create_generic(ciType* type, llvm::Value* value) + ciType* type() const + { + return _type; + } + + public: + BasicType basic_type() const + { + return type()->basic_type(); + } + int size() const + { + return type()->size(); + } + + public: + bool is_jint() const + { + return llvm_value()->getType() == SharkType::jint_type(); + } + bool is_jlong() const + { + return llvm_value()->getType() == SharkType::jlong_type(); + } + bool is_jfloat() const + { + return llvm_value()->getType() == SharkType::jfloat_type(); + } + bool is_jdouble() const + { + return llvm_value()->getType() == SharkType::jdouble_type(); + } + bool is_jobject() const + { + return llvm_value()->getType() == SharkType::jobject_type(); + } + bool is_jarray() const { - return new SharkValue(type, value); + return basic_type() == T_ARRAY; + } + + // Typed conversions to LLVM values + public: + llvm::Value* jint_value() const + { + assert(is_jint(), "should be"); + return llvm_value(); + } + llvm::Value* jlong_value() const + { + assert(is_jlong(), "should be"); + return llvm_value(); } + llvm::Value* jfloat_value() const + { + assert(is_jfloat(), "should be"); + return llvm_value(); + } + llvm::Value* jdouble_value() const + { + assert(is_jdouble(), "should be"); + return llvm_value(); + } + llvm::Value* jobject_value() const + { + assert(is_jobject(), "should be"); + return llvm_value(); + } + llvm::Value* jarray_value() const + { + assert(is_jarray(), "should be"); + return llvm_value(); + } + + // Type-losing conversions, use with care + public: llvm::Value* generic_value() const { return llvm_value(); } - llvm::Value* intptr_value(llvm::IRBuilder<>* builder) const + llvm::Value* intptr_value(llvm::IRBuilder* builder) const { assert(is_jobject(), "should be"); return builder->CreatePtrToInt(llvm_value(), SharkType::intptr_type()); } - // Constants of various types + // Wrapped PHINodes public: - static SharkValue* jint_constant(jint value) - { - return create_jint(LLVMValue::jint_constant(value)); - } - static SharkValue* jlong_constant(jlong value) + void addIncoming(SharkValue *value, llvm::BasicBlock* block) { - return create_jlong(LLVMValue::jlong_constant(value)); - } - static SharkValue* jfloat_constant(jfloat value) - { - return create_jfloat(LLVMValue::jfloat_constant(value)); - } - static SharkValue* jdouble_constant(jdouble value) - { - return create_jdouble(LLVMValue::jdouble_constant(value)); - } - static SharkValue* null() - { - return create_generic(ciType::make(T_OBJECT), LLVMValue::null()); + assert(llvm::isa(generic_value()), "should be"); + ((llvm::PHINode *) generic_value())->addIncoming( + value->generic_value(), block); } // Repeated null and divide-by-zero check removal @@ -268,3 +396,52 @@ _zero_checked = zero_checked; } }; + +class SharkReturnAddressValue : public SharkValue { + friend class SharkValue; + + protected: + SharkReturnAddressValue(int bci) + : _bci(bci) {} + + private: + int _bci; + + // Type access + public: + BasicType basic_type() const + { + return T_ADDRESS; + } + int size() const + { + return 1; + } + + public: + bool is_returnAddress() const + { + return true; + } + + // Typed "conversion" + public: + int returnAddress_value() const + { + return _bci; + } + + // Type-losing "conversion", use with care + public: + llvm::Value* generic_value() const + { + return LLVMValue::intptr_constant(_bci); + } + + // Phi-style stuff + public: + void addIncoming(SharkValue *value, llvm::BasicBlock* block) + { + assert(_bci == value->returnAddress_value(), "should be"); + } +}; diff -r 9ff3417e28cc -r 28523a4d7bd6 ports/hotspot/src/share/vm/shark/sharkValue.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkValue.inline.hpp Tue Sep 30 08:42:10 2008 -0400 @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +inline SharkValue* SharkValue::create_generic(ciType* type, llvm::Value* value) +{ + return new SharkComputableValue(type, value); +} + +inline SharkValue* SharkValue::create_returnAddress(int bci) +{ + return new SharkReturnAddressValue(bci); +}