/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2008, 2009, 2010 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_SHARK_SHARKTOPLEVELBLOCK_HPP
#define SHARE_VM_SHARK_SHARKTOPLEVELBLOCK_HPP
#include "ci/ciStreams.hpp"
#include "ci/ciType.hpp"
#include "ci/ciTypeFlow.hpp"
#include "interpreter/bytecodes.hpp"
#include "memory/allocation.hpp"
#include "shark/llvmHeaders.hpp"
#include "shark/sharkBlock.hpp"
#include "shark/sharkBuilder.hpp"
#include "shark/sharkFunction.hpp"
#include "shark/sharkState.hpp"
#include "shark/sharkValue.hpp"
class SharkTopLevelBlock : public SharkBlock {
public:
SharkTopLevelBlock(SharkFunction* function, ciTypeFlow::Block* ciblock)
: SharkBlock(function),
_function(function),
_ciblock(ciblock),
_entered(false),
_has_trap(false),
_needs_phis(false),
_entry_state(NULL),
_entry_block(NULL) {}
private:
SharkFunction* _function;
ciTypeFlow::Block* _ciblock;
public:
SharkFunction* function() const {
return _function;
}
ciTypeFlow::Block* ciblock() const {
return _ciblock;
}
// Function properties
public:
SharkStack* stack() const {
return function()->stack();
}
// Typeflow properties
public:
int index() const {
return ciblock()->pre_order();
}
bool is_backedge_copy() const {
return ciblock()->is_backedge_copy();
}
int stack_depth_at_entry() const {
return ciblock()->stack_size();
}
ciType* local_type_at_entry(int index) const {
return ciblock()->local_type_at(index);
}
ciType* stack_type_at_entry(int slot) const {
return ciblock()->stack_type_at(slot);
}
int start() const {
return ciblock()->start();
}
int limit() const {
return ciblock()->limit();
}
bool falls_through() const {
return ciblock()->control() == ciBlock::fall_through_bci;
}
int num_successors() const {
return ciblock()->successors()->length();
}
SharkTopLevelBlock* successor(int index) const {
return function()->block(ciblock()->successors()->at(index)->pre_order());
}
SharkTopLevelBlock* bci_successor(int bci) const;
// Exceptions
private:
GrowableArray<ciExceptionHandler*>* _exc_handlers;
GrowableArray<SharkTopLevelBlock*>* _exceptions;
private:
void compute_exceptions();
private:
int num_exceptions() const {
return _exc_handlers->length();
}
ciExceptionHandler* exc_handler(int index) const {
return _exc_handlers->at(index);
}
SharkTopLevelBlock* exception(int index) const {
return _exceptions->at(index);
}
// Traps
private:
bool _has_trap;
int _trap_request;
int _trap_bci;
void set_trap(int trap_request, int trap_bci) {
assert(!has_trap(), "shouldn't have");
_has_trap = true;
_trap_request = trap_request;
_trap_bci = trap_bci;
}
private:
bool has_trap() {
return _has_trap;
}
int trap_request() {
assert(has_trap(), "should have");
return _trap_request;
}
int trap_bci() {
assert(has_trap(), "should have");
return _trap_bci;
}
private:
void scan_for_traps();
private:
bool static_field_ok_in_clinit(ciField* field);
// Entry state
private:
bool _entered;
bool _needs_phis;
public:
bool entered() const {
return _entered;
}
bool needs_phis() const {
return _needs_phis;
}
private:
void enter(SharkTopLevelBlock* predecessor, bool is_exception);
public:
void enter() {
enter(NULL, false);
}
private:
SharkState* _entry_state;
private:
SharkState* 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);
// Method
public:
llvm::Value* method() {
return current_state()->method();
}
// Temporary oop storage
public:
void set_oop_tmp(llvm::Value* value) {
assert(value, "value must be non-NULL (will be reset by get_oop_tmp)");
assert(!current_state()->oop_tmp(), "oop_tmp gets and sets must match");
current_state()->set_oop_tmp(value);
}
llvm::Value* get_oop_tmp() {
llvm::Value* value = current_state()->oop_tmp();
assert(value, "oop_tmp gets and sets must match");
current_state()->set_oop_tmp(NULL);
return value;
}
// Cache and decache
private:
void decache_for_Java_call(ciMethod* callee);
void cache_after_Java_call(ciMethod* callee);
void decache_for_VM_call();
void cache_after_VM_call();
void decache_for_trap();
// Monitors
private:
int num_monitors() {
return current_state()->num_monitors();
}
int set_num_monitors(int num_monitors) {
current_state()->set_num_monitors(num_monitors);
}
// Code generation
public:
void emit_IR();
// Branch helpers
private:
void do_branch(int successor_index);
// Zero checks
private:
void do_zero_check(SharkValue* value);
void zero_check_value(SharkValue* value, llvm::BasicBlock* continue_block);
public:
void do_deferred_zero_check(SharkValue* value,
int bci,
SharkState* saved_state,
llvm::BasicBlock* continue_block);
// Exceptions
private:
llvm::Value* pending_exception_address() const {
return builder()->CreateAddressOfStructEntry(
thread(), Thread::pending_exception_offset(),
llvm::PointerType::getUnqual(SharkType::oop_type()),
"pending_exception_addr");
}
llvm::LoadInst* get_pending_exception() const {
return builder()->CreateLoad(
pending_exception_address(), "pending_exception");
}
void clear_pending_exception() const {
builder()->CreateStore(LLVMValue::null(), pending_exception_address());
}
public:
enum ExceptionActionMask {
// The actual bitmasks that things test against
EAM_CHECK = 1, // whether to check for pending exceptions
EAM_HANDLE = 2, // whether to attempt to handle pending exceptions
EAM_MONITOR_FUDGE = 4, // whether the monitor count needs adjusting
// More convenient values for passing
EX_CHECK_NONE = 0,
EX_CHECK_NO_CATCH = EAM_CHECK,
EX_CHECK_FULL = EAM_CHECK | EAM_HANDLE
};
void check_pending_exception(int action);
void handle_exception(llvm::Value* exception, int action);
void marshal_exception_fast(int num_options);
void marshal_exception_slow(int num_options);
llvm::BasicBlock* handler_for_exception(int index);
// VM calls
private:
llvm::CallInst* call_vm(llvm::Value* callee,
llvm::Value** args_start,
llvm::Value** args_end,
int exception_action) {
decache_for_VM_call();
stack()->CreateSetLastJavaFrame();
llvm::CallInst *res = builder()->CreateCall(callee, args_start, args_end);
stack()->CreateResetLastJavaFrame();
cache_after_VM_call();
if (exception_action & EAM_CHECK) {
check_pending_exception(exception_action);
current_state()->set_has_safepointed(true);
}
return res;
}
public:
llvm::CallInst* call_vm(llvm::Value* callee,
int exception_action) {
llvm::Value *args[] = {thread()};
return call_vm(callee, args, args + 1, exception_action);
}
llvm::CallInst* call_vm(llvm::Value* callee,
llvm::Value* arg1,
int exception_action) {
llvm::Value *args[] = {thread(), arg1};
return call_vm(callee, args, args + 2, exception_action);
}
llvm::CallInst* call_vm(llvm::Value* callee,
llvm::Value* arg1,
llvm::Value* arg2,
int exception_action) {
llvm::Value *args[] = {thread(), arg1, arg2};
return call_vm(callee, args, args + 3, exception_action);
}
llvm::CallInst* call_vm(llvm::Value* callee,
llvm::Value* arg1,
llvm::Value* arg2,
llvm::Value* arg3,
int exception_action) {
llvm::Value *args[] = {thread(), arg1, arg2, arg3};
return call_vm(callee, args, args + 4, exception_action);
}
// VM call oop return handling
private:
llvm::LoadInst* get_vm_result() const {
llvm::Value *addr = builder()->CreateAddressOfStructEntry(
thread(), JavaThread::vm_result_offset(),
llvm::PointerType::getUnqual(SharkType::oop_type()),
"vm_result_addr");
llvm::LoadInst *result = builder()->CreateLoad(addr, "vm_result");
builder()->CreateStore(LLVMValue::null(), addr);
return result;
}
// Synchronization
private:
void acquire_lock(llvm::Value* lockee, int exception_action);
void release_lock(int exception_action);
public:
void acquire_method_lock();
// Bounds checks
private:
void check_bounds(SharkValue* array, SharkValue* index);
// Safepoints
private:
void maybe_add_safepoint();
void maybe_add_backedge_safepoint();
// Loop safepoint removal
private:
bool _can_reach_visited;
bool can_reach(SharkTopLevelBlock* other);
bool can_reach_helper(SharkTopLevelBlock* other);
// Traps
private:
llvm::BasicBlock* make_trap(int trap_bci, int trap_request);
void do_trap(int trap_request);
// Returns
private:
void call_register_finalizer(llvm::Value* receiver);
void handle_return(BasicType type, llvm::Value* exception);
// arraylength
private:
void do_arraylength();
// *aload and *astore
private:
void do_aload(BasicType basic_type);
void do_astore(BasicType basic_type);
// *return and athrow
private:
void do_return(BasicType type);
void do_athrow();
// goto*
private:
void do_goto();
// jsr* and ret
private:
void do_jsr();
void do_ret();
// if*
private:
void do_if_helper(llvm::ICmpInst::Predicate p,
llvm::Value* b,
llvm::Value* a,
SharkState* if_taken_state,
SharkState* not_taken_state);
void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a);
// tableswitch and lookupswitch
private:
void do_switch();
// invoke*
private:
ciMethod* improve_virtual_call(ciMethod* caller,
ciInstanceKlass* klass,
ciMethod* dest_method,
ciType* receiver_type);
llvm::Value* get_direct_callee(ciMethod* method);
llvm::Value* get_virtual_callee(SharkValue* receiver, int vtable_index);
llvm::Value* get_interface_callee(SharkValue* receiver, ciMethod* method);
void do_call();
// checkcast and instanceof
private:
bool static_subtype_check(ciKlass* check_klass, ciKlass* object_klass);
void do_full_instance_check(ciKlass* klass);
void do_trapping_instance_check(ciKlass* klass);
void do_instance_check();
bool maybe_do_instanceof_if();
// 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();
};
#endif // SHARE_VM_SHARK_SHARKTOPLEVELBLOCK_HPP