twisti@2047: /* stefank@2314: * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. twisti@2047: * Copyright 2008, 2009, 2010 Red Hat, Inc. twisti@2047: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. twisti@2047: * twisti@2047: * This code is free software; you can redistribute it and/or modify it twisti@2047: * under the terms of the GNU General Public License version 2 only, as twisti@2047: * published by the Free Software Foundation. twisti@2047: * twisti@2047: * This code is distributed in the hope that it will be useful, but WITHOUT twisti@2047: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or twisti@2047: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License twisti@2047: * version 2 for more details (a copy is included in the LICENSE file that twisti@2047: * accompanied this code). twisti@2047: * twisti@2047: * You should have received a copy of the GNU General Public License version twisti@2047: * 2 along with this work; if not, write to the Free Software Foundation, twisti@2047: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. twisti@2047: * twisti@2047: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA twisti@2047: * or visit www.oracle.com if you need additional information or have any twisti@2047: * questions. twisti@2047: * twisti@2047: */ twisti@2047: stefank@2314: #ifndef SHARE_VM_SHARK_SHARKTOPLEVELBLOCK_HPP stefank@2314: #define SHARE_VM_SHARK_SHARKTOPLEVELBLOCK_HPP stefank@2314: stefank@2314: #include "ci/ciStreams.hpp" stefank@2314: #include "ci/ciType.hpp" stefank@2314: #include "ci/ciTypeFlow.hpp" stefank@2314: #include "interpreter/bytecodes.hpp" stefank@2314: #include "memory/allocation.hpp" stefank@2314: #include "shark/llvmHeaders.hpp" stefank@2314: #include "shark/sharkBlock.hpp" stefank@2314: #include "shark/sharkBuilder.hpp" stefank@2314: #include "shark/sharkFunction.hpp" stefank@2314: #include "shark/sharkState.hpp" stefank@2314: #include "shark/sharkValue.hpp" stefank@2314: twisti@2047: class SharkTopLevelBlock : public SharkBlock { twisti@2047: public: twisti@2047: SharkTopLevelBlock(SharkFunction* function, ciTypeFlow::Block* ciblock) twisti@2047: : SharkBlock(function), twisti@2047: _function(function), twisti@2047: _ciblock(ciblock), twisti@2047: _entered(false), twisti@2047: _has_trap(false), twisti@2047: _needs_phis(false), twisti@2047: _entry_state(NULL), twisti@2047: _entry_block(NULL) {} twisti@2047: twisti@2047: private: twisti@2047: SharkFunction* _function; twisti@2047: ciTypeFlow::Block* _ciblock; twisti@2047: twisti@2047: public: twisti@2047: SharkFunction* function() const { twisti@2047: return _function; twisti@2047: } twisti@2047: ciTypeFlow::Block* ciblock() const { twisti@2047: return _ciblock; twisti@2047: } twisti@2047: twisti@2047: // Function properties twisti@2047: public: twisti@2047: SharkStack* stack() const { twisti@2047: return function()->stack(); twisti@2047: } twisti@2047: twisti@2047: // Typeflow properties twisti@2047: public: twisti@2047: int index() const { twisti@2047: return ciblock()->pre_order(); twisti@2047: } twisti@2047: bool is_backedge_copy() const { twisti@2047: return ciblock()->is_backedge_copy(); twisti@2047: } twisti@2047: int stack_depth_at_entry() const { twisti@2047: return ciblock()->stack_size(); twisti@2047: } twisti@2047: ciType* local_type_at_entry(int index) const { twisti@2047: return ciblock()->local_type_at(index); twisti@2047: } twisti@2047: ciType* stack_type_at_entry(int slot) const { twisti@2047: return ciblock()->stack_type_at(slot); twisti@2047: } twisti@2047: int start() const { twisti@2047: return ciblock()->start(); twisti@2047: } twisti@2047: int limit() const { twisti@2047: return ciblock()->limit(); twisti@2047: } twisti@2047: bool falls_through() const { twisti@2047: return ciblock()->control() == ciBlock::fall_through_bci; twisti@2047: } twisti@2047: int num_successors() const { twisti@2047: return ciblock()->successors()->length(); twisti@2047: } twisti@2047: SharkTopLevelBlock* successor(int index) const { twisti@2047: return function()->block(ciblock()->successors()->at(index)->pre_order()); twisti@2047: } twisti@2047: SharkTopLevelBlock* bci_successor(int bci) const; twisti@2047: twisti@2047: // Exceptions twisti@2047: private: twisti@2047: GrowableArray* _exc_handlers; twisti@2047: GrowableArray* _exceptions; twisti@2047: twisti@2047: private: twisti@2047: void compute_exceptions(); twisti@2047: twisti@2047: private: twisti@2047: int num_exceptions() const { twisti@2047: return _exc_handlers->length(); twisti@2047: } twisti@2047: ciExceptionHandler* exc_handler(int index) const { twisti@2047: return _exc_handlers->at(index); twisti@2047: } twisti@2047: SharkTopLevelBlock* exception(int index) const { twisti@2047: return _exceptions->at(index); twisti@2047: } twisti@2047: twisti@2047: // Traps twisti@2047: private: twisti@2047: bool _has_trap; twisti@2047: int _trap_request; twisti@2047: int _trap_bci; twisti@2047: twisti@2047: void set_trap(int trap_request, int trap_bci) { twisti@2047: assert(!has_trap(), "shouldn't have"); twisti@2047: _has_trap = true; twisti@2047: _trap_request = trap_request; twisti@2047: _trap_bci = trap_bci; twisti@2047: } twisti@2047: twisti@2047: private: twisti@2047: bool has_trap() { twisti@2047: return _has_trap; twisti@2047: } twisti@2047: int trap_request() { twisti@2047: assert(has_trap(), "should have"); twisti@2047: return _trap_request; twisti@2047: } twisti@2047: int trap_bci() { twisti@2047: assert(has_trap(), "should have"); twisti@2047: return _trap_bci; twisti@2047: } twisti@2047: twisti@2047: private: twisti@2047: void scan_for_traps(); twisti@2047: twisti@2047: private: twisti@2047: bool static_field_ok_in_clinit(ciField* field); twisti@2047: twisti@2047: // Entry state twisti@2047: private: twisti@2047: bool _entered; twisti@2047: bool _needs_phis; twisti@2047: twisti@2047: public: twisti@2047: bool entered() const { twisti@2047: return _entered; twisti@2047: } twisti@2047: bool needs_phis() const { twisti@2047: return _needs_phis; twisti@2047: } twisti@2047: twisti@2047: private: twisti@2047: void enter(SharkTopLevelBlock* predecessor, bool is_exception); twisti@2047: twisti@2047: public: twisti@2047: void enter() { twisti@2047: enter(NULL, false); twisti@2047: } twisti@2047: twisti@2047: private: twisti@2047: SharkState* _entry_state; twisti@2047: twisti@2047: private: twisti@2047: SharkState* entry_state(); twisti@2047: twisti@2047: private: twisti@2047: llvm::BasicBlock* _entry_block; twisti@2047: twisti@2047: public: twisti@2047: llvm::BasicBlock* entry_block() const { twisti@2047: return _entry_block; twisti@2047: } twisti@2047: twisti@2047: public: twisti@2047: void initialize(); twisti@2047: twisti@2047: public: twisti@2047: void add_incoming(SharkState* incoming_state); twisti@2047: twisti@2047: // Method twisti@2047: public: twisti@2047: llvm::Value* method() { twisti@2047: return current_state()->method(); twisti@2047: } twisti@2047: twisti@2047: // Temporary oop storage twisti@2047: public: twisti@2047: void set_oop_tmp(llvm::Value* value) { twisti@2047: assert(value, "value must be non-NULL (will be reset by get_oop_tmp)"); twisti@2047: assert(!current_state()->oop_tmp(), "oop_tmp gets and sets must match"); twisti@2047: current_state()->set_oop_tmp(value); twisti@2047: } twisti@2047: llvm::Value* get_oop_tmp() { twisti@2047: llvm::Value* value = current_state()->oop_tmp(); twisti@2047: assert(value, "oop_tmp gets and sets must match"); twisti@2047: current_state()->set_oop_tmp(NULL); twisti@2047: return value; twisti@2047: } twisti@2047: twisti@2047: // Cache and decache twisti@2047: private: twisti@2047: void decache_for_Java_call(ciMethod* callee); twisti@2047: void cache_after_Java_call(ciMethod* callee); twisti@2047: void decache_for_VM_call(); twisti@2047: void cache_after_VM_call(); twisti@2047: void decache_for_trap(); twisti@2047: twisti@2047: // Monitors twisti@2047: private: twisti@2047: int num_monitors() { twisti@2047: return current_state()->num_monitors(); twisti@2047: } twisti@2047: int set_num_monitors(int num_monitors) { twisti@2047: current_state()->set_num_monitors(num_monitors); twisti@2047: } twisti@2047: twisti@2047: // Code generation twisti@2047: public: twisti@2047: void emit_IR(); twisti@2047: twisti@2047: // Branch helpers twisti@2047: private: twisti@2047: void do_branch(int successor_index); twisti@2047: twisti@2047: // Zero checks twisti@2047: private: twisti@2047: void do_zero_check(SharkValue* value); twisti@2047: void zero_check_value(SharkValue* value, llvm::BasicBlock* continue_block); twisti@2047: twisti@2047: public: twisti@2047: void do_deferred_zero_check(SharkValue* value, twisti@2047: int bci, twisti@2047: SharkState* saved_state, twisti@2047: llvm::BasicBlock* continue_block); twisti@2047: // Exceptions twisti@2047: private: twisti@2047: llvm::Value* pending_exception_address() const { twisti@2047: return builder()->CreateAddressOfStructEntry( twisti@2047: thread(), Thread::pending_exception_offset(), twisti@2047: llvm::PointerType::getUnqual(SharkType::oop_type()), twisti@2047: "pending_exception_addr"); twisti@2047: } twisti@2047: llvm::LoadInst* get_pending_exception() const { twisti@2047: return builder()->CreateLoad( twisti@2047: pending_exception_address(), "pending_exception"); twisti@2047: } twisti@2047: void clear_pending_exception() const { twisti@2047: builder()->CreateStore(LLVMValue::null(), pending_exception_address()); twisti@2047: } twisti@2047: public: twisti@2047: enum ExceptionActionMask { twisti@2047: // The actual bitmasks that things test against twisti@2047: EAM_CHECK = 1, // whether to check for pending exceptions twisti@2047: EAM_HANDLE = 2, // whether to attempt to handle pending exceptions twisti@2047: EAM_MONITOR_FUDGE = 4, // whether the monitor count needs adjusting twisti@2047: twisti@2047: // More convenient values for passing twisti@2047: EX_CHECK_NONE = 0, twisti@2047: EX_CHECK_NO_CATCH = EAM_CHECK, twisti@2047: EX_CHECK_FULL = EAM_CHECK | EAM_HANDLE twisti@2047: }; twisti@2047: void check_pending_exception(int action); twisti@2047: void handle_exception(llvm::Value* exception, int action); twisti@2047: void marshal_exception_fast(int num_options); twisti@2047: void marshal_exception_slow(int num_options); twisti@2047: llvm::BasicBlock* handler_for_exception(int index); twisti@2047: twisti@2047: // VM calls twisti@2047: private: twisti@2047: llvm::CallInst* call_vm(llvm::Value* callee, twisti@2047: llvm::Value** args_start, twisti@2047: llvm::Value** args_end, twisti@2047: int exception_action) { twisti@2047: decache_for_VM_call(); twisti@2047: stack()->CreateSetLastJavaFrame(); twisti@4314: llvm::CallInst *res = builder()->CreateCall(callee, llvm::makeArrayRef(args_start, args_end)); twisti@2047: stack()->CreateResetLastJavaFrame(); twisti@2047: cache_after_VM_call(); twisti@2047: if (exception_action & EAM_CHECK) { twisti@2047: check_pending_exception(exception_action); twisti@2047: current_state()->set_has_safepointed(true); twisti@2047: } twisti@2047: return res; twisti@2047: } twisti@2047: twisti@2047: public: twisti@2047: llvm::CallInst* call_vm(llvm::Value* callee, twisti@2047: int exception_action) { twisti@2047: llvm::Value *args[] = {thread()}; twisti@2047: return call_vm(callee, args, args + 1, exception_action); twisti@2047: } twisti@2047: llvm::CallInst* call_vm(llvm::Value* callee, twisti@2047: llvm::Value* arg1, twisti@2047: int exception_action) { twisti@2047: llvm::Value *args[] = {thread(), arg1}; twisti@2047: return call_vm(callee, args, args + 2, exception_action); twisti@2047: } twisti@2047: llvm::CallInst* call_vm(llvm::Value* callee, twisti@2047: llvm::Value* arg1, twisti@2047: llvm::Value* arg2, twisti@2047: int exception_action) { twisti@2047: llvm::Value *args[] = {thread(), arg1, arg2}; twisti@2047: return call_vm(callee, args, args + 3, exception_action); twisti@2047: } twisti@2047: llvm::CallInst* call_vm(llvm::Value* callee, twisti@2047: llvm::Value* arg1, twisti@2047: llvm::Value* arg2, twisti@2047: llvm::Value* arg3, twisti@2047: int exception_action) { twisti@2047: llvm::Value *args[] = {thread(), arg1, arg2, arg3}; twisti@2047: return call_vm(callee, args, args + 4, exception_action); twisti@2047: } twisti@2047: twisti@2047: // VM call oop return handling twisti@2047: private: twisti@2047: llvm::LoadInst* get_vm_result() const { twisti@2047: llvm::Value *addr = builder()->CreateAddressOfStructEntry( twisti@2047: thread(), JavaThread::vm_result_offset(), twisti@2047: llvm::PointerType::getUnqual(SharkType::oop_type()), twisti@2047: "vm_result_addr"); twisti@2047: llvm::LoadInst *result = builder()->CreateLoad(addr, "vm_result"); twisti@2047: builder()->CreateStore(LLVMValue::null(), addr); twisti@2047: return result; twisti@2047: } twisti@2047: twisti@2047: // Synchronization twisti@2047: private: twisti@2047: void acquire_lock(llvm::Value* lockee, int exception_action); twisti@2047: void release_lock(int exception_action); twisti@2047: twisti@2047: public: twisti@2047: void acquire_method_lock(); twisti@2047: twisti@2047: // Bounds checks twisti@2047: private: twisti@2047: void check_bounds(SharkValue* array, SharkValue* index); twisti@2047: twisti@2047: // Safepoints twisti@2047: private: twisti@2047: void maybe_add_safepoint(); twisti@2047: void maybe_add_backedge_safepoint(); twisti@2047: twisti@2047: // Loop safepoint removal twisti@2047: private: twisti@2047: bool _can_reach_visited; twisti@2047: twisti@2047: bool can_reach(SharkTopLevelBlock* other); twisti@2047: bool can_reach_helper(SharkTopLevelBlock* other); twisti@2047: twisti@2047: // Traps twisti@2047: private: twisti@2047: llvm::BasicBlock* make_trap(int trap_bci, int trap_request); twisti@2047: void do_trap(int trap_request); twisti@2047: twisti@2047: // Returns twisti@2047: private: twisti@2047: void call_register_finalizer(llvm::Value* receiver); twisti@2047: void handle_return(BasicType type, llvm::Value* exception); twisti@2047: twisti@2047: // arraylength twisti@2047: private: twisti@2047: void do_arraylength(); twisti@2047: twisti@2047: // *aload and *astore twisti@2047: private: twisti@2047: void do_aload(BasicType basic_type); twisti@2047: void do_astore(BasicType basic_type); twisti@2047: twisti@2047: // *return and athrow twisti@2047: private: twisti@2047: void do_return(BasicType type); twisti@2047: void do_athrow(); twisti@2047: twisti@2047: // goto* twisti@2047: private: twisti@2047: void do_goto(); twisti@2047: twisti@2047: // jsr* and ret twisti@2047: private: twisti@2047: void do_jsr(); twisti@2047: void do_ret(); twisti@2047: twisti@2047: // if* twisti@2047: private: twisti@2047: void do_if_helper(llvm::ICmpInst::Predicate p, twisti@2047: llvm::Value* b, twisti@2047: llvm::Value* a, twisti@2047: SharkState* if_taken_state, twisti@2047: SharkState* not_taken_state); twisti@2047: void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a); twisti@2047: twisti@2047: // tableswitch and lookupswitch twisti@2047: private: twisti@2047: void do_switch(); twisti@2047: twisti@2047: // invoke* twisti@2047: private: twisti@2047: ciMethod* improve_virtual_call(ciMethod* caller, twisti@2047: ciInstanceKlass* klass, twisti@2047: ciMethod* dest_method, twisti@2047: ciType* receiver_type); twisti@2047: llvm::Value* get_direct_callee(ciMethod* method); twisti@2047: llvm::Value* get_virtual_callee(SharkValue* receiver, int vtable_index); twisti@2047: llvm::Value* get_interface_callee(SharkValue* receiver, ciMethod* method); twisti@2047: twisti@2047: void do_call(); twisti@2047: twisti@2047: // checkcast and instanceof twisti@2047: private: twisti@2047: bool static_subtype_check(ciKlass* check_klass, ciKlass* object_klass); twisti@2047: void do_full_instance_check(ciKlass* klass); twisti@2047: void do_trapping_instance_check(ciKlass* klass); twisti@2047: twisti@2047: void do_instance_check(); twisti@2047: bool maybe_do_instanceof_if(); twisti@2047: twisti@2047: // new and *newarray twisti@2047: private: twisti@2047: void do_new(); twisti@2047: void do_newarray(); twisti@2047: void do_anewarray(); twisti@2047: void do_multianewarray(); twisti@2047: twisti@2047: // monitorenter and monitorexit twisti@2047: private: twisti@2047: void do_monitorenter(); twisti@2047: void do_monitorexit(); twisti@2047: }; stefank@2314: stefank@2314: #endif // SHARE_VM_SHARK_SHARKTOPLEVELBLOCK_HPP