/*
* Copyright 2008, 2009, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*
*/
#include "precompiled.hpp"
#include "ci/ciField.hpp"
#include "ci/ciInstance.hpp"
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciStreams.hpp"
#include "ci/ciType.hpp"
#include "ci/ciTypeFlow.hpp"
#include "interpreter/bytecodes.hpp"
#include "memory/allocation.hpp"
#include "runtime/deoptimization.hpp"
#include "shark/llvmHeaders.hpp"
#include "shark/llvmValue.hpp"
#include "shark/sharkBuilder.hpp"
#include "shark/sharkCacheDecache.hpp"
#include "shark/sharkConstant.hpp"
#include "shark/sharkInliner.hpp"
#include "shark/sharkState.hpp"
#include "shark/sharkTopLevelBlock.hpp"
#include "shark/sharkValue.hpp"
#include "shark/shark_globals.hpp"
using namespace llvm;
// If typeflow found a trap then don't scan past it
// Scan the bytecode for traps that are always hit
bool will_link;
bool is_field;
switch (bc()) {
return;
}
break;
case Bytecodes::_getstatic:
case Bytecodes::_putstatic:
// If the bytecode does not match the field then bail out to
// the interpreter to throw an IncompatibleClassChangeError
return;
}
// Bail out if we are trying to access a static variable
// before the class initializer has completed.
if (!static_field_ok_in_clinit(field)) {
return;
}
}
break;
case Bytecodes::_invokestatic:
case Bytecodes::_invokespecial:
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface:
return;
}
iter()->get_declared_method_holder());
return;
}
}
break;
// Bail out if the class is unloaded
return;
}
// Bail out if the class cannot be instantiated
return;
}
break;
}
}
// Trap if typeflow trapped (and we didn't before)
return;
}
}
// This code is lifted pretty much verbatim from C2's
// Parse::static_field_ok_in_clinit() in parse3.cpp.
bool access_OK = false;
// It's OK to access static fields from the class initializer
access_OK = true;
}
}
else {
// It's also OK to access static fields inside a constructor,
// because any thread calling the constructor must first have
// synchronized on the class by executing a "new" bytecode.
access_OK = true;
}
}
}
return access_OK;
}
if (_entry_state == NULL) {
_entry_state = new SharkPHIState(this);
}
return _entry_state;
}
if (needs_phis()) {
}
else if (_entry_state == NULL) {
}
else {
}
}
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 ||
_needs_phis = true;
// Recurse into the tree
if (!entered()) {
_entered = true;
if (!has_trap()) {
for (int i = 0; i < num_successors(); i++) {
}
}
for (int i = 0; i < num_exceptions(); i++) {
if (handler)
}
}
}
"bci_%d%s",
}
xpop();
}
case T_BOOLEAN:
case T_BYTE:
case T_CHAR:
case T_SHORT:
break;
default:
}
}
}
}
}
}
// Parse the bytecode
// If this block falls through to the next then it won't have been
// terminated by a bytecode and we have to add the branch ourselves
if (falls_through() && !has_trap())
}
// XXX now with Linear Search Technology (tm)
for (int i = 0; i < num_successors(); i++) {
}
}
}
else {
}
value->set_zero_checked(true);
}
int bci,
}
else {
}
}
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);
break;
case T_LONG:
a = value->jlong_value();
b = LLVMValue::jlong_constant(0);
break;
case T_OBJECT:
case T_ARRAY:
a = value->jobject_value();
break;
default:
}
builder()->CreateCondBr(
if (value->is_jobject()) {
}
else {
}
}
// we use an unsigned comparison to catch negative values
builder()->CreateCondBr(
index->jint_value(),
}
builder()->CreateCondBr(
if (action & EAM_MONITOR_FUDGE) {
// The top monitor is marked live, but the exception was thrown
// while setting it up so we need to mark it dead before we enter
// any exception handlers as they will not expect it to be there.
}
}
int index = 0;
break;
// Try and get this exception's handler from typeflow. We should
// do it this way always, really, except that typeflow sometimes
// doesn't record exceptions, even loaded ones, and sometimes it
// returns them with a different handler bci. Why???
if (handler->is_catch_all()) {
}
else {
}
break;
else
}
}
// If typeflow let us down then try and figure it out ourselves
for (int i = 0; i < function()->block_count(); i++) {
break;
}
}
}
}
}
}
// Clear the stack and push the exception onto it
while (xstack_depth())
pop();
// Work out how many options we have to check
if (has_catch_all)
num_options--;
// Marshal any non-catch-all handlers
if (num_options > 0) {
bool all_loaded = true;
for (int i = 0; i < num_options; i++) {
all_loaded = false;
break;
}
}
if (all_loaded)
else
}
// Install the catch-all handler, if present
if (has_catch_all) {
return;
}
}
// No exception handler was found; unwind and return
}
xstack(0)->jobject_value(),
"exception_klass");
for (int i = 0; i < num_options; i++) {
builder()->CreateCondBr(
builder()->CreateCondBr(
builder()->CreateICmpNE(
builder()->CreateCall2(
LLVMValue::jbyte_constant(0)),
}
}
for (int i = 0; i < num_options; i++)
num_options * sizeof(int),
for (int i = 0; i < num_options; i++) {
LLVMValue::jint_constant(i),
}
}
if (successor) {
return successor->entry_block();
}
else {
return make_trap(
}
}
if (current_state()->has_safepointed())
return;
"state");
builder()->CreateCondBr(
builder()->CreateICmpEQ(
current_state()->set_has_safepointed(true);
}
if (current_state()->has_safepointed())
return;
for (int i = 0; i < num_successors(); i++) {
break;
}
}
}
for (int i = 0; i < function()->block_count(); i++)
return can_reach_helper(other);
}
if (this == other)
return true;
if (_can_reach_visited)
return false;
_can_reach_visited = true;
if (!has_trap()) {
for (int i = 0; i < num_successors(); i++) {
return true;
}
}
for (int i = 0; i < num_exceptions(); i++) {
return true;
}
return false;
}
return trap_block;
}
builder()->CreateCall2(
builder()->uncommon_trap(),
thread(),
}
"klass");
"access_flags");
builder()->CreateCondBr(
builder()->CreateICmpNE(
LLVMValue::jint_constant(0)),
}
if (num_monitors()) {
// Protect our exception across possible monitor release decaches
if (exception)
// We don't need to check for exceptions thrown here. If
// we're returning a value then we just carry on as normal:
// the caller will see the pending exception and handle it.
// If we're returning with an exception then that exception
// takes priority and the release_lock one will be ignored.
while (num_monitors())
// Reload the exception we're throwing
if (exception)
exception = get_oop_tmp();
}
if (exception) {
}
builder()->CreateStore(
}
}
}
switch (basic_type) {
case T_BYTE:
case T_CHAR:
case T_SHORT:
case T_INT:
break;
case T_LONG:
break;
case T_FLOAT:
break;
case T_DOUBLE:
break;
case T_OBJECT:
// You might expect that array->type()->is_array_klass() would
// always be true, but it isn't. If ciTypeFlow detects that a
// value is always null then that value becomes an untyped null
// object. Shark doesn't presently support this, so a generic
// T_OBJECT is created. In this case we guess the type using
// the BasicType we were supplied. In reality the generated
// code will never be used, as the null value will be caught
// by the above null pointer check.
push(
value, false));
break;
default:
}
}
switch (basic_type) {
case T_BYTE:
case T_CHAR:
case T_SHORT:
case T_INT:
break;
case T_LONG:
break;
case T_FLOAT:
break;
case T_DOUBLE:
break;
case T_OBJECT:
// XXX assignability check
break;
default:
}
}
}
}
}
}
}
// All propagation of state from one block to the next (via
// dest->add_incoming) is handled by these methods:
// do_branch
// do_if_helper
// do_switch
// handle_exception
}
SharkValue* b,
SharkValue* a) {
if (a->is_jobject()) {
}
else {
llvm_a = a->jint_value();
llvm_b = b->jint_value();
}
}
Value* b,
Value* a,
builder()->CreateCondBr(
builder()->CreateICmp(p, a, b),
}
for (int i = 0; i < len; i++) {
if (dest_bci != switch_default_dest()) {
dest_block->entry_block());
}
}
}
ciType* receiver_type) {
// If the method is obviously final then we are already done
if (dest_method->can_be_statically_bound())
return dest_method;
// Array methods are all inherited from Object and are monomorphic
if (receiver_type->is_array_klass() &&
return dest_method;
// This code can replace a virtual call with a direct call if this
// class is the only one in the entire set of loaded classes that
// implements this method. This makes the compiled code dependent
// on other classes that implement the method not being loaded, a
// condition which is enforced by the dependency tracker. If the
// dependency tracker determines a method has become invalid it
// will mark it for recompilation, causing running copies to be
// deoptimized. Shark currently can't deoptimize arbitrarily like
// that, so this optimization cannot be used.
// All other interesting cases are instance classes
if (!receiver_type->is_instance_klass())
return NULL;
// Attempt to improve the receiver
if (improved_receiver->is_loaded() &&
!improved_receiver->is_interface() &&
}
// Attempt to find a monomorphic target for this call using
// class heirachy analysis.
if (monomorphic_target != NULL) {
// Opto has a bunch of type checking here that I don't
// understand. It's to inhibit casting in one direction,
// possibly because objects in Opto can have inexact
// types, but I can't even tell which direction it
// doesn't like. For now I'm going to block *any* cast.
if (monomorphic_target != dest_method) {
if (SharkPerformanceWarnings) {
warning("found monomorphic target, but inhibited cast:");
}
}
}
// Replace the virtual call with a direct one. This makes
// us dependent on that target method not getting overridden
// by dynamic class loading.
if (monomorphic_target != NULL) {
return monomorphic_target;
}
// Because Opto distinguishes exact types from inexact ones
// it can perform a further optimization to replace calls
// with non-monomorphic targets if the receiver has an exact
// type. We don't mark types this way, so we can't do this.
#endif // SHARK_CAN_DEOPTIMIZE_ANYWHERE
return NULL;
}
return builder()->CreateBitCast(
"callee");
}
int vtable_index) {
"klass");
return builder()->CreateLoad(
"callee");
}
// Locate the receiver's itable
"object_klass");
"vtable_start");
"vtable_length");
if (needs_aligning) {
"itable_start");
}
// Locate this interface's entry in the table
"itable_iklass");
builder()->CreateCondBr(
// 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()->CreateUnreachable();
builder()->CreateCondBr(
// Locate the method pointer
"offset");
offset =
return builder()->CreateLoad(
offset),
"callee");
}
// Set frequently used booleans
// Find the method being called
bool will_link;
// Find the class of the method being called. Note
// that the superclass check in the second assertion
// is to cope with a hole in the spec that allows for
// invokeinterface instructions where the resolved
// method is a virtual method in java.lang.Object.
// javac doesn't generate code like that, but there's
// no reason a compliant Java compiler might not.
!is_interface, "must match bc");
// Find the receiver in the stack. We do this before
// trying to inline because the inliner can only use
// zero-checked values, not being able to perform the
// check itself.
if (!is_static) {
}
// Try to improve non-direct calls
if (call_is_virtual) {
if (optimized_method) {
call_is_virtual = false;
}
}
// Try to inline the call
if (!call_is_virtual) {
return;
}
// Find the method we are calling
if (call_is_virtual) {
if (is_virtual) {
}
else {
}
}
else {
}
// Load the SharkEntry from the callee
SharkType::intptr_type(),
"base_pc");
// Load the entry point from the SharkEntry
"entry_point");
// Make the call
// If the callee got deoptimized then reexecute in the interpreter
builder()->CreateCondBr(
builder()->CreateCall2(
thread());
// Cache after the call
// Check for pending exceptions
// Mark that a safepoint check has occurred
current_state()->set_has_safepointed(true);
}
ciKlass* object_klass) {
// If the class we're checking against is java.lang.Object
// then this is a no brainer. Apparently this can happen
// in reflective code...
if (check_klass == java_lang_Object_klass())
return true;
// Perform a subtype check. NB in opto's code for this
// (GraphKit::static_subtype_check) it says that static
// interface types cannot be trusted, and if opto can't
// trust them then I assume we can't either.
if (object_klass == check_klass)
return true;
return true;
}
return false;
}
// Get the class we're checking against
bool will_link;
// Get the class of the object we're checking
// Can we optimize this check away?
pop();
}
return;
}
// Need to check this one at runtime
if (will_link)
else
}
// Get the class we're checking against
bool will_link;
// If the class is unloaded then the instanceof
// cannot possibly succeed.
if (!will_link)
return false;
// Keep a copy of the object we're checking
// Get the class of the object we're checking
// If the instanceof can be optimized away at compile time
// then any subsequent checkcasts will be too so we handle
// it normally.
return false;
// Perform the instance check
// Create the casted object
// Create two copies of the current state, one with the
// original object and one with all instances of the
// original object replaced with the new, casted object.
// Perform the check-and-branch
// branch if not an instance
break;
// branch if an instance
break;
default:
}
return true;
}
enum InstanceCheckStates {
};
// Pop the object off the stack
// Null objects aren't instances of anything
builder()->CreateCondBr(
// Get the class we're checking against
// Get the class of the object being tested
"object_klass");
// Perform the check
builder()->CreateCondBr(
builder()->CreateCondBr(
builder()->CreateICmpNE(
builder()->CreateCall2(
LLVMValue::jbyte_constant(0)),
// First merge
// Second merge
// Handle the result
builder()->CreateCondBr(
builder()->CreateICmpNE(
}
else {
push(
builder()->CreateIntCast(
builder()->CreateICmpEQ(
}
}
// Leave the object on the stack so it's there if we trap
builder()->CreateCondBr(
// If it's not null then we need to trap
// If it's null then we're ok
}
else {
pop();
}
}
bool will_link;
// The fast path
if (UseTLAB) {
}
// Thread local allocation
if (UseTLAB) {
"top_addr");
SharkType::intptr_type(),
"end");
builder()->CreateCondBr(
}
// Heap allocation
"top_addr");
"end");
builder()->CreateCondBr(
builder()->CreateCondBr(
initialize, retry);
// Initialize the object
if (tlab_object) {
fast_object = phi;
}
else {
}
builder()->CreateMemset(
builder()->CreateBitCast(
LLVMValue::jbyte_constant(0),
"mark_addr");
"klass_addr");
// Set the mark
if (UseBiasedLocking) {
}
else {
}
// Set the class
}
// The slow path
builder()->new_instance(),
slow_object = get_vm_result();
// Push the object
if (push_object) {
}
if (fast_object) {
}
else {
}
}
pop()->jint_value(),
}
bool will_link;
if (!array_klass->is_loaded()) {
}
pop()->jint_value(),
}
bool will_link;
// 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.
"dimensions");
for (int i = 0; i < ndims; i++) {
builder()->CreateStore(
}
builder()->multianewarray(),
// Now we can pop the dimensions off the stack
for (int i = 0; i < ndims; i++)
pop();
}
else
}
}
pop(); // don't need this (monitors are block structured)
}
// Store the object and mark the slot as live
// Try a simple lock
"mark_addr");
builder()->CreateCondBr(
// Locking failed, but maybe this thread already owns it
disp,
// NB we use the entire stack, but JavaThread::is_lock_owned()
// uses a more limited range. I don't think it hurts though...
SharkType::intptr_type(),
"stack_limit");
SharkType::intptr_type(),
"stack_size");
builder()->CreateCondBr(
// Create an edge for the state merge
// It's not a recursive case so we need to drop into the runtime
// All done
}
// If it is recursive then we're already done
builder()->CreateCondBr(
// Try a simple unlock
"mark_addr");
builder()->CreateCondBr(
// Create an edge for the state merge
// Need to drop into the runtime to release this one
// All done
// The object slot is now dead
}