Initial load

This commit is contained in:
J. Duke 2007-12-01 00:00:00 +00:00
parent 686d76f772
commit 8153779ad3
2894 changed files with 911801 additions and 0 deletions

View file

@ -0,0 +1,245 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// This file contains the platform-independant parts
// of the abstract interpreter and the abstract interpreter generator.
// Organization of the interpreter(s). There exists two different interpreters in hotpot
// an assembly language version (aka template interpreter) and a high level language version
// (aka c++ interpreter). Th division of labor is as follows:
// Template Interpreter C++ Interpreter Functionality
//
// templateTable* bytecodeInterpreter* actual interpretation of bytecodes
//
// templateInterpreter* cppInterpreter* generation of assembly code that creates
// and manages interpreter runtime frames.
// Also code for populating interpreter
// frames created during deoptimization.
//
// For both template and c++ interpreter. There are common files for aspects of the interpreter
// that are generic to both interpreters. This is the layout:
//
// abstractInterpreter.hpp: generic description of the interpreter.
// interpreter*: generic frame creation and handling.
//
//------------------------------------------------------------------------------------------------------------------------
// The C++ interface to the bytecode interpreter(s).
class AbstractInterpreter: AllStatic {
friend class VMStructs;
friend class Interpreter;
friend class CppInterpreterGenerator;
public:
enum MethodKind {
zerolocals, // method needs locals initialization
zerolocals_synchronized, // method needs locals initialization & is synchronized
native, // native method
native_synchronized, // native method & is synchronized
empty, // empty method (code: _return)
accessor, // accessor method (code: _aload_0, _getfield, _(a|i)return)
abstract, // abstract method (throws an AbstractMethodException)
java_lang_math_sin, // implementation of java.lang.Math.sin (x)
java_lang_math_cos, // implementation of java.lang.Math.cos (x)
java_lang_math_tan, // implementation of java.lang.Math.tan (x)
java_lang_math_abs, // implementation of java.lang.Math.abs (x)
java_lang_math_sqrt, // implementation of java.lang.Math.sqrt (x)
java_lang_math_log, // implementation of java.lang.Math.log (x)
java_lang_math_log10, // implementation of java.lang.Math.log10 (x)
number_of_method_entries,
invalid = -1
};
enum SomeConstants {
number_of_result_handlers = 10 // number of result handlers for native calls
};
protected:
static StubQueue* _code; // the interpreter code (codelets)
static bool _notice_safepoints; // true if safepoints are activated
static address _native_entry_begin; // Region for native entry code
static address _native_entry_end;
// method entry points
static address _entry_table[number_of_method_entries]; // entry points for a given method
static address _native_abi_to_tosca[number_of_result_handlers]; // for native method result handlers
static address _slow_signature_handler; // the native method generic (slow) signature handler
static address _rethrow_exception_entry; // rethrows an activation in previous frame
friend class AbstractInterpreterGenerator;
friend class InterpreterGenerator;
friend class InterpreterMacroAssembler;
public:
// Initialization/debugging
static void initialize();
static StubQueue* code() { return _code; }
// Method activation
static MethodKind method_kind(methodHandle m);
static address entry_for_kind(MethodKind k) { assert(0 <= k && k < number_of_method_entries, "illegal kind"); return _entry_table[k]; }
static address entry_for_method(methodHandle m) { return _entry_table[method_kind(m)]; }
static void print_method_kind(MethodKind kind) PRODUCT_RETURN;
// Runtime support
// length = invoke bytecode length (to advance to next bytecode)
static address deopt_entry (TosState state, int length) { ShouldNotReachHere(); return NULL; }
static address return_entry (TosState state, int length) { ShouldNotReachHere(); return NULL; }
static address rethrow_exception_entry() { return _rethrow_exception_entry; }
// Activation size in words for a method that is just being called.
// Parameters haven't been pushed so count them too.
static int size_top_interpreter_activation(methodOop method);
// Deoptimization support
static address continuation_for(methodOop method,
address bcp,
int callee_parameters,
bool is_top_frame,
bool& use_next_mdp);
// share implementation of size_activation and layout_activation:
static int size_activation(methodOop method,
int temps,
int popframe_args,
int monitors,
int callee_params,
int callee_locals,
bool is_top_frame);
static int layout_activation(methodOop method,
int temps,
int popframe_args,
int monitors,
int callee_params,
int callee_locals,
frame* caller,
frame* interpreter_frame,
bool is_top_frame);
// Runtime support
static bool is_not_reached( methodHandle method, int bci);
// Safepoint support
static void notice_safepoints() { ShouldNotReachHere(); } // stops the thread when reaching a safepoint
static void ignore_safepoints() { ShouldNotReachHere(); } // ignores safepoints
// Support for native calls
static address slow_signature_handler() { return _slow_signature_handler; }
static address result_handler(BasicType type) { return _native_abi_to_tosca[BasicType_as_index(type)]; }
static int BasicType_as_index(BasicType type); // computes index into result_handler_by_index table
static bool in_native_entry(address pc) { return _native_entry_begin <= pc && pc < _native_entry_end; }
// Debugging/printing
static void print(); // prints the interpreter code
// Support for Tagged Stacks
//
// Tags are stored on the Java Expression stack above the value:
//
// tag
// value
//
// For double values:
//
// tag2
// high word
// tag1
// low word
public:
static int stackElementWords() { return TaggedStackInterpreter ? 2 : 1; }
static int stackElementSize() { return stackElementWords()*wordSize; }
static int logStackElementSize() { return
TaggedStackInterpreter? LogBytesPerWord+1 : LogBytesPerWord; }
// Tag is at pointer, value is one below for a stack growing down
// (or above for stack growing up)
static int value_offset_in_bytes() {
return TaggedStackInterpreter ?
frame::interpreter_frame_expression_stack_direction() * wordSize : 0;
}
static int tag_offset_in_bytes() {
assert(TaggedStackInterpreter, "should not call this");
return 0;
}
// Tagged Locals
// Locals are stored relative to Llocals:
//
// tag <- Llocals[n]
// value
//
// Category 2 types are indexed as:
//
// tag <- Llocals[-n]
// high word
// tag <- Llocals[-n+1]
// low word
//
// Local values relative to locals[n]
static int local_offset_in_bytes(int n) {
return ((frame::interpreter_frame_expression_stack_direction() * n) *
stackElementSize()) + value_offset_in_bytes();
}
static int local_tag_offset_in_bytes(int n) {
assert(TaggedStackInterpreter, "should not call this");
return ((frame::interpreter_frame_expression_stack_direction() * n) *
stackElementSize()) + tag_offset_in_bytes();
}
};
//------------------------------------------------------------------------------------------------------------------------
// The interpreter generator.
class Template;
class AbstractInterpreterGenerator: public StackObj {
protected:
InterpreterMacroAssembler* _masm;
// shared code sequences
// Converter for native abi result to tosca result
address generate_result_handler_for(BasicType type);
address generate_slow_signature_handler();
// entry point generator
address generate_method_entry(AbstractInterpreter::MethodKind kind);
void bang_stack_shadow_pages(bool native_call);
void generate_all();
public:
AbstractInterpreterGenerator(StubQueue* _code);
};

View file

@ -0,0 +1,205 @@
/*
* Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved.
* 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/_bytecode.cpp.incl"
// Implementation of Bytecode
// Should eventually get rid of these functions and use ThisRelativeObj methods instead
void Bytecode::set_code(Bytecodes::Code code) {
Bytecodes::check(code);
*addr_at(0) = u_char(code);
}
void Bytecode::set_fast_index(int i) {
assert(0 <= i && i < 0x10000, "illegal index value");
Bytes::put_native_u2(addr_at(1), (jushort)i);
}
bool Bytecode::check_must_rewrite() const {
assert(Bytecodes::can_rewrite(code()), "post-check only");
// Some codes are conditionally rewriting. Look closely at them.
switch (code()) {
case Bytecodes::_aload_0:
// Even if RewriteFrequentPairs is turned on,
// the _aload_0 code might delay its rewrite until
// a following _getfield rewrites itself.
return false;
case Bytecodes::_lookupswitch:
return false; // the rewrite is not done by the interpreter
case Bytecodes::_new:
// (Could actually look at the class here, but the profit would be small.)
return false; // the rewrite is not always done
}
// No other special cases.
return true;
}
// Implementation of Bytecode_tableupswitch
int Bytecode_tableswitch::dest_offset_at(int i) const {
address x = aligned_addr_at(1);
int x2 = aligned_offset(1 + (3 + i)*jintSize);
int val = java_signed_word_at(x2);
return java_signed_word_at(aligned_offset(1 + (3 + i)*jintSize));
}
// Implementation of Bytecode_invoke
void Bytecode_invoke::verify() const {
Bytecodes::Code bc = adjusted_invoke_code();
assert(is_valid(), "check invoke");
}
symbolOop Bytecode_invoke::signature() const {
constantPoolOop constants = method()->constants();
return constants->signature_ref_at(index());
}
symbolOop Bytecode_invoke::name() const {
constantPoolOop constants = method()->constants();
return constants->name_ref_at(index());
}
BasicType Bytecode_invoke::result_type(Thread *thread) const {
symbolHandle sh(thread, signature());
ResultTypeFinder rts(sh);
rts.iterate();
return rts.type();
}
methodHandle Bytecode_invoke::static_target(TRAPS) {
methodHandle m;
KlassHandle resolved_klass;
constantPoolHandle constants(THREAD, _method->constants());
if (adjusted_invoke_code() != Bytecodes::_invokeinterface) {
LinkResolver::resolve_method(m, resolved_klass, constants, index(), CHECK_(methodHandle()));
} else {
LinkResolver::resolve_interface_method(m, resolved_klass, constants, index(), CHECK_(methodHandle()));
}
return m;
}
int Bytecode_invoke::index() const {
return Bytes::get_Java_u2(bcp() + 1);
}
// Implementation of Bytecode_static
void Bytecode_static::verify() const {
assert(Bytecodes::java_code(code()) == Bytecodes::_putstatic
|| Bytecodes::java_code(code()) == Bytecodes::_getstatic, "check static");
}
BasicType Bytecode_static::result_type(methodOop method) const {
int index = java_hwrd_at(1);
constantPoolOop constants = method->constants();
symbolOop field_type = constants->signature_ref_at(index);
BasicType basic_type = FieldType::basic_type(field_type);
return basic_type;
}
// Implementation of Bytecode_field
void Bytecode_field::verify() const {
Bytecodes::Code stdc = Bytecodes::java_code(code());
assert(stdc == Bytecodes::_putstatic || stdc == Bytecodes::_getstatic ||
stdc == Bytecodes::_putfield || stdc == Bytecodes::_getfield, "check field");
}
bool Bytecode_field::is_static() const {
Bytecodes::Code stdc = Bytecodes::java_code(code());
return stdc == Bytecodes::_putstatic || stdc == Bytecodes::_getstatic;
}
int Bytecode_field::index() const {
return java_hwrd_at(1);
}
// Implementation of Bytecodes loac constant
int Bytecode_loadconstant::index() const {
Bytecodes::Code stdc = Bytecodes::java_code(code());
return stdc == Bytecodes::_ldc ? java_byte_at(1) : java_hwrd_at(1);
}
//------------------------------------------------------------------------------
// Non-product code
#ifndef PRODUCT
void Bytecode_lookupswitch::verify() const {
switch (Bytecodes::java_code(code())) {
case Bytecodes::_lookupswitch:
{ int i = number_of_pairs() - 1;
while (i-- > 0) {
assert(pair_at(i)->match() < pair_at(i+1)->match(), "unsorted table entries");
}
}
break;
default:
fatal("not a lookupswitch bytecode");
}
}
void Bytecode_tableswitch::verify() const {
switch (Bytecodes::java_code(code())) {
case Bytecodes::_tableswitch:
{ int lo = low_key();
int hi = high_key();
assert (hi >= lo, "incorrect hi/lo values in tableswitch");
int i = hi - lo - 1 ;
while (i-- > 0) {
// no special check needed
}
}
break;
default:
fatal("not a tableswitch bytecode");
}
}
#endif

View file

@ -0,0 +1,376 @@
/*
* Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// Base class for different kinds of abstractions working
// relative to an objects 'this' pointer.
class ThisRelativeObj VALUE_OBJ_CLASS_SPEC {
private:
int sign_extend (int x, int size) const { const int s = (BytesPerInt - size)*BitsPerByte; return (x << s) >> s; }
public:
// Address computation
address addr_at (int offset) const { return (address)this + offset; }
address aligned_addr_at (int offset) const { return (address)round_to((intptr_t)addr_at(offset), jintSize); }
int aligned_offset (int offset) const { return aligned_addr_at(offset) - addr_at(0); }
// Java unsigned accessors (using Java spec byte ordering)
int java_byte_at (int offset) const { return *(jubyte*)addr_at(offset); }
int java_hwrd_at (int offset) const { return java_byte_at(offset) << (1 * BitsPerByte) | java_byte_at(offset + 1); }
int java_word_at (int offset) const { return java_hwrd_at(offset) << (2 * BitsPerByte) | java_hwrd_at(offset + 2); }
// Java signed accessors (using Java spec byte ordering)
int java_signed_byte_at(int offset) const { return sign_extend(java_byte_at(offset), 1); }
int java_signed_hwrd_at(int offset) const { return sign_extend(java_hwrd_at(offset), 2); }
int java_signed_word_at(int offset) const { return java_word_at(offset) ; }
// Fast accessors (using the machine's natural byte ordering)
int fast_byte_at (int offset) const { return *(jubyte *)addr_at(offset); }
int fast_hwrd_at (int offset) const { return *(jushort*)addr_at(offset); }
int fast_word_at (int offset) const { return *(juint *)addr_at(offset); }
// Fast signed accessors (using the machine's natural byte ordering)
int fast_signed_byte_at(int offset) const { return *(jbyte *)addr_at(offset); }
int fast_signed_hwrd_at(int offset) const { return *(jshort*)addr_at(offset); }
int fast_signed_word_at(int offset) const { return *(jint *)addr_at(offset); }
// Fast manipulators (using the machine's natural byte ordering)
void set_fast_byte_at (int offset, int x) const { *(jbyte *)addr_at(offset) = (jbyte )x; }
void set_fast_hwrd_at (int offset, int x) const { *(jshort*)addr_at(offset) = (jshort)x; }
void set_fast_word_at (int offset, int x) const { *(jint *)addr_at(offset) = (jint )x; }
};
// The base class for different kinds of bytecode abstractions.
// Provides the primitive operations to manipulate code relative
// to an objects 'this' pointer.
//
// Note: Even though it seems that the fast_index & set_fast_index
// functions are machine specific, they're not. They only use
// the natural way to store a 16bit index on a given machine,
// independent of the particular byte ordering. Since all other
// places in the system that refer to these indices use the
// same method (the natural byte ordering on the platform)
// this will always work and be machine-independent).
class Bytecode: public ThisRelativeObj {
protected:
u_char byte_at(int offset) const { return *addr_at(offset); }
bool check_must_rewrite() const;
public:
// Attributes
address bcp() const { return addr_at(0); }
address next_bcp() const { return addr_at(0) + Bytecodes::length_at(bcp()); }
Bytecodes::Code code() const { return Bytecodes::code_at(addr_at(0)); }
Bytecodes::Code java_code() const { return Bytecodes::java_code(code()); }
bool must_rewrite() const { return Bytecodes::can_rewrite(code()) && check_must_rewrite(); }
bool is_active_breakpoint() const { return Bytecodes::is_active_breakpoint_at(bcp()); }
int one_byte_index() const { return byte_at(1); }
int two_byte_index() const { return (byte_at(1) << 8) + byte_at(2); }
int offset() const { return (two_byte_index() << 16) >> 16; }
address destination() const { return bcp() + offset(); }
int fast_index() const { return Bytes::get_native_u2(addr_at(1)); }
// Attribute modification
void set_code(Bytecodes::Code code);
void set_fast_index(int i);
// Creation
inline friend Bytecode* Bytecode_at(address bcp);
};
inline Bytecode* Bytecode_at(address bcp) {
return (Bytecode*)bcp;
}
// Abstractions for lookupswitch bytecode
class LookupswitchPair: ThisRelativeObj {
private:
int _match;
int _offset;
public:
int match() const { return java_signed_word_at(0 * jintSize); }
int offset() const { return java_signed_word_at(1 * jintSize); }
};
class Bytecode_lookupswitch: public Bytecode {
public:
void verify() const PRODUCT_RETURN;
// Attributes
int default_offset() const { return java_signed_word_at(aligned_offset(1 + 0*jintSize)); }
int number_of_pairs() const { return java_signed_word_at(aligned_offset(1 + 1*jintSize)); }
LookupswitchPair* pair_at(int i) const { assert(0 <= i && i < number_of_pairs(), "pair index out of bounds");
return (LookupswitchPair*)aligned_addr_at(1 + (1 + i)*2*jintSize); }
// Creation
inline friend Bytecode_lookupswitch* Bytecode_lookupswitch_at(address bcp);
};
inline Bytecode_lookupswitch* Bytecode_lookupswitch_at(address bcp) {
Bytecode_lookupswitch* b = (Bytecode_lookupswitch*)bcp;
debug_only(b->verify());
return b;
}
class Bytecode_tableswitch: public Bytecode {
public:
void verify() const PRODUCT_RETURN;
// Attributes
int default_offset() const { return java_signed_word_at(aligned_offset(1 + 0*jintSize)); }
int low_key() const { return java_signed_word_at(aligned_offset(1 + 1*jintSize)); }
int high_key() const { return java_signed_word_at(aligned_offset(1 + 2*jintSize)); }
int dest_offset_at(int i) const;
int length() { return high_key()-low_key()+1; }
// Creation
inline friend Bytecode_tableswitch* Bytecode_tableswitch_at(address bcp);
};
inline Bytecode_tableswitch* Bytecode_tableswitch_at(address bcp) {
Bytecode_tableswitch* b = (Bytecode_tableswitch*)bcp;
debug_only(b->verify());
return b;
}
// Abstraction for invoke_{virtual, static, interface, special}
class Bytecode_invoke: public ResourceObj {
protected:
methodHandle _method; // method containing the bytecode
int _bci; // position of the bytecode
Bytecode_invoke(methodHandle method, int bci) : _method(method), _bci(bci) {}
public:
void verify() const;
// Attributes
methodHandle method() const { return _method; }
int bci() const { return _bci; }
address bcp() const { return _method->bcp_from(bci()); }
int index() const; // the constant pool index for the invoke
symbolOop name() const; // returns the name of the invoked method
symbolOop signature() const; // returns the signature of the invoked method
BasicType result_type(Thread *thread) const; // returns the result type of the invoke
Bytecodes::Code code() const { return Bytecodes::code_at(bcp(), _method()); }
Bytecodes::Code adjusted_invoke_code() const { return Bytecodes::java_code(code()); }
methodHandle static_target(TRAPS); // "specified" method (from constant pool)
// Testers
bool is_invokeinterface() const { return adjusted_invoke_code() == Bytecodes::_invokeinterface; }
bool is_invokevirtual() const { return adjusted_invoke_code() == Bytecodes::_invokevirtual; }
bool is_invokestatic() const { return adjusted_invoke_code() == Bytecodes::_invokestatic; }
bool is_invokespecial() const { return adjusted_invoke_code() == Bytecodes::_invokespecial; }
bool is_valid() const { return is_invokeinterface() ||
is_invokevirtual() ||
is_invokestatic() ||
is_invokespecial(); }
// Creation
inline friend Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci);
// Like Bytecode_invoke_at. Instead it returns NULL if the bci is not at an invoke.
inline friend Bytecode_invoke* Bytecode_invoke_at_check(methodHandle method, int bci);
};
inline Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci) {
Bytecode_invoke* b = new Bytecode_invoke(method, bci);
debug_only(b->verify());
return b;
}
inline Bytecode_invoke* Bytecode_invoke_at_check(methodHandle method, int bci) {
Bytecode_invoke* b = new Bytecode_invoke(method, bci);
return b->is_valid() ? b : NULL;
}
// Abstraction for all field accesses (put/get field/static_
class Bytecode_field: public Bytecode {
public:
void verify() const;
int index() const;
bool is_static() const;
// Creation
inline friend Bytecode_field* Bytecode_field_at(const methodOop method, address bcp);
};
inline Bytecode_field* Bytecode_field_at(const methodOop method, address bcp) {
Bytecode_field* b = (Bytecode_field*)bcp;
debug_only(b->verify());
return b;
}
// Abstraction for {get,put}static
class Bytecode_static: public Bytecode {
public:
void verify() const;
// Returns the result type of the send by inspecting the field ref
BasicType result_type(methodOop method) const;
// Creation
inline friend Bytecode_static* Bytecode_static_at(const methodOop method, address bcp);
};
inline Bytecode_static* Bytecode_static_at(const methodOop method, address bcp) {
Bytecode_static* b = (Bytecode_static*)bcp;
debug_only(b->verify());
return b;
}
// Abstraction for checkcast
class Bytecode_checkcast: public Bytecode {
public:
void verify() const { assert(Bytecodes::java_code(code()) == Bytecodes::_checkcast, "check checkcast"); }
// Returns index
long index() const { return java_hwrd_at(1); };
// Creation
inline friend Bytecode_checkcast* Bytecode_checkcast_at(address bcp);
};
inline Bytecode_checkcast* Bytecode_checkcast_at(address bcp) {
Bytecode_checkcast* b = (Bytecode_checkcast*)bcp;
debug_only(b->verify());
return b;
}
// Abstraction for instanceof
class Bytecode_instanceof: public Bytecode {
public:
void verify() const { assert(code() == Bytecodes::_instanceof, "check instanceof"); }
// Returns index
long index() const { return java_hwrd_at(1); };
// Creation
inline friend Bytecode_instanceof* Bytecode_instanceof_at(address bcp);
};
inline Bytecode_instanceof* Bytecode_instanceof_at(address bcp) {
Bytecode_instanceof* b = (Bytecode_instanceof*)bcp;
debug_only(b->verify());
return b;
}
class Bytecode_new: public Bytecode {
public:
void verify() const { assert(java_code() == Bytecodes::_new, "check new"); }
// Returns index
long index() const { return java_hwrd_at(1); };
// Creation
inline friend Bytecode_new* Bytecode_new_at(address bcp);
};
inline Bytecode_new* Bytecode_new_at(address bcp) {
Bytecode_new* b = (Bytecode_new*)bcp;
debug_only(b->verify());
return b;
}
class Bytecode_multianewarray: public Bytecode {
public:
void verify() const { assert(java_code() == Bytecodes::_multianewarray, "check new"); }
// Returns index
long index() const { return java_hwrd_at(1); };
// Creation
inline friend Bytecode_multianewarray* Bytecode_multianewarray_at(address bcp);
};
inline Bytecode_multianewarray* Bytecode_multianewarray_at(address bcp) {
Bytecode_multianewarray* b = (Bytecode_multianewarray*)bcp;
debug_only(b->verify());
return b;
}
class Bytecode_anewarray: public Bytecode {
public:
void verify() const { assert(java_code() == Bytecodes::_anewarray, "check anewarray"); }
// Returns index
long index() const { return java_hwrd_at(1); };
// Creation
inline friend Bytecode_anewarray* Bytecode_anewarray_at(address bcp);
};
inline Bytecode_anewarray* Bytecode_anewarray_at(address bcp) {
Bytecode_anewarray* b = (Bytecode_anewarray*)bcp;
debug_only(b->verify());
return b;
}
// Abstraction for ldc, ldc_w and ldc2_w
class Bytecode_loadconstant: public Bytecode {
public:
void verify() const {
Bytecodes::Code stdc = Bytecodes::java_code(code());
assert(stdc == Bytecodes::_ldc ||
stdc == Bytecodes::_ldc_w ||
stdc == Bytecodes::_ldc2_w, "load constant");
}
int index() const;
inline friend Bytecode_loadconstant* Bytecode_loadconstant_at(const methodOop method, address bcp);
};
inline Bytecode_loadconstant* Bytecode_loadconstant_at(const methodOop method, address bcp) {
Bytecode_loadconstant* b = (Bytecode_loadconstant*)bcp;
debug_only(b->verify());
return b;
}

View file

@ -0,0 +1,186 @@
/*
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
* 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/_bytecodeHistogram.cpp.incl"
// ------------------------------------------------------------------------------------------------
// Non-product code
#ifndef PRODUCT
// Implementation of BytecodeCounter
int BytecodeCounter::_counter_value = 0;
jlong BytecodeCounter::_reset_time = 0;
void BytecodeCounter::reset() {
_counter_value = 0;
_reset_time = os::elapsed_counter();
}
double BytecodeCounter::elapsed_time() {
return (double)(os::elapsed_counter() - _reset_time) / (double)os::elapsed_frequency();
}
double BytecodeCounter::frequency() {
return (double)counter_value() / elapsed_time();
}
void BytecodeCounter::print() {
tty->print_cr(
"%d bytecodes executed in %.1fs (%.3fMHz)",
counter_value(),
elapsed_time(),
frequency() / 1000000.0
);
}
// Helper class for sorting
class HistoEntry: public ResourceObj {
private:
int _index;
int _count;
public:
HistoEntry(int index, int count) { _index = index; _count = count; }
int index() const { return _index; }
int count() const { return _count; }
static int compare(HistoEntry** x, HistoEntry** y) { return (*x)->count() - (*y)->count(); }
};
// Helper functions
static GrowableArray<HistoEntry*>* sorted_array(int* array, int length) {
GrowableArray<HistoEntry*>* a = new GrowableArray<HistoEntry*>(length);
int i = length;
while (i-- > 0) a->append(new HistoEntry(i, array[i]));
a->sort(HistoEntry::compare);
return a;
}
static int total_count(GrowableArray<HistoEntry*>* profile) {
int sum = 0;
int i = profile->length();
while (i-- > 0) sum += profile->at(i)->count();
return sum;
}
static const char* name_for(int i) {
return Bytecodes::is_defined(i) ? Bytecodes::name(Bytecodes::cast(i)) : "xxxunusedxxx";
}
// Implementation of BytecodeHistogram
int BytecodeHistogram::_counters[Bytecodes::number_of_codes];
void BytecodeHistogram::reset() {
int i = Bytecodes::number_of_codes;
while (i-- > 0) _counters[i] = 0;
}
void BytecodeHistogram::print(float cutoff) {
ResourceMark rm;
GrowableArray<HistoEntry*>* profile = sorted_array(_counters, Bytecodes::number_of_codes);
// print profile
int tot = total_count(profile);
int abs_sum = 0;
tty->cr(); //0123456789012345678901234567890123456789012345678901234567890123456789
tty->print_cr("Histogram of %d executed bytecodes:", tot);
tty->cr();
tty->print_cr(" absolute relative code name");
tty->print_cr("----------------------------------------------------------------------");
int i = profile->length();
while (i-- > 0) {
HistoEntry* e = profile->at(i);
int abs = e->count();
float rel = abs * 100.0F / tot;
if (cutoff <= rel) {
tty->print_cr("%10d %7.2f%% %02x %s", abs, rel, e->index(), name_for(e->index()));
abs_sum += abs;
}
}
tty->print_cr("----------------------------------------------------------------------");
float rel_sum = abs_sum * 100.0F / tot;
tty->print_cr("%10d %7.2f%% (cutoff = %.2f%%)", abs_sum, rel_sum, cutoff);
tty->cr();
}
// Implementation of BytecodePairHistogram
int BytecodePairHistogram::_index;
int BytecodePairHistogram::_counters[BytecodePairHistogram::number_of_pairs];
void BytecodePairHistogram::reset() {
_index = Bytecodes::_nop << log2_number_of_codes;
int i = number_of_pairs;
while (i-- > 0) _counters[i] = 0;
}
void BytecodePairHistogram::print(float cutoff) {
ResourceMark rm;
GrowableArray<HistoEntry*>* profile = sorted_array(_counters, number_of_pairs);
// print profile
int tot = total_count(profile);
int abs_sum = 0;
tty->cr(); //0123456789012345678901234567890123456789012345678901234567890123456789
tty->print_cr("Histogram of %d executed bytecode pairs:", tot);
tty->cr();
tty->print_cr(" absolute relative codes 1st bytecode 2nd bytecode");
tty->print_cr("----------------------------------------------------------------------");
int i = profile->length();
while (i-- > 0) {
HistoEntry* e = profile->at(i);
int abs = e->count();
float rel = abs * 100.0F / tot;
if (cutoff <= rel) {
int c1 = e->index() % number_of_codes;
int c2 = e->index() / number_of_codes;
tty->print_cr("%10d %6.3f%% %02x %02x %-19s %s", abs, rel, c1, c2, name_for(c1), name_for(c2));
abs_sum += abs;
}
}
tty->print_cr("----------------------------------------------------------------------");
float rel_sum = abs_sum * 100.0F / tot;
tty->print_cr("%10d %6.3f%% (cutoff = %.3f%%)", abs_sum, rel_sum, cutoff);
tty->cr();
}
#endif

View file

@ -0,0 +1,92 @@
/*
* Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// BytecodeCounter counts the number of bytecodes executed
class BytecodeCounter: AllStatic {
private:
NOT_PRODUCT(static int _counter_value;)
NOT_PRODUCT(static jlong _reset_time;)
friend class TemplateInterpreterGenerator;
friend class BytecodeInterpreter;
public:
// Initialization
static void reset() PRODUCT_RETURN;
// Counter info (all info since last reset)
static int counter_value() PRODUCT_RETURN0 NOT_PRODUCT({ return _counter_value; });
static double elapsed_time() PRODUCT_RETURN0; // in seconds
static double frequency() PRODUCT_RETURN0; // bytecodes/seconds
// Counter printing
static void print() PRODUCT_RETURN;
};
// BytecodeHistogram collects number of executions of bytecodes
class BytecodeHistogram: AllStatic {
private:
NOT_PRODUCT(static int _counters[Bytecodes::number_of_codes];) // a counter for each bytecode
friend class TemplateInterpreterGenerator;
friend class InterpreterGenerator;
friend class BytecodeInterpreter;
public:
// Initialization
static void reset() PRODUCT_RETURN; // reset counters
// Profile printing
static void print(float cutoff = 0.01F) PRODUCT_RETURN; // cutoff in percent
};
// BytecodePairHistogram collects number of executions of bytecode pairs.
// A bytecode pair is any sequence of two consequtive bytecodes.
class BytecodePairHistogram: AllStatic {
public: // for SparcWorks
enum Constants {
log2_number_of_codes = 8, // use a power of 2 for faster addressing
number_of_codes = 1 << log2_number_of_codes, // must be no less than Bytecodes::number_of_codes
number_of_pairs = number_of_codes * number_of_codes
};
private:
NOT_PRODUCT(static int _index;) // new bytecode is shifted in - used to index into _counters
NOT_PRODUCT(static int _counters[number_of_pairs];) // a counter for each pair
friend class TemplateInterpreterGenerator;
friend class InterpreterGenerator;
public:
// Initialization
static void reset() PRODUCT_RETURN; // reset counters
// Profile printing
static void print(float cutoff = 0.01F) PRODUCT_RETURN; // cutoff in percent
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,572 @@
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
#ifdef CC_INTERP
// CVM definitions find hotspot equivalents...
union VMJavaVal64 {
jlong l;
jdouble d;
uint32_t v[2];
};
typedef class BytecodeInterpreter* interpreterState;
struct call_message {
class methodOopDesc* _callee; /* method to call during call_method request */
address _callee_entry_point; /* address to jump to for call_method request */
int _bcp_advance; /* size of the invoke bytecode operation */
};
struct osr_message {
address _osr_buf; /* the osr buffer */
address _osr_entry; /* the entry to the osr method */
};
struct osr_result {
nmethod* nm; /* osr nmethod */
address return_addr; /* osr blob return address */
};
// Result returned to frame manager
union frame_manager_message {
call_message _to_call; /* describes callee */
Bytecodes::Code _return_kind; /* i_return, a_return, ... */
osr_message _osr; /* describes the osr */
osr_result _osr_result; /* result of OSR request */
};
class BytecodeInterpreter : StackObj {
friend class SharedRuntime;
friend class AbstractInterpreterGenerator;
friend class CppInterpreterGenerator;
friend class InterpreterGenerator;
friend class InterpreterMacroAssembler;
friend class frame;
friend class SharedRuntime;
friend class VMStructs;
public:
enum messages {
no_request = 0, // unused
initialize, // Perform one time interpreter initializations (assumes all switches set)
// status message to C++ interpreter
method_entry, // initial method entry to interpreter
method_resume, // frame manager response to return_from_method request (assuming a frame to resume)
deopt_resume, // returning from a native call into a deopted frame
deopt_resume2, // deopt resume as a result of a PopFrame
got_monitors, // frame manager response to more_monitors request
rethrow_exception, // unwinding and throwing exception
// requests to frame manager from C++ interpreter
call_method, // request for new frame from interpreter, manager responds with method_entry
return_from_method, // request from interpreter to unwind, manager responds with method_continue
more_monitors, // need a new monitor
throwing_exception, // unwind stack and rethrow
popping_frame, // unwind call and retry call
do_osr // request this invocation be OSR's
};
private:
JavaThread* _thread; // the vm's java thread pointer
address _bcp; // instruction pointer
intptr_t* _locals; // local variable pointer
constantPoolCacheOop _constants; // constant pool cache
methodOop _method; // method being executed
DataLayout* _mdx; // compiler profiling data for current bytecode
intptr_t* _stack; // expression stack
messages _msg; // frame manager <-> interpreter message
frame_manager_message _result; // result to frame manager
interpreterState _prev_link; // previous interpreter state
oop _oop_temp; // mirror for interpreted native, null otherwise
intptr_t* _stack_base; // base of expression stack
intptr_t* _stack_limit; // limit of expression stack
BasicObjectLock* _monitor_base; // base of monitors on the native stack
public:
// Constructor is only used by the initialization step. All other instances are created
// by the frame manager.
BytecodeInterpreter(messages msg);
//
// Deoptimization support
//
static void layout_interpreterState(interpreterState to_fill,
frame* caller,
frame* interpreter_frame,
methodOop method,
intptr_t* locals,
intptr_t* stack,
intptr_t* stack_base,
intptr_t* monitor_base,
intptr_t* frame_bottom,
bool top_frame);
/*
* Generic 32-bit wide "Java slot" definition. This type occurs
* in operand stacks, Java locals, object fields, constant pools.
*/
union VMJavaVal32 {
jint i;
jfloat f;
class oopDesc* r;
uint32_t raw;
};
/*
* Generic 64-bit Java value definition
*/
union VMJavaVal64 {
jlong l;
jdouble d;
uint32_t v[2];
};
/*
* Generic 32-bit wide "Java slot" definition. This type occurs
* in Java locals, object fields, constant pools, and
* operand stacks (as a CVMStackVal32).
*/
typedef union VMSlotVal32 {
VMJavaVal32 j; /* For "Java" values */
address a; /* a return created by jsr or jsr_w */
} VMSlotVal32;
/*
* Generic 32-bit wide stack slot definition.
*/
union VMStackVal32 {
VMJavaVal32 j; /* For "Java" values */
VMSlotVal32 s; /* any value from a "slot" or locals[] */
};
inline JavaThread* thread() { return _thread; }
inline address bcp() { return _bcp; }
inline void set_bcp(address new_bcp) { _bcp = new_bcp; }
inline intptr_t* locals() { return _locals; }
inline constantPoolCacheOop constants() { return _constants; }
inline methodOop method() { return _method; }
inline DataLayout* mdx() { return _mdx; }
inline void set_mdx(DataLayout *new_mdx) { _mdx = new_mdx; }
inline messages msg() { return _msg; }
inline void set_msg(messages new_msg) { _msg = new_msg; }
inline methodOop callee() { return _result._to_call._callee; }
inline void set_callee(methodOop new_callee) { _result._to_call._callee = new_callee; }
inline void set_callee_entry_point(address entry) { _result._to_call._callee_entry_point = entry; }
inline void set_osr_buf(address buf) { _result._osr._osr_buf = buf; }
inline void set_osr_entry(address entry) { _result._osr._osr_entry = entry; }
inline int bcp_advance() { return _result._to_call._bcp_advance; }
inline void set_bcp_advance(int count) { _result._to_call._bcp_advance = count; }
inline void set_return_kind(Bytecodes::Code kind) { _result._return_kind = kind; }
inline interpreterState prev() { return _prev_link; }
inline intptr_t* stack() { return _stack; }
inline void set_stack(intptr_t* new_stack) { _stack = new_stack; }
inline intptr_t* stack_base() { return _stack_base; }
inline intptr_t* stack_limit() { return _stack_limit; }
inline BasicObjectLock* monitor_base() { return _monitor_base; }
/*
* 64-bit Arithmetic:
*
* The functions below follow the semantics of the
* ladd, land, ldiv, lmul, lor, lxor, and lrem bytecodes,
* respectively.
*/
static jlong VMlongAdd(jlong op1, jlong op2);
static jlong VMlongAnd(jlong op1, jlong op2);
static jlong VMlongDiv(jlong op1, jlong op2);
static jlong VMlongMul(jlong op1, jlong op2);
static jlong VMlongOr (jlong op1, jlong op2);
static jlong VMlongSub(jlong op1, jlong op2);
static jlong VMlongXor(jlong op1, jlong op2);
static jlong VMlongRem(jlong op1, jlong op2);
/*
* Shift:
*
* The functions below follow the semantics of the
* lushr, lshl, and lshr bytecodes, respectively.
*/
static jlong VMlongUshr(jlong op1, jint op2);
static jlong VMlongShl (jlong op1, jint op2);
static jlong VMlongShr (jlong op1, jint op2);
/*
* Unary:
*
* Return the negation of "op" (-op), according to
* the semantics of the lneg bytecode.
*/
static jlong VMlongNeg(jlong op);
/*
* Return the complement of "op" (~op)
*/
static jlong VMlongNot(jlong op);
/*
* Comparisons to 0:
*/
static int32_t VMlongLtz(jlong op); /* op <= 0 */
static int32_t VMlongGez(jlong op); /* op >= 0 */
static int32_t VMlongEqz(jlong op); /* op == 0 */
/*
* Between operands:
*/
static int32_t VMlongEq(jlong op1, jlong op2); /* op1 == op2 */
static int32_t VMlongNe(jlong op1, jlong op2); /* op1 != op2 */
static int32_t VMlongGe(jlong op1, jlong op2); /* op1 >= op2 */
static int32_t VMlongLe(jlong op1, jlong op2); /* op1 <= op2 */
static int32_t VMlongLt(jlong op1, jlong op2); /* op1 < op2 */
static int32_t VMlongGt(jlong op1, jlong op2); /* op1 > op2 */
/*
* Comparisons (returning an jint value: 0, 1, or -1)
*
* Between operands:
*
* Compare "op1" and "op2" according to the semantics of the
* "lcmp" bytecode.
*/
static int32_t VMlongCompare(jlong op1, jlong op2);
/*
* Convert int to long, according to "i2l" bytecode semantics
*/
static jlong VMint2Long(jint val);
/*
* Convert long to int, according to "l2i" bytecode semantics
*/
static jint VMlong2Int(jlong val);
/*
* Convert long to float, according to "l2f" bytecode semantics
*/
static jfloat VMlong2Float(jlong val);
/*
* Convert long to double, according to "l2d" bytecode semantics
*/
static jdouble VMlong2Double(jlong val);
/*
* Java floating-point float value manipulation.
*
* The result argument is, once again, an lvalue.
*
* Arithmetic:
*
* The functions below follow the semantics of the
* fadd, fsub, fmul, fdiv, and frem bytecodes,
* respectively.
*/
static jfloat VMfloatAdd(jfloat op1, jfloat op2);
static jfloat VMfloatSub(jfloat op1, jfloat op2);
static jfloat VMfloatMul(jfloat op1, jfloat op2);
static jfloat VMfloatDiv(jfloat op1, jfloat op2);
static jfloat VMfloatRem(jfloat op1, jfloat op2);
/*
* Unary:
*
* Return the negation of "op" (-op), according to
* the semantics of the fneg bytecode.
*/
static jfloat VMfloatNeg(jfloat op);
/*
* Comparisons (returning an int value: 0, 1, or -1)
*
* Between operands:
*
* Compare "op1" and "op2" according to the semantics of the
* "fcmpl" (direction is -1) or "fcmpg" (direction is 1) bytecodes.
*/
static int32_t VMfloatCompare(jfloat op1, jfloat op2,
int32_t direction);
/*
* Conversion:
*/
/*
* Convert float to double, according to "f2d" bytecode semantics
*/
static jdouble VMfloat2Double(jfloat op);
/*
******************************************
* Java double floating-point manipulation.
******************************************
*
* The result argument is, once again, an lvalue.
*
* Conversions:
*/
/*
* Convert double to int, according to "d2i" bytecode semantics
*/
static jint VMdouble2Int(jdouble val);
/*
* Convert double to float, according to "d2f" bytecode semantics
*/
static jfloat VMdouble2Float(jdouble val);
/*
* Convert int to double, according to "i2d" bytecode semantics
*/
static jdouble VMint2Double(jint val);
/*
* Arithmetic:
*
* The functions below follow the semantics of the
* dadd, dsub, ddiv, dmul, and drem bytecodes, respectively.
*/
static jdouble VMdoubleAdd(jdouble op1, jdouble op2);
static jdouble VMdoubleSub(jdouble op1, jdouble op2);
static jdouble VMdoubleDiv(jdouble op1, jdouble op2);
static jdouble VMdoubleMul(jdouble op1, jdouble op2);
static jdouble VMdoubleRem(jdouble op1, jdouble op2);
/*
* Unary:
*
* Return the negation of "op" (-op), according to
* the semantics of the dneg bytecode.
*/
static jdouble VMdoubleNeg(jdouble op);
/*
* Comparisons (returning an int32_t value: 0, 1, or -1)
*
* Between operands:
*
* Compare "op1" and "op2" according to the semantics of the
* "dcmpl" (direction is -1) or "dcmpg" (direction is 1) bytecodes.
*/
static int32_t VMdoubleCompare(jdouble op1, jdouble op2, int32_t direction);
/*
* Copy two typeless 32-bit words from one location to another.
* This is semantically equivalent to:
*
* to[0] = from[0];
* to[1] = from[1];
*
* but this interface is provided for those platforms that could
* optimize this into a single 64-bit transfer.
*/
static void VMmemCopy64(uint32_t to[2], const uint32_t from[2]);
// Arithmetic operations
/*
* Java arithmetic methods.
* The functions below follow the semantics of the
* iadd, isub, imul, idiv, irem, iand, ior, ixor,
* and ineg bytecodes, respectively.
*/
static jint VMintAdd(jint op1, jint op2);
static jint VMintSub(jint op1, jint op2);
static jint VMintMul(jint op1, jint op2);
static jint VMintDiv(jint op1, jint op2);
static jint VMintRem(jint op1, jint op2);
static jint VMintAnd(jint op1, jint op2);
static jint VMintOr (jint op1, jint op2);
static jint VMintXor(jint op1, jint op2);
/*
* Shift Operation:
* The functions below follow the semantics of the
* iushr, ishl, and ishr bytecodes, respectively.
*/
static jint VMintUshr(jint op, jint num);
static jint VMintShl (jint op, jint num);
static jint VMintShr (jint op, jint num);
/*
* Unary Operation:
*
* Return the negation of "op" (-op), according to
* the semantics of the ineg bytecode.
*/
static jint VMintNeg(jint op);
/*
* Int Conversions:
*/
/*
* Convert int to float, according to "i2f" bytecode semantics
*/
static jfloat VMint2Float(jint val);
/*
* Convert int to byte, according to "i2b" bytecode semantics
*/
static jbyte VMint2Byte(jint val);
/*
* Convert int to char, according to "i2c" bytecode semantics
*/
static jchar VMint2Char(jint val);
/*
* Convert int to short, according to "i2s" bytecode semantics
*/
static jshort VMint2Short(jint val);
/*=========================================================================
* Bytecode interpreter operations
*=======================================================================*/
static void dup(intptr_t *tos);
static void dup2(intptr_t *tos);
static void dup_x1(intptr_t *tos); /* insert top word two down */
static void dup_x2(intptr_t *tos); /* insert top word three down */
static void dup2_x1(intptr_t *tos); /* insert top 2 slots three down */
static void dup2_x2(intptr_t *tos); /* insert top 2 slots four down */
static void swap(intptr_t *tos); /* swap top two elements */
// umm don't like this method modifies its object
// The Interpreter used when
static void run(interpreterState istate);
// The interpreter used if JVMTI needs interpreter events
static void runWithChecks(interpreterState istate);
static void End_Of_Interpreter(void);
// Inline static functions for Java Stack and Local manipulation
static address stack_slot(intptr_t *tos, int offset);
static jint stack_int(intptr_t *tos, int offset);
static jfloat stack_float(intptr_t *tos, int offset);
static oop stack_object(intptr_t *tos, int offset);
static jdouble stack_double(intptr_t *tos, int offset);
static jlong stack_long(intptr_t *tos, int offset);
static void tag_stack(intptr_t *tos, frame::Tag tag, int offset);
// only used for value types
static void set_stack_slot(intptr_t *tos, address value, int offset);
static void set_stack_int(intptr_t *tos, int value, int offset);
static void set_stack_float(intptr_t *tos, jfloat value, int offset);
static void set_stack_object(intptr_t *tos, oop value, int offset);
// needs to be platform dep for the 32 bit platforms.
static void set_stack_double(intptr_t *tos, jdouble value, int offset);
static void set_stack_long(intptr_t *tos, jlong value, int offset);
static void set_stack_double_from_addr(intptr_t *tos, address addr, int offset);
static void set_stack_long_from_addr(intptr_t *tos, address addr, int offset);
// Locals
static address locals_slot(intptr_t* locals, int offset);
static jint locals_int(intptr_t* locals, int offset);
static jfloat locals_float(intptr_t* locals, int offset);
static oop locals_object(intptr_t* locals, int offset);
static jdouble locals_double(intptr_t* locals, int offset);
static jlong locals_long(intptr_t* locals, int offset);
static address locals_long_at(intptr_t* locals, int offset);
static address locals_double_at(intptr_t* locals, int offset);
static void tag_locals(intptr_t *locals, frame::Tag tag, int offset);
static void set_locals_slot(intptr_t *locals, address value, int offset);
static void set_locals_int(intptr_t *locals, jint value, int offset);
static void set_locals_float(intptr_t *locals, jfloat value, int offset);
static void set_locals_object(intptr_t *locals, oop value, int offset);
static void set_locals_double(intptr_t *locals, jdouble value, int offset);
static void set_locals_long(intptr_t *locals, jlong value, int offset);
static void set_locals_double_from_addr(intptr_t *locals,
address addr, int offset);
static void set_locals_long_from_addr(intptr_t *locals,
address addr, int offset);
static void astore(intptr_t* topOfStack, int stack_offset,
intptr_t* locals, int locals_offset);
// Support for dup and swap
static void copy_stack_slot(intptr_t *tos, int from_offset, int to_offset);
#ifndef PRODUCT
static void verify_locals_tag(intptr_t *locals, frame::Tag tag, int offset);
static void verify_stack_tag(intptr_t *tos, frame::Tag tag, int offset);
static const char* C_msg(BytecodeInterpreter::messages msg);
void print();
#endif // PRODUCT
// Platform fields/methods
# include "incls/_bytecodeInterpreter_pd.hpp.incl"
}; // BytecodeInterpreter
#endif // CC_INTERP

View file

@ -0,0 +1,44 @@
/*
* Copyright 2002 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// This file holds platform-independant bodies of inline functions for the C++ based interpreter
#ifdef CC_INTERP
#ifdef ASSERT
extern "C" { typedef void (*verify_oop_fn_t)(oop, const char *);};
#define VERIFY_OOP(o) \
/*{ verify_oop_fn_t verify_oop_entry = \
*StubRoutines::verify_oop_subroutine_entry_address(); \
if (verify_oop_entry) { \
(*verify_oop_entry)((o), "Not an oop!"); \
} \
}*/
#else
#define VERIFY_OOP(o)
#endif
// Platform dependent data manipulation
# include "incls/_bytecodeInterpreter_pd.inline.hpp.incl"
#endif // CC_INTERP

View file

@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!--
Copyright 2006 Sun Microsystems, Inc. All rights reserved.
SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-->
<!DOCTYPE processcode [
<!ELEMENT processcode ANY>
]>
<processcode>
</processcode>

View file

@ -0,0 +1,21 @@
<?xml version="1.0"?>
<!--
Copyright 2006 Sun Microsystems, Inc. All rights reserved.
SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="processcode">
<xsl:text>
#define VM_JVMTI
#include "bytecodeInterpreter.cpp"
</xsl:text>
<xsl:text disable-output-escaping = "yes">
</xsl:text>
<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,48 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* 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/_bytecodeStream.cpp.incl"
Bytecodes::Code RawBytecodeStream::raw_next_special(Bytecodes::Code code) {
assert(!is_last_bytecode(), "should have been checked");
// set next bytecode position
address bcp = RawBytecodeStream::bcp();
int l = Bytecodes::raw_special_length_at(bcp);
if (l <= 0 || (_bci + l) > _end_bci) {
code = Bytecodes::_illegal;
} else {
_next_bci += l;
assert(_bci < _next_bci, "length must be > 0");
// set attributes
_is_wide = false;
// check for special (uncommon) cases
if (code == Bytecodes::_wide) {
code = (Bytecodes::Code)bcp[1];
_is_wide = true;
}
}
_code = code;
return code;
}

View file

@ -0,0 +1,172 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// A BytecodeStream is used for fast iteration over the bytecodes
// of a methodOop.
//
// Usage:
//
// BytecodeStream s(method);
// Bytecodes::Code c;
// while ((c = s.next()) >= 0) {
// ...
// }
//
// A RawBytecodeStream is a simple version of BytecodeStream.
// It is used ONLY when we know the bytecodes haven't been rewritten
// yet, such as in the rewriter or the verifier. Currently only the
// verifier uses this class.
class RawBytecodeStream: StackObj {
protected:
// stream buffer
methodHandle _method; // read from method directly
// reading position
int _bci; // bci if current bytecode
int _next_bci; // bci of next bytecode
int _end_bci; // bci after the current iteration interval
// last bytecode read
Bytecodes::Code _code;
bool _is_wide;
public:
// Construction
RawBytecodeStream(methodHandle method) : _method(method) {
set_interval(0, _method->code_size());
}
// Iteration control
void set_interval(int beg_bci, int end_bci) {
// iterate over the interval [beg_bci, end_bci)
assert(0 <= beg_bci && beg_bci <= method()->code_size(), "illegal beg_bci");
assert(0 <= end_bci && end_bci <= method()->code_size(), "illegal end_bci");
// setup of iteration pointers
_bci = beg_bci;
_next_bci = beg_bci;
_end_bci = end_bci;
}
void set_start (int beg_bci) {
set_interval(beg_bci, _method->code_size());
}
// Iteration
// Use raw_next() rather than next() for faster method reference
Bytecodes::Code raw_next() {
Bytecodes::Code code;
// set reading position
_bci = _next_bci;
assert(!is_last_bytecode(), "caller should check is_last_bytecode()");
address bcp = RawBytecodeStream::bcp();
code = Bytecodes::code_or_bp_at(bcp);
// set next bytecode position
int l = Bytecodes::length_for(code);
if (l > 0 && (_bci + l) <= _end_bci) {
assert(code != Bytecodes::_wide && code != Bytecodes::_tableswitch
&& code != Bytecodes::_lookupswitch, "can't be special bytecode");
_is_wide = false;
_next_bci += l;
_code = code;
return code;
} else if (code == Bytecodes::_wide && _bci + 1 >= _end_bci) {
return Bytecodes::_illegal;
} else {
return raw_next_special(code);
}
}
Bytecodes::Code raw_next_special(Bytecodes::Code code);
// Stream attributes
methodHandle method() const { return _method; }
int bci() const { return _bci; }
int next_bci() const { return _next_bci; }
int end_bci() const { return _end_bci; }
Bytecodes::Code code() const { return _code; }
bool is_wide() const { return _is_wide; }
bool is_last_bytecode() const { return _next_bci >= _end_bci; }
address bcp() const { return method()->code_base() + _bci; }
address next_bcp() { return method()->code_base() + _next_bci; }
// State changes
void set_next_bci(int bci) { assert(0 <= bci && bci <= method()->code_size(), "illegal bci"); _next_bci = bci; }
// Bytecode-specific attributes
int dest() const { return bci() + (short)Bytes::get_Java_u2(bcp() + 1); }
int dest_w() const { return bci() + (int )Bytes::get_Java_u4(bcp() + 1); }
// Unsigned indices, widening
int get_index() const { return (is_wide()) ? Bytes::get_Java_u2(bcp() + 2) : bcp()[1]; }
int get_index_big() const { return (int)Bytes::get_Java_u2(bcp() + 1); }
};
// In BytecodeStream, non-java bytecodes will be translated into the
// corresponding java bytecodes.
class BytecodeStream: public RawBytecodeStream {
public:
// Construction
BytecodeStream(methodHandle method) : RawBytecodeStream(method) { }
// Iteration
Bytecodes::Code next() {
Bytecodes::Code code;
// set reading position
_bci = _next_bci;
if (is_last_bytecode()) {
// indicate end of bytecode stream
code = Bytecodes::_illegal;
} else {
// get bytecode
address bcp = BytecodeStream::bcp();
code = Bytecodes::java_code_at(bcp);
// set next bytecode position
//
// note that we cannot advance before having the
// tty bytecode otherwise the stepping is wrong!
// (carefull: length_for(...) must be used first!)
int l = Bytecodes::length_for(code);
if (l == 0) l = Bytecodes::length_at(bcp);
_next_bci += l;
assert(_bci < _next_bci, "length must be > 0");
// set attributes
_is_wide = false;
// check for special (uncommon) cases
if (code == Bytecodes::_wide) {
code = (Bytecodes::Code)bcp[1];
_is_wide = true;
}
assert(Bytecodes::is_java_code(code), "sanity check");
}
_code = code;
return _code;
}
bool is_active_breakpoint() const { return Bytecodes::is_active_breakpoint_at(bcp()); }
};

View file

@ -0,0 +1,419 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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/_bytecodeTracer.cpp.incl"
#ifndef PRODUCT
// Standard closure for BytecodeTracer: prints the current bytecode
// and its attributes using bytecode-specific information.
class BytecodePrinter: public BytecodeClosure {
private:
// %%% This field is not GC-ed, and so can contain garbage
// between critical sections. Use only pointer-comparison
// operations on the pointer, except within a critical section.
// (Also, ensure that occasional false positives are benign.)
methodOop _current_method;
bool _is_wide;
address _next_pc; // current decoding position
void align() { _next_pc = (address)round_to((intptr_t)_next_pc, sizeof(jint)); }
int get_byte() { return *(jbyte*) _next_pc++; } // signed
short get_short() { short i=Bytes::get_Java_u2(_next_pc); _next_pc+=2; return i; }
int get_int() { int i=Bytes::get_Java_u4(_next_pc); _next_pc+=4; return i; }
int get_index() { return *(address)_next_pc++; }
int get_big_index() { int i=Bytes::get_Java_u2(_next_pc); _next_pc+=2; return i; }
int get_index_special() { return (is_wide()) ? get_big_index() : get_index(); }
methodOop method() { return _current_method; }
bool is_wide() { return _is_wide; }
void print_constant(int i, outputStream* st = tty);
void print_attributes(Bytecodes::Code code, int bci, outputStream* st = tty);
void bytecode_epilog(int bci, outputStream* st = tty);
public:
BytecodePrinter() {
_is_wide = false;
}
// This method is called while executing the raw bytecodes, so none of
// the adjustments that BytecodeStream performs applies.
void trace(methodHandle method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) {
ResourceMark rm;
if (_current_method != method()) {
// Note 1: This code will not work as expected with true MT/MP.
// Need an explicit lock or a different solution.
// It is possible for this block to be skipped, if a garbage
// _current_method pointer happens to have the same bits as
// the incoming method. We could lose a line of trace output.
// This is acceptable in a debug-only feature.
st->cr();
st->print("[%d] ", (int) Thread::current()->osthread()->thread_id());
method->print_name(st);
st->cr();
_current_method = method();
}
Bytecodes::Code code;
if (is_wide()) {
// bcp wasn't advanced if previous bytecode was _wide.
code = Bytecodes::code_at(bcp+1);
} else {
code = Bytecodes::code_at(bcp);
}
int bci = bcp - method->code_base();
st->print("[%d] ", (int) Thread::current()->osthread()->thread_id());
if (Verbose) {
st->print("%8d %4d " INTPTR_FORMAT " " INTPTR_FORMAT " %s",
BytecodeCounter::counter_value(), bci, tos, tos2, Bytecodes::name(code));
} else {
st->print("%8d %4d %s",
BytecodeCounter::counter_value(), bci, Bytecodes::name(code));
}
_next_pc = is_wide() ? bcp+2 : bcp+1;
print_attributes(code, bci);
// Set is_wide for the next one, since the caller of this doesn't skip
// the next bytecode.
_is_wide = (code == Bytecodes::_wide);
}
// Used for methodOop::print_codes(). The input bcp comes from
// BytecodeStream, which will skip wide bytecodes.
void trace(methodHandle method, address bcp, outputStream* st) {
_current_method = method();
ResourceMark rm;
Bytecodes::Code code = Bytecodes::code_at(bcp);
// Set is_wide
_is_wide = (code == Bytecodes::_wide);
if (is_wide()) {
code = Bytecodes::code_at(bcp+1);
}
int bci = bcp - method->code_base();
// Print bytecode index and name
if (is_wide()) {
st->print("%d %s_w", bci, Bytecodes::name(code));
} else {
st->print("%d %s", bci, Bytecodes::name(code));
}
_next_pc = is_wide() ? bcp+2 : bcp+1;
print_attributes(code, bci, st);
bytecode_epilog(bci, st);
}
};
// Implementation of BytecodeTracer
// %%% This set_closure thing seems overly general, given that
// nobody uses it. Also, if BytecodePrinter weren't hidden
// then methodOop could use instances of it directly and it
// would be easier to remove races on _current_method and bcp.
// Since this is not product functionality, we can defer cleanup.
BytecodeClosure* BytecodeTracer::_closure = NULL;
static BytecodePrinter std_closure;
BytecodeClosure* BytecodeTracer::std_closure() {
return &::std_closure;
}
void BytecodeTracer::trace(methodHandle method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) {
if (TraceBytecodes && BytecodeCounter::counter_value() >= TraceBytecodesAt) {
ttyLocker ttyl; // 5065316: keep the following output coherent
// The ttyLocker also prevents races between two threads
// trying to use the single instance of BytecodePrinter.
// Using the ttyLocker prevents the system from coming to
// a safepoint within this code, which is sensitive to methodOop
// movement.
//
// There used to be a leaf mutex here, but the ttyLocker will
// work just as well, as long as the printing operations never block.
//
// We put the locker on the static trace method, not the
// virtual one, because the clients of this module go through
// the static method.
_closure->trace(method, bcp, tos, tos2, st);
}
}
void BytecodeTracer::trace(methodHandle method, address bcp, outputStream* st) {
ttyLocker ttyl; // 5065316: keep the following output coherent
_closure->trace(method, bcp, st);
}
void print_oop(oop value, outputStream* st) {
if (value == NULL) {
st->print_cr(" NULL");
} else {
EXCEPTION_MARK;
Handle h_value (THREAD, value);
symbolHandle sym = java_lang_String::as_symbol(h_value, CATCH);
if (sym->utf8_length() > 32) {
st->print_cr(" ....");
} else {
sym->print_on(st); st->cr();
}
}
}
void BytecodePrinter::print_constant(int i, outputStream* st) {
constantPoolOop constants = method()->constants();
constantTag tag = constants->tag_at(i);
if (tag.is_int()) {
st->print_cr(" " INT32_FORMAT, constants->int_at(i));
} else if (tag.is_long()) {
st->print_cr(" " INT64_FORMAT, constants->long_at(i));
} else if (tag.is_float()) {
st->print_cr(" %f", constants->float_at(i));
} else if (tag.is_double()) {
st->print_cr(" %f", constants->double_at(i));
} else if (tag.is_string()) {
oop string = constants->resolved_string_at(i);
print_oop(string, st);
} else if (tag.is_unresolved_string()) {
st->print_cr(" <unresolved string at %d>", i);
} else if (tag.is_klass()) {
st->print_cr(" %s", constants->resolved_klass_at(i)->klass_part()->external_name());
} else if (tag.is_unresolved_klass()) {
st->print_cr(" <unresolved klass at %d>", i);
} else ShouldNotReachHere();
}
void BytecodePrinter::print_attributes(Bytecodes::Code code, int bci, outputStream* st) {
// Show attributes of pre-rewritten codes
code = Bytecodes::java_code(code);
// If the code doesn't have any fields there's nothing to print.
// note this is ==1 because the tableswitch and lookupswitch are
// zero size (for some reason) and we want to print stuff out for them.
if (Bytecodes::length_for(code) == 1) {
st->cr();
return;
}
switch(code) {
// Java specific bytecodes only matter.
case Bytecodes::_bipush:
st->print_cr(" " INT32_FORMAT, get_byte());
break;
case Bytecodes::_sipush:
st->print_cr(" " INT32_FORMAT, get_short());
break;
case Bytecodes::_ldc:
print_constant(get_index(), st);
break;
case Bytecodes::_ldc_w:
case Bytecodes::_ldc2_w:
print_constant(get_big_index(), st);
break;
case Bytecodes::_iload:
case Bytecodes::_lload:
case Bytecodes::_fload:
case Bytecodes::_dload:
case Bytecodes::_aload:
case Bytecodes::_istore:
case Bytecodes::_lstore:
case Bytecodes::_fstore:
case Bytecodes::_dstore:
case Bytecodes::_astore:
st->print_cr(" #%d", get_index_special());
break;
case Bytecodes::_iinc:
{ int index = get_index_special();
jint offset = is_wide() ? get_short(): get_byte();
st->print_cr(" #%d " INT32_FORMAT, index, offset);
}
break;
case Bytecodes::_newarray: {
BasicType atype = (BasicType)get_index();
const char* str = type2name(atype);
if (str == NULL || atype == T_OBJECT || atype == T_ARRAY) {
assert(false, "Unidentified basic type");
}
st->print_cr(" %s", str);
}
break;
case Bytecodes::_anewarray: {
int klass_index = get_big_index();
constantPoolOop constants = method()->constants();
symbolOop name = constants->klass_name_at(klass_index);
st->print_cr(" %s ", name->as_C_string());
}
break;
case Bytecodes::_multianewarray: {
int klass_index = get_big_index();
int nof_dims = get_index();
constantPoolOop constants = method()->constants();
symbolOop name = constants->klass_name_at(klass_index);
st->print_cr(" %s %d", name->as_C_string(), nof_dims);
}
break;
case Bytecodes::_ifeq:
case Bytecodes::_ifnull:
case Bytecodes::_iflt:
case Bytecodes::_ifle:
case Bytecodes::_ifne:
case Bytecodes::_ifnonnull:
case Bytecodes::_ifgt:
case Bytecodes::_ifge:
case Bytecodes::_if_icmpeq:
case Bytecodes::_if_icmpne:
case Bytecodes::_if_icmplt:
case Bytecodes::_if_icmpgt:
case Bytecodes::_if_icmple:
case Bytecodes::_if_icmpge:
case Bytecodes::_if_acmpeq:
case Bytecodes::_if_acmpne:
case Bytecodes::_goto:
case Bytecodes::_jsr:
st->print_cr(" %d", bci + get_short());
break;
case Bytecodes::_goto_w:
case Bytecodes::_jsr_w:
st->print_cr(" %d", bci + get_int());
break;
case Bytecodes::_ret: st->print_cr(" %d", get_index_special()); break;
case Bytecodes::_tableswitch:
{ align();
int default_dest = bci + get_int();
int lo = get_int();
int hi = get_int();
int len = hi - lo + 1;
jint* dest = NEW_RESOURCE_ARRAY(jint, len);
for (int i = 0; i < len; i++) {
dest[i] = bci + get_int();
}
st->print(" %d " INT32_FORMAT " " INT32_FORMAT " ",
default_dest, lo, hi);
int first = true;
for (int ll = lo; ll <= hi; ll++, first = false) {
int idx = ll - lo;
const char *format = first ? " %d:" INT32_FORMAT " (delta: %d)" :
", %d:" INT32_FORMAT " (delta: %d)";
st->print(format, ll, dest[idx], dest[idx]-bci);
}
st->cr();
}
break;
case Bytecodes::_lookupswitch:
{ align();
int default_dest = bci + get_int();
int len = get_int();
jint* key = NEW_RESOURCE_ARRAY(jint, len);
jint* dest = NEW_RESOURCE_ARRAY(jint, len);
for (int i = 0; i < len; i++) {
key [i] = get_int();
dest[i] = bci + get_int();
};
st->print(" %d %d ", default_dest, len);
bool first = true;
for (int ll = 0; ll < len; ll++, first = false) {
const char *format = first ? " " INT32_FORMAT ":" INT32_FORMAT :
", " INT32_FORMAT ":" INT32_FORMAT ;
st->print(format, key[ll], dest[ll]);
}
st->cr();
}
break;
case Bytecodes::_putstatic:
case Bytecodes::_getstatic:
case Bytecodes::_putfield:
case Bytecodes::_getfield: {
int i = get_big_index();
constantPoolOop constants = method()->constants();
symbolOop field = constants->name_ref_at(i);
st->print_cr(" %d <%s>", i, field->as_C_string());
}
break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
{ int i = get_big_index();
constantPoolOop constants = method()->constants();
symbolOop name = constants->name_ref_at(i);
symbolOop signature = constants->signature_ref_at(i);
st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string());
}
break;
case Bytecodes::_invokeinterface:
{ int i = get_big_index();
int n = get_index();
get_index();
constantPoolOop constants = method()->constants();
symbolOop name = constants->name_ref_at(i);
symbolOop signature = constants->signature_ref_at(i);
st->print_cr(" %d <%s> <%s> %d", i, name->as_C_string(), signature->as_C_string(), n);
}
break;
case Bytecodes::_new:
case Bytecodes::_checkcast:
case Bytecodes::_instanceof:
{ int i = get_big_index();
constantPoolOop constants = method()->constants();
symbolOop name = constants->klass_name_at(i);
st->print_cr(" %d <%s>", i, name->as_C_string());
}
break;
case Bytecodes::_wide:
// length is zero not one, but printed with no more info.
break;
default:
ShouldNotReachHere();
break;
}
}
void BytecodePrinter::bytecode_epilog(int bci, outputStream* st) {
methodDataOop mdo = method()->method_data();
if (mdo != NULL) {
ProfileData* data = mdo->bci_to_data(bci);
if (data != NULL) {
st->print(" %d", mdo->dp_to_di(data->dp()));
st->fill_to(6);
data->print_data_on(st);
}
}
}
#endif // PRODUCT

View file

@ -0,0 +1,58 @@
/*
* Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// The BytecodeTracer is a helper class used by the interpreter for run-time
// bytecode tracing. If bytecode tracing is turned on, trace() will be called
// for each bytecode.
//
// By specialising the BytecodeClosure, all kinds of bytecode traces can
// be done.
#ifndef PRODUCT
// class BytecodeTracer is only used by TraceBytecodes option
class BytecodeClosure;
class BytecodeTracer: AllStatic {
private:
static BytecodeClosure* _closure;
public:
static BytecodeClosure* std_closure(); // a printing closure
static BytecodeClosure* closure() { return _closure; }
static void set_closure(BytecodeClosure* closure) { _closure = closure; }
static void trace(methodHandle method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st = tty);
static void trace(methodHandle method, address bcp, outputStream* st = tty);
};
// For each bytecode, a BytecodeClosure's trace() routine will be called.
class BytecodeClosure {
public:
virtual void trace(methodHandle method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) = 0;
virtual void trace(methodHandle method, address bcp, outputStream* st) = 0;
};
#endif // !PRODUCT

View file

@ -0,0 +1,435 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* 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/_bytecodes.cpp.incl"
// Windows AMD64 Compiler Hangs compiling this file
// unless optimization is off
#ifdef _M_AMD64
#pragma optimize ("", off)
#endif
bool Bytecodes::_is_initialized = false;
const char* Bytecodes::_name [Bytecodes::number_of_codes];
const char* Bytecodes::_format [Bytecodes::number_of_codes];
const char* Bytecodes::_wide_format [Bytecodes::number_of_codes];
BasicType Bytecodes::_result_type [Bytecodes::number_of_codes];
s_char Bytecodes::_depth [Bytecodes::number_of_codes];
u_char Bytecodes::_length [Bytecodes::number_of_codes];
bool Bytecodes::_can_trap [Bytecodes::number_of_codes];
Bytecodes::Code Bytecodes::_java_code [Bytecodes::number_of_codes];
bool Bytecodes::_can_rewrite [Bytecodes::number_of_codes];
Bytecodes::Code Bytecodes::code_at(methodOop method, int bci) {
return code_at(method->bcp_from(bci), method);
}
Bytecodes::Code Bytecodes::non_breakpoint_code_at(address bcp, methodOop method) {
if (method == NULL) method = methodOopDesc::method_from_bcp(bcp);
return method->orig_bytecode_at(method->bci_from(bcp));
}
int Bytecodes::special_length_at(address bcp) {
Code code = code_at(bcp);
switch (code) {
case _wide:
return wide_length_for(cast(*(bcp + 1)));
case _tableswitch:
{ address aligned_bcp = (address)round_to((intptr_t)bcp + 1, jintSize);
jlong lo = (jint)Bytes::get_Java_u4(aligned_bcp + 1*jintSize);
jlong hi = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize);
jlong len = (aligned_bcp - bcp) + (3 + hi - lo + 1)*jintSize;
// only return len if it can be represented as a positive int;
// return -1 otherwise
return (len > 0 && len == (int)len) ? len : -1;
}
case _lookupswitch: // fall through
case _fast_binaryswitch: // fall through
case _fast_linearswitch:
{ address aligned_bcp = (address)round_to((intptr_t)bcp + 1, jintSize);
jlong npairs = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize);
jlong len = (aligned_bcp - bcp) + (2 + 2*npairs)*jintSize;
// only return len if it can be represented as a positive int;
// return -1 otherwise
return (len > 0 && len == (int)len) ? len : -1;
}
}
return 0;
}
// At a breakpoint instruction, this returns the breakpoint's length,
// otherwise, it's the same as special_length_at(). This is used by
// the RawByteCodeStream, which wants to see the actual bytecode
// values (including breakpoint). RawByteCodeStream is used by the
// verifier when reading in bytecode to verify. Other mechanisms that
// run at runtime (such as generateOopMaps) need to iterate over the code
// and don't expect to see breakpoints: they want to see the instruction
// which was replaces so that they can get the correct length and find
// the next bytecode.
int Bytecodes::raw_special_length_at(address bcp) {
Code code = code_or_bp_at(bcp);
if (code == _breakpoint) {
return 1;
} else {
return special_length_at(bcp);
}
}
void Bytecodes::def(Code code, const char* name, const char* format, const char* wide_format, BasicType result_type, int depth, bool can_trap) {
def(code, name, format, wide_format, result_type, depth, can_trap, code);
}
void Bytecodes::def(Code code, const char* name, const char* format, const char* wide_format, BasicType result_type, int depth, bool can_trap, Code java_code) {
assert(wide_format == NULL || format != NULL, "short form must exist if there's a wide form");
_name [code] = name;
_format [code] = format;
_wide_format [code] = wide_format;
_result_type [code] = result_type;
_depth [code] = depth;
_can_trap [code] = can_trap;
_length [code] = format != NULL ? (u_char)strlen(format) : 0;
_java_code [code] = java_code;
if (java_code != code) _can_rewrite[java_code] = true;
}
// Format strings interpretation:
//
// b: bytecode
// c: signed constant, Java byte-ordering
// i: unsigned index , Java byte-ordering
// j: unsigned index , native byte-ordering
// o: branch offset , Java byte-ordering
// _: unused/ignored
// w: wide bytecode
//
// Note: Right now the format strings are used for 2 purposes:
// 1. to specify the length of the bytecode
// (= number of characters in format string)
// 2. to specify the bytecode attributes
//
// The bytecode attributes are currently used only for bytecode tracing
// (see BytecodeTracer); thus if more specific format information is
// used, one would also have to adjust the bytecode tracer.
//
// Note: For bytecodes with variable length, the format string is the empty string.
void Bytecodes::initialize() {
if (_is_initialized) return;
assert(number_of_codes <= 256, "too many bytecodes");
// initialize bytecode tables - didn't use static array initializers
// (such as {}) so we can do additional consistency checks and init-
// code is independent of actual bytecode numbering.
//
// Note 1: NULL for the format string means the bytecode doesn't exist
// in that form.
//
// Note 2: The result type is T_ILLEGAL for bytecodes where the top of stack
// type after execution is not only determined by the bytecode itself.
// Java bytecodes
// bytecode bytecode name format wide f. result tp stk traps
def(_nop , "nop" , "b" , NULL , T_VOID , 0, false);
def(_aconst_null , "aconst_null" , "b" , NULL , T_OBJECT , 1, false);
def(_iconst_m1 , "iconst_m1" , "b" , NULL , T_INT , 1, false);
def(_iconst_0 , "iconst_0" , "b" , NULL , T_INT , 1, false);
def(_iconst_1 , "iconst_1" , "b" , NULL , T_INT , 1, false);
def(_iconst_2 , "iconst_2" , "b" , NULL , T_INT , 1, false);
def(_iconst_3 , "iconst_3" , "b" , NULL , T_INT , 1, false);
def(_iconst_4 , "iconst_4" , "b" , NULL , T_INT , 1, false);
def(_iconst_5 , "iconst_5" , "b" , NULL , T_INT , 1, false);
def(_lconst_0 , "lconst_0" , "b" , NULL , T_LONG , 2, false);
def(_lconst_1 , "lconst_1" , "b" , NULL , T_LONG , 2, false);
def(_fconst_0 , "fconst_0" , "b" , NULL , T_FLOAT , 1, false);
def(_fconst_1 , "fconst_1" , "b" , NULL , T_FLOAT , 1, false);
def(_fconst_2 , "fconst_2" , "b" , NULL , T_FLOAT , 1, false);
def(_dconst_0 , "dconst_0" , "b" , NULL , T_DOUBLE , 2, false);
def(_dconst_1 , "dconst_1" , "b" , NULL , T_DOUBLE , 2, false);
def(_bipush , "bipush" , "bc" , NULL , T_INT , 1, false);
def(_sipush , "sipush" , "bcc" , NULL , T_INT , 1, false);
def(_ldc , "ldc" , "bi" , NULL , T_ILLEGAL, 1, true );
def(_ldc_w , "ldc_w" , "bii" , NULL , T_ILLEGAL, 1, true );
def(_ldc2_w , "ldc2_w" , "bii" , NULL , T_ILLEGAL, 2, true );
def(_iload , "iload" , "bi" , "wbii" , T_INT , 1, false);
def(_lload , "lload" , "bi" , "wbii" , T_LONG , 2, false);
def(_fload , "fload" , "bi" , "wbii" , T_FLOAT , 1, false);
def(_dload , "dload" , "bi" , "wbii" , T_DOUBLE , 2, false);
def(_aload , "aload" , "bi" , "wbii" , T_OBJECT , 1, false);
def(_iload_0 , "iload_0" , "b" , NULL , T_INT , 1, false);
def(_iload_1 , "iload_1" , "b" , NULL , T_INT , 1, false);
def(_iload_2 , "iload_2" , "b" , NULL , T_INT , 1, false);
def(_iload_3 , "iload_3" , "b" , NULL , T_INT , 1, false);
def(_lload_0 , "lload_0" , "b" , NULL , T_LONG , 2, false);
def(_lload_1 , "lload_1" , "b" , NULL , T_LONG , 2, false);
def(_lload_2 , "lload_2" , "b" , NULL , T_LONG , 2, false);
def(_lload_3 , "lload_3" , "b" , NULL , T_LONG , 2, false);
def(_fload_0 , "fload_0" , "b" , NULL , T_FLOAT , 1, false);
def(_fload_1 , "fload_1" , "b" , NULL , T_FLOAT , 1, false);
def(_fload_2 , "fload_2" , "b" , NULL , T_FLOAT , 1, false);
def(_fload_3 , "fload_3" , "b" , NULL , T_FLOAT , 1, false);
def(_dload_0 , "dload_0" , "b" , NULL , T_DOUBLE , 2, false);
def(_dload_1 , "dload_1" , "b" , NULL , T_DOUBLE , 2, false);
def(_dload_2 , "dload_2" , "b" , NULL , T_DOUBLE , 2, false);
def(_dload_3 , "dload_3" , "b" , NULL , T_DOUBLE , 2, false);
def(_aload_0 , "aload_0" , "b" , NULL , T_OBJECT , 1, true ); // rewriting in interpreter
def(_aload_1 , "aload_1" , "b" , NULL , T_OBJECT , 1, false);
def(_aload_2 , "aload_2" , "b" , NULL , T_OBJECT , 1, false);
def(_aload_3 , "aload_3" , "b" , NULL , T_OBJECT , 1, false);
def(_iaload , "iaload" , "b" , NULL , T_INT , -1, true );
def(_laload , "laload" , "b" , NULL , T_LONG , 0, true );
def(_faload , "faload" , "b" , NULL , T_FLOAT , -1, true );
def(_daload , "daload" , "b" , NULL , T_DOUBLE , 0, true );
def(_aaload , "aaload" , "b" , NULL , T_OBJECT , -1, true );
def(_baload , "baload" , "b" , NULL , T_INT , -1, true );
def(_caload , "caload" , "b" , NULL , T_INT , -1, true );
def(_saload , "saload" , "b" , NULL , T_INT , -1, true );
def(_istore , "istore" , "bi" , "wbii" , T_VOID , -1, false);
def(_lstore , "lstore" , "bi" , "wbii" , T_VOID , -2, false);
def(_fstore , "fstore" , "bi" , "wbii" , T_VOID , -1, false);
def(_dstore , "dstore" , "bi" , "wbii" , T_VOID , -2, false);
def(_astore , "astore" , "bi" , "wbii" , T_VOID , -1, false);
def(_istore_0 , "istore_0" , "b" , NULL , T_VOID , -1, false);
def(_istore_1 , "istore_1" , "b" , NULL , T_VOID , -1, false);
def(_istore_2 , "istore_2" , "b" , NULL , T_VOID , -1, false);
def(_istore_3 , "istore_3" , "b" , NULL , T_VOID , -1, false);
def(_lstore_0 , "lstore_0" , "b" , NULL , T_VOID , -2, false);
def(_lstore_1 , "lstore_1" , "b" , NULL , T_VOID , -2, false);
def(_lstore_2 , "lstore_2" , "b" , NULL , T_VOID , -2, false);
def(_lstore_3 , "lstore_3" , "b" , NULL , T_VOID , -2, false);
def(_fstore_0 , "fstore_0" , "b" , NULL , T_VOID , -1, false);
def(_fstore_1 , "fstore_1" , "b" , NULL , T_VOID , -1, false);
def(_fstore_2 , "fstore_2" , "b" , NULL , T_VOID , -1, false);
def(_fstore_3 , "fstore_3" , "b" , NULL , T_VOID , -1, false);
def(_dstore_0 , "dstore_0" , "b" , NULL , T_VOID , -2, false);
def(_dstore_1 , "dstore_1" , "b" , NULL , T_VOID , -2, false);
def(_dstore_2 , "dstore_2" , "b" , NULL , T_VOID , -2, false);
def(_dstore_3 , "dstore_3" , "b" , NULL , T_VOID , -2, false);
def(_astore_0 , "astore_0" , "b" , NULL , T_VOID , -1, false);
def(_astore_1 , "astore_1" , "b" , NULL , T_VOID , -1, false);
def(_astore_2 , "astore_2" , "b" , NULL , T_VOID , -1, false);
def(_astore_3 , "astore_3" , "b" , NULL , T_VOID , -1, false);
def(_iastore , "iastore" , "b" , NULL , T_VOID , -3, true );
def(_lastore , "lastore" , "b" , NULL , T_VOID , -4, true );
def(_fastore , "fastore" , "b" , NULL , T_VOID , -3, true );
def(_dastore , "dastore" , "b" , NULL , T_VOID , -4, true );
def(_aastore , "aastore" , "b" , NULL , T_VOID , -3, true );
def(_bastore , "bastore" , "b" , NULL , T_VOID , -3, true );
def(_castore , "castore" , "b" , NULL , T_VOID , -3, true );
def(_sastore , "sastore" , "b" , NULL , T_VOID , -3, true );
def(_pop , "pop" , "b" , NULL , T_VOID , -1, false);
def(_pop2 , "pop2" , "b" , NULL , T_VOID , -2, false);
def(_dup , "dup" , "b" , NULL , T_VOID , 1, false);
def(_dup_x1 , "dup_x1" , "b" , NULL , T_VOID , 1, false);
def(_dup_x2 , "dup_x2" , "b" , NULL , T_VOID , 1, false);
def(_dup2 , "dup2" , "b" , NULL , T_VOID , 2, false);
def(_dup2_x1 , "dup2_x1" , "b" , NULL , T_VOID , 2, false);
def(_dup2_x2 , "dup2_x2" , "b" , NULL , T_VOID , 2, false);
def(_swap , "swap" , "b" , NULL , T_VOID , 0, false);
def(_iadd , "iadd" , "b" , NULL , T_INT , -1, false);
def(_ladd , "ladd" , "b" , NULL , T_LONG , -2, false);
def(_fadd , "fadd" , "b" , NULL , T_FLOAT , -1, false);
def(_dadd , "dadd" , "b" , NULL , T_DOUBLE , -2, false);
def(_isub , "isub" , "b" , NULL , T_INT , -1, false);
def(_lsub , "lsub" , "b" , NULL , T_LONG , -2, false);
def(_fsub , "fsub" , "b" , NULL , T_FLOAT , -1, false);
def(_dsub , "dsub" , "b" , NULL , T_DOUBLE , -2, false);
def(_imul , "imul" , "b" , NULL , T_INT , -1, false);
def(_lmul , "lmul" , "b" , NULL , T_LONG , -2, false);
def(_fmul , "fmul" , "b" , NULL , T_FLOAT , -1, false);
def(_dmul , "dmul" , "b" , NULL , T_DOUBLE , -2, false);
def(_idiv , "idiv" , "b" , NULL , T_INT , -1, true );
def(_ldiv , "ldiv" , "b" , NULL , T_LONG , -2, true );
def(_fdiv , "fdiv" , "b" , NULL , T_FLOAT , -1, false);
def(_ddiv , "ddiv" , "b" , NULL , T_DOUBLE , -2, false);
def(_irem , "irem" , "b" , NULL , T_INT , -1, true );
def(_lrem , "lrem" , "b" , NULL , T_LONG , -2, true );
def(_frem , "frem" , "b" , NULL , T_FLOAT , -1, false);
def(_drem , "drem" , "b" , NULL , T_DOUBLE , -2, false);
def(_ineg , "ineg" , "b" , NULL , T_INT , 0, false);
def(_lneg , "lneg" , "b" , NULL , T_LONG , 0, false);
def(_fneg , "fneg" , "b" , NULL , T_FLOAT , 0, false);
def(_dneg , "dneg" , "b" , NULL , T_DOUBLE , 0, false);
def(_ishl , "ishl" , "b" , NULL , T_INT , -1, false);
def(_lshl , "lshl" , "b" , NULL , T_LONG , -1, false);
def(_ishr , "ishr" , "b" , NULL , T_INT , -1, false);
def(_lshr , "lshr" , "b" , NULL , T_LONG , -1, false);
def(_iushr , "iushr" , "b" , NULL , T_INT , -1, false);
def(_lushr , "lushr" , "b" , NULL , T_LONG , -1, false);
def(_iand , "iand" , "b" , NULL , T_INT , -1, false);
def(_land , "land" , "b" , NULL , T_LONG , -2, false);
def(_ior , "ior" , "b" , NULL , T_INT , -1, false);
def(_lor , "lor" , "b" , NULL , T_LONG , -2, false);
def(_ixor , "ixor" , "b" , NULL , T_INT , -1, false);
def(_lxor , "lxor" , "b" , NULL , T_LONG , -2, false);
def(_iinc , "iinc" , "bic" , "wbiicc", T_VOID , 0, false);
def(_i2l , "i2l" , "b" , NULL , T_LONG , 1, false);
def(_i2f , "i2f" , "b" , NULL , T_FLOAT , 0, false);
def(_i2d , "i2d" , "b" , NULL , T_DOUBLE , 1, false);
def(_l2i , "l2i" , "b" , NULL , T_INT , -1, false);
def(_l2f , "l2f" , "b" , NULL , T_FLOAT , -1, false);
def(_l2d , "l2d" , "b" , NULL , T_DOUBLE , 0, false);
def(_f2i , "f2i" , "b" , NULL , T_INT , 0, false);
def(_f2l , "f2l" , "b" , NULL , T_LONG , 1, false);
def(_f2d , "f2d" , "b" , NULL , T_DOUBLE , 1, false);
def(_d2i , "d2i" , "b" , NULL , T_INT , -1, false);
def(_d2l , "d2l" , "b" , NULL , T_LONG , 0, false);
def(_d2f , "d2f" , "b" , NULL , T_FLOAT , -1, false);
def(_i2b , "i2b" , "b" , NULL , T_BYTE , 0, false);
def(_i2c , "i2c" , "b" , NULL , T_CHAR , 0, false);
def(_i2s , "i2s" , "b" , NULL , T_SHORT , 0, false);
def(_lcmp , "lcmp" , "b" , NULL , T_VOID , -3, false);
def(_fcmpl , "fcmpl" , "b" , NULL , T_VOID , -1, false);
def(_fcmpg , "fcmpg" , "b" , NULL , T_VOID , -1, false);
def(_dcmpl , "dcmpl" , "b" , NULL , T_VOID , -3, false);
def(_dcmpg , "dcmpg" , "b" , NULL , T_VOID , -3, false);
def(_ifeq , "ifeq" , "boo" , NULL , T_VOID , -1, false);
def(_ifne , "ifne" , "boo" , NULL , T_VOID , -1, false);
def(_iflt , "iflt" , "boo" , NULL , T_VOID , -1, false);
def(_ifge , "ifge" , "boo" , NULL , T_VOID , -1, false);
def(_ifgt , "ifgt" , "boo" , NULL , T_VOID , -1, false);
def(_ifle , "ifle" , "boo" , NULL , T_VOID , -1, false);
def(_if_icmpeq , "if_icmpeq" , "boo" , NULL , T_VOID , -2, false);
def(_if_icmpne , "if_icmpne" , "boo" , NULL , T_VOID , -2, false);
def(_if_icmplt , "if_icmplt" , "boo" , NULL , T_VOID , -2, false);
def(_if_icmpge , "if_icmpge" , "boo" , NULL , T_VOID , -2, false);
def(_if_icmpgt , "if_icmpgt" , "boo" , NULL , T_VOID , -2, false);
def(_if_icmple , "if_icmple" , "boo" , NULL , T_VOID , -2, false);
def(_if_acmpeq , "if_acmpeq" , "boo" , NULL , T_VOID , -2, false);
def(_if_acmpne , "if_acmpne" , "boo" , NULL , T_VOID , -2, false);
def(_goto , "goto" , "boo" , NULL , T_VOID , 0, false);
def(_jsr , "jsr" , "boo" , NULL , T_INT , 0, false);
def(_ret , "ret" , "bi" , "wbii" , T_VOID , 0, false);
def(_tableswitch , "tableswitch" , "" , NULL , T_VOID , -1, false); // may have backward branches
def(_lookupswitch , "lookupswitch" , "" , NULL , T_VOID , -1, false); // rewriting in interpreter
def(_ireturn , "ireturn" , "b" , NULL , T_INT , -1, true);
def(_lreturn , "lreturn" , "b" , NULL , T_LONG , -2, true);
def(_freturn , "freturn" , "b" , NULL , T_FLOAT , -1, true);
def(_dreturn , "dreturn" , "b" , NULL , T_DOUBLE , -2, true);
def(_areturn , "areturn" , "b" , NULL , T_OBJECT , -1, true);
def(_return , "return" , "b" , NULL , T_VOID , 0, true);
def(_getstatic , "getstatic" , "bjj" , NULL , T_ILLEGAL, 1, true );
def(_putstatic , "putstatic" , "bjj" , NULL , T_ILLEGAL, -1, true );
def(_getfield , "getfield" , "bjj" , NULL , T_ILLEGAL, 0, true );
def(_putfield , "putfield" , "bjj" , NULL , T_ILLEGAL, -2, true );
def(_invokevirtual , "invokevirtual" , "bjj" , NULL , T_ILLEGAL, -1, true);
def(_invokespecial , "invokespecial" , "bjj" , NULL , T_ILLEGAL, -1, true);
def(_invokestatic , "invokestatic" , "bjj" , NULL , T_ILLEGAL, 0, true);
def(_invokeinterface , "invokeinterface" , "bjj__", NULL , T_ILLEGAL, -1, true);
def(_xxxunusedxxx , "xxxunusedxxx" , NULL , NULL , T_VOID , 0, false);
def(_new , "new" , "bii" , NULL , T_OBJECT , 1, true );
def(_newarray , "newarray" , "bc" , NULL , T_OBJECT , 0, true );
def(_anewarray , "anewarray" , "bii" , NULL , T_OBJECT , 0, true );
def(_arraylength , "arraylength" , "b" , NULL , T_VOID , 0, true );
def(_athrow , "athrow" , "b" , NULL , T_VOID , -1, true );
def(_checkcast , "checkcast" , "bii" , NULL , T_OBJECT , 0, true );
def(_instanceof , "instanceof" , "bii" , NULL , T_INT , 0, true );
def(_monitorenter , "monitorenter" , "b" , NULL , T_VOID , -1, true );
def(_monitorexit , "monitorexit" , "b" , NULL , T_VOID , -1, true );
def(_wide , "wide" , "" , NULL , T_VOID , 0, false);
def(_multianewarray , "multianewarray" , "biic" , NULL , T_OBJECT , 1, true );
def(_ifnull , "ifnull" , "boo" , NULL , T_VOID , -1, false);
def(_ifnonnull , "ifnonnull" , "boo" , NULL , T_VOID , -1, false);
def(_goto_w , "goto_w" , "boooo", NULL , T_VOID , 0, false);
def(_jsr_w , "jsr_w" , "boooo", NULL , T_INT , 0, false);
def(_breakpoint , "breakpoint" , "" , NULL , T_VOID , 0, true);
// JVM bytecodes
// bytecode bytecode name format wide f. result tp stk traps std code
def(_fast_agetfield , "fast_agetfield" , "bjj" , NULL , T_OBJECT , 0, true , _getfield );
def(_fast_bgetfield , "fast_bgetfield" , "bjj" , NULL , T_INT , 0, true , _getfield );
def(_fast_cgetfield , "fast_cgetfield" , "bjj" , NULL , T_CHAR , 0, true , _getfield );
def(_fast_dgetfield , "fast_dgetfield" , "bjj" , NULL , T_DOUBLE , 0, true , _getfield );
def(_fast_fgetfield , "fast_fgetfield" , "bjj" , NULL , T_FLOAT , 0, true , _getfield );
def(_fast_igetfield , "fast_igetfield" , "bjj" , NULL , T_INT , 0, true , _getfield );
def(_fast_lgetfield , "fast_lgetfield" , "bjj" , NULL , T_LONG , 0, true , _getfield );
def(_fast_sgetfield , "fast_sgetfield" , "bjj" , NULL , T_SHORT , 0, true , _getfield );
def(_fast_aputfield , "fast_aputfield" , "bjj" , NULL , T_OBJECT , 0, true , _putfield );
def(_fast_bputfield , "fast_bputfield" , "bjj" , NULL , T_INT , 0, true , _putfield );
def(_fast_cputfield , "fast_cputfield" , "bjj" , NULL , T_CHAR , 0, true , _putfield );
def(_fast_dputfield , "fast_dputfield" , "bjj" , NULL , T_DOUBLE , 0, true , _putfield );
def(_fast_fputfield , "fast_fputfield" , "bjj" , NULL , T_FLOAT , 0, true , _putfield );
def(_fast_iputfield , "fast_iputfield" , "bjj" , NULL , T_INT , 0, true , _putfield );
def(_fast_lputfield , "fast_lputfield" , "bjj" , NULL , T_LONG , 0, true , _putfield );
def(_fast_sputfield , "fast_sputfield" , "bjj" , NULL , T_SHORT , 0, true , _putfield );
def(_fast_aload_0 , "fast_aload_0" , "b" , NULL , T_OBJECT , 1, true , _aload_0 );
def(_fast_iaccess_0 , "fast_iaccess_0" , "b_jj" , NULL , T_INT , 1, true , _aload_0 );
def(_fast_aaccess_0 , "fast_aaccess_0" , "b_jj" , NULL , T_OBJECT , 1, true , _aload_0 );
def(_fast_faccess_0 , "fast_faccess_0" , "b_jj" , NULL , T_OBJECT , 1, true , _aload_0 );
def(_fast_iload , "fast_iload" , "bi" , NULL , T_INT , 1, false, _iload);
def(_fast_iload2 , "fast_iload2" , "bi_i" , NULL , T_INT , 2, false, _iload);
def(_fast_icaload , "fast_icaload" , "bi_" , NULL , T_INT , 0, false, _iload);
// Faster method invocation.
def(_fast_invokevfinal , "fast_invokevfinal" , "bjj" , NULL , T_ILLEGAL, -1, true, _invokevirtual );
def(_fast_linearswitch , "fast_linearswitch" , "" , NULL , T_VOID , -1, false, _lookupswitch );
def(_fast_binaryswitch , "fast_binaryswitch" , "" , NULL , T_VOID , -1, false, _lookupswitch );
def(_return_register_finalizer , "return_register_finalizer" , "b" , NULL , T_VOID , 0, true, _return);
def(_shouldnotreachhere , "_shouldnotreachhere" , "b" , NULL , T_VOID , 0, false);
// platform specific JVM bytecodes
pd_initialize();
// compare can_trap information for each bytecode with the
// can_trap information for the corresponding base bytecode
// (if a rewritten bytecode can trap, so must the base bytecode)
#ifdef ASSERT
{ for (int i = 0; i < number_of_codes; i++) {
if (is_defined(i)) {
Code code = cast(i);
Code java = java_code(code);
if (can_trap(code) && !can_trap(java)) fatal2("%s can trap => %s can trap, too", name(code), name(java));
}
}
}
#endif
// initialization successful
_is_initialized = true;
}
void bytecodes_init() {
Bytecodes::initialize();
}
// Restore optimization
#ifdef _M_AMD64
#pragma optimize ("", on)
#endif

View file

@ -0,0 +1,358 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// Bytecodes specifies all bytecodes used in the VM and
// provides utility functions to get bytecode attributes.
// NOTE: replicated in SA in vm/agent/sun/jvm/hotspot/interpreter/Bytecodes.java
class Bytecodes: AllStatic {
public:
enum Code {
_illegal = -1,
// Java bytecodes
_nop = 0, // 0x00
_aconst_null = 1, // 0x01
_iconst_m1 = 2, // 0x02
_iconst_0 = 3, // 0x03
_iconst_1 = 4, // 0x04
_iconst_2 = 5, // 0x05
_iconst_3 = 6, // 0x06
_iconst_4 = 7, // 0x07
_iconst_5 = 8, // 0x08
_lconst_0 = 9, // 0x09
_lconst_1 = 10, // 0x0a
_fconst_0 = 11, // 0x0b
_fconst_1 = 12, // 0x0c
_fconst_2 = 13, // 0x0d
_dconst_0 = 14, // 0x0e
_dconst_1 = 15, // 0x0f
_bipush = 16, // 0x10
_sipush = 17, // 0x11
_ldc = 18, // 0x12
_ldc_w = 19, // 0x13
_ldc2_w = 20, // 0x14
_iload = 21, // 0x15
_lload = 22, // 0x16
_fload = 23, // 0x17
_dload = 24, // 0x18
_aload = 25, // 0x19
_iload_0 = 26, // 0x1a
_iload_1 = 27, // 0x1b
_iload_2 = 28, // 0x1c
_iload_3 = 29, // 0x1d
_lload_0 = 30, // 0x1e
_lload_1 = 31, // 0x1f
_lload_2 = 32, // 0x20
_lload_3 = 33, // 0x21
_fload_0 = 34, // 0x22
_fload_1 = 35, // 0x23
_fload_2 = 36, // 0x24
_fload_3 = 37, // 0x25
_dload_0 = 38, // 0x26
_dload_1 = 39, // 0x27
_dload_2 = 40, // 0x28
_dload_3 = 41, // 0x29
_aload_0 = 42, // 0x2a
_aload_1 = 43, // 0x2b
_aload_2 = 44, // 0x2c
_aload_3 = 45, // 0x2d
_iaload = 46, // 0x2e
_laload = 47, // 0x2f
_faload = 48, // 0x30
_daload = 49, // 0x31
_aaload = 50, // 0x32
_baload = 51, // 0x33
_caload = 52, // 0x34
_saload = 53, // 0x35
_istore = 54, // 0x36
_lstore = 55, // 0x37
_fstore = 56, // 0x38
_dstore = 57, // 0x39
_astore = 58, // 0x3a
_istore_0 = 59, // 0x3b
_istore_1 = 60, // 0x3c
_istore_2 = 61, // 0x3d
_istore_3 = 62, // 0x3e
_lstore_0 = 63, // 0x3f
_lstore_1 = 64, // 0x40
_lstore_2 = 65, // 0x41
_lstore_3 = 66, // 0x42
_fstore_0 = 67, // 0x43
_fstore_1 = 68, // 0x44
_fstore_2 = 69, // 0x45
_fstore_3 = 70, // 0x46
_dstore_0 = 71, // 0x47
_dstore_1 = 72, // 0x48
_dstore_2 = 73, // 0x49
_dstore_3 = 74, // 0x4a
_astore_0 = 75, // 0x4b
_astore_1 = 76, // 0x4c
_astore_2 = 77, // 0x4d
_astore_3 = 78, // 0x4e
_iastore = 79, // 0x4f
_lastore = 80, // 0x50
_fastore = 81, // 0x51
_dastore = 82, // 0x52
_aastore = 83, // 0x53
_bastore = 84, // 0x54
_castore = 85, // 0x55
_sastore = 86, // 0x56
_pop = 87, // 0x57
_pop2 = 88, // 0x58
_dup = 89, // 0x59
_dup_x1 = 90, // 0x5a
_dup_x2 = 91, // 0x5b
_dup2 = 92, // 0x5c
_dup2_x1 = 93, // 0x5d
_dup2_x2 = 94, // 0x5e
_swap = 95, // 0x5f
_iadd = 96, // 0x60
_ladd = 97, // 0x61
_fadd = 98, // 0x62
_dadd = 99, // 0x63
_isub = 100, // 0x64
_lsub = 101, // 0x65
_fsub = 102, // 0x66
_dsub = 103, // 0x67
_imul = 104, // 0x68
_lmul = 105, // 0x69
_fmul = 106, // 0x6a
_dmul = 107, // 0x6b
_idiv = 108, // 0x6c
_ldiv = 109, // 0x6d
_fdiv = 110, // 0x6e
_ddiv = 111, // 0x6f
_irem = 112, // 0x70
_lrem = 113, // 0x71
_frem = 114, // 0x72
_drem = 115, // 0x73
_ineg = 116, // 0x74
_lneg = 117, // 0x75
_fneg = 118, // 0x76
_dneg = 119, // 0x77
_ishl = 120, // 0x78
_lshl = 121, // 0x79
_ishr = 122, // 0x7a
_lshr = 123, // 0x7b
_iushr = 124, // 0x7c
_lushr = 125, // 0x7d
_iand = 126, // 0x7e
_land = 127, // 0x7f
_ior = 128, // 0x80
_lor = 129, // 0x81
_ixor = 130, // 0x82
_lxor = 131, // 0x83
_iinc = 132, // 0x84
_i2l = 133, // 0x85
_i2f = 134, // 0x86
_i2d = 135, // 0x87
_l2i = 136, // 0x88
_l2f = 137, // 0x89
_l2d = 138, // 0x8a
_f2i = 139, // 0x8b
_f2l = 140, // 0x8c
_f2d = 141, // 0x8d
_d2i = 142, // 0x8e
_d2l = 143, // 0x8f
_d2f = 144, // 0x90
_i2b = 145, // 0x91
_i2c = 146, // 0x92
_i2s = 147, // 0x93
_lcmp = 148, // 0x94
_fcmpl = 149, // 0x95
_fcmpg = 150, // 0x96
_dcmpl = 151, // 0x97
_dcmpg = 152, // 0x98
_ifeq = 153, // 0x99
_ifne = 154, // 0x9a
_iflt = 155, // 0x9b
_ifge = 156, // 0x9c
_ifgt = 157, // 0x9d
_ifle = 158, // 0x9e
_if_icmpeq = 159, // 0x9f
_if_icmpne = 160, // 0xa0
_if_icmplt = 161, // 0xa1
_if_icmpge = 162, // 0xa2
_if_icmpgt = 163, // 0xa3
_if_icmple = 164, // 0xa4
_if_acmpeq = 165, // 0xa5
_if_acmpne = 166, // 0xa6
_goto = 167, // 0xa7
_jsr = 168, // 0xa8
_ret = 169, // 0xa9
_tableswitch = 170, // 0xaa
_lookupswitch = 171, // 0xab
_ireturn = 172, // 0xac
_lreturn = 173, // 0xad
_freturn = 174, // 0xae
_dreturn = 175, // 0xaf
_areturn = 176, // 0xb0
_return = 177, // 0xb1
_getstatic = 178, // 0xb2
_putstatic = 179, // 0xb3
_getfield = 180, // 0xb4
_putfield = 181, // 0xb5
_invokevirtual = 182, // 0xb6
_invokespecial = 183, // 0xb7
_invokestatic = 184, // 0xb8
_invokeinterface = 185, // 0xb9
_xxxunusedxxx = 186, // 0xba
_new = 187, // 0xbb
_newarray = 188, // 0xbc
_anewarray = 189, // 0xbd
_arraylength = 190, // 0xbe
_athrow = 191, // 0xbf
_checkcast = 192, // 0xc0
_instanceof = 193, // 0xc1
_monitorenter = 194, // 0xc2
_monitorexit = 195, // 0xc3
_wide = 196, // 0xc4
_multianewarray = 197, // 0xc5
_ifnull = 198, // 0xc6
_ifnonnull = 199, // 0xc7
_goto_w = 200, // 0xc8
_jsr_w = 201, // 0xc9
_breakpoint = 202, // 0xca
number_of_java_codes,
// JVM bytecodes
_fast_agetfield = number_of_java_codes,
_fast_bgetfield ,
_fast_cgetfield ,
_fast_dgetfield ,
_fast_fgetfield ,
_fast_igetfield ,
_fast_lgetfield ,
_fast_sgetfield ,
_fast_aputfield ,
_fast_bputfield ,
_fast_cputfield ,
_fast_dputfield ,
_fast_fputfield ,
_fast_iputfield ,
_fast_lputfield ,
_fast_sputfield ,
_fast_aload_0 ,
_fast_iaccess_0 ,
_fast_aaccess_0 ,
_fast_faccess_0 ,
_fast_iload ,
_fast_iload2 ,
_fast_icaload ,
_fast_invokevfinal ,
_fast_linearswitch ,
_fast_binaryswitch ,
_return_register_finalizer ,
_shouldnotreachhere, // For debugging
// Platform specific JVM bytecodes
#include "incls/_bytecodes_pd.hpp.incl"
number_of_codes
};
private:
static bool _is_initialized;
static const char* _name [number_of_codes];
static const char* _format [number_of_codes];
static const char* _wide_format [number_of_codes];
static BasicType _result_type [number_of_codes];
static s_char _depth [number_of_codes];
static u_char _length [number_of_codes];
static bool _can_trap [number_of_codes];
static Code _java_code [number_of_codes];
static bool _can_rewrite [number_of_codes];
static void def(Code code, const char* name, const char* format, const char* wide_format, BasicType result_type, int depth, bool can_trap);
static void def(Code code, const char* name, const char* format, const char* wide_format, BasicType result_type, int depth, bool can_trap, Code java_code);
static void pd_initialize(); // platform specific initialization
static Code pd_base_code_for(Code code); // platform specific base_code_for implementation
public:
// Conversion
static void check (Code code) { assert(is_defined(code), "illegal code"); }
static void wide_check (Code code) { assert(wide_is_defined(code), "illegal code"); }
static Code cast (int code) { return (Code)code; }
// Fetch a bytecode, hiding breakpoints as necessary:
static Code code_at(address bcp, methodOop method = NULL) {
Code code = cast(*bcp); return (code != _breakpoint) ? code : non_breakpoint_code_at(bcp, method);
}
static Code java_code_at(address bcp, methodOop method = NULL) {
return java_code(code_at(bcp, method));
}
// Fetch a bytecode or a breakpoint:
static Code code_or_bp_at(address bcp) { return (Code)cast(*bcp); }
static Code code_at(methodOop method, int bci);
static bool is_active_breakpoint_at(address bcp) { return (Code)*bcp == _breakpoint; }
// find a bytecode, behind a breakpoint if necessary:
static Code non_breakpoint_code_at(address bcp, methodOop method = NULL);
// Bytecode attributes
static bool is_defined (int code) { return 0 <= code && code < number_of_codes && _format[code] != NULL; }
static bool wide_is_defined(int code) { return is_defined(code) && _wide_format[code] != NULL; }
static const char* name (Code code) { check(code); return _name [code]; }
static const char* format (Code code) { check(code); return _format [code]; }
static const char* wide_format (Code code) { return _wide_format[code]; }
static BasicType result_type (Code code) { check(code); return _result_type [code]; }
static int depth (Code code) { check(code); return _depth [code]; }
static int length_for (Code code) { return _length[code]; }
static bool can_trap (Code code) { check(code); return _can_trap [code]; }
static Code java_code (Code code) { check(code); return _java_code [code]; }
static bool can_rewrite (Code code) { check(code); return _can_rewrite [code]; }
static int wide_length_for(Code code) {
if (!is_defined(code)) {
return 0;
}
const char* wf = wide_format(code);
return (wf == NULL) ? 0 : (int)strlen(wf);
}
static int special_length_at(address bcp);
static int raw_special_length_at(address bcp);
static int length_at (address bcp) { int l = length_for(code_at(bcp)); return l > 0 ? l : special_length_at(bcp); }
static int java_length_at (address bcp) { int l = length_for(java_code_at(bcp)); return l > 0 ? l : special_length_at(bcp); }
static bool is_java_code (Code code) { return 0 <= code && code < number_of_java_codes; }
static bool is_aload (Code code) { return (code == _aload || code == _aload_0 || code == _aload_1
|| code == _aload_2 || code == _aload_3); }
static bool is_astore (Code code) { return (code == _astore || code == _astore_0 || code == _astore_1
|| code == _astore_2 || code == _astore_3); }
static bool is_zero_const (Code code) { return (code == _aconst_null || code == _iconst_0
|| code == _fconst_0 || code == _dconst_0); }
// Initialization
static void initialize ();
};

View file

@ -0,0 +1,135 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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/_cppInterpreter.cpp.incl"
#ifdef CC_INTERP
# define __ _masm->
void CppInterpreter::initialize() {
if (_code != NULL) return;
AbstractInterpreter::initialize();
// generate interpreter
{ ResourceMark rm;
TraceTime timer("Interpreter generation", TraceStartupTime);
int code_size = InterpreterCodeSize;
NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space
_code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
"Interpreter");
InterpreterGenerator g(_code);
if (PrintInterpreter) print();
}
// Allow c++ interpreter to do one initialization now that switches are set, etc.
BytecodeInterpreter start_msg(BytecodeInterpreter::initialize);
if (JvmtiExport::can_post_interpreter_events())
BytecodeInterpreter::runWithChecks(&start_msg);
else
BytecodeInterpreter::run(&start_msg);
}
address CppInterpreter::_tosca_to_stack [AbstractInterpreter::number_of_result_handlers];
address CppInterpreter::_stack_to_stack [AbstractInterpreter::number_of_result_handlers];
address CppInterpreter::_stack_to_native_abi [AbstractInterpreter::number_of_result_handlers];
CppInterpreterGenerator::CppInterpreterGenerator(StubQueue* _code): AbstractInterpreterGenerator(_code) {
}
static const BasicType types[Interpreter::number_of_result_handlers] = {
T_BOOLEAN,
T_CHAR ,
T_BYTE ,
T_SHORT ,
T_INT ,
T_LONG ,
T_VOID ,
T_FLOAT ,
T_DOUBLE ,
T_OBJECT
};
void CppInterpreterGenerator::generate_all() {
AbstractInterpreterGenerator::generate_all();
{ CodeletMark cm(_masm, "result handlers for native calls");
// The various result converter stublets.
int is_generated[Interpreter::number_of_result_handlers];
memset(is_generated, 0, sizeof(is_generated));
int _tosca_to_stack_is_generated[Interpreter::number_of_result_handlers];
int _stack_to_stack_is_generated[Interpreter::number_of_result_handlers];
int _stack_to_native_abi_is_generated[Interpreter::number_of_result_handlers];
memset(_tosca_to_stack_is_generated, 0, sizeof(_tosca_to_stack_is_generated));
memset(_stack_to_stack_is_generated, 0, sizeof(_stack_to_stack_is_generated));
memset(_stack_to_native_abi_is_generated, 0, sizeof(_stack_to_native_abi_is_generated));
for (int i = 0; i < Interpreter::number_of_result_handlers; i++) {
BasicType type = types[i];
if (!is_generated[Interpreter::BasicType_as_index(type)]++) {
Interpreter::_native_abi_to_tosca[Interpreter::BasicType_as_index(type)] = generate_result_handler_for(type);
}
if (!_tosca_to_stack_is_generated[Interpreter::BasicType_as_index(type)]++) {
Interpreter::_tosca_to_stack[Interpreter::BasicType_as_index(type)] = generate_tosca_to_stack_converter(type);
}
if (!_stack_to_stack_is_generated[Interpreter::BasicType_as_index(type)]++) {
Interpreter::_stack_to_stack[Interpreter::BasicType_as_index(type)] = generate_stack_to_stack_converter(type);
}
if (!_stack_to_native_abi_is_generated[Interpreter::BasicType_as_index(type)]++) {
Interpreter::_stack_to_native_abi[Interpreter::BasicType_as_index(type)] = generate_stack_to_native_abi_converter(type);
}
}
}
#define method_entry(kind) Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind)
{ CodeletMark cm(_masm, "(kind = frame_manager)");
// all non-native method kinds
method_entry(zerolocals);
method_entry(zerolocals_synchronized);
method_entry(empty);
method_entry(accessor);
method_entry(abstract);
method_entry(java_lang_math_sin );
method_entry(java_lang_math_cos );
method_entry(java_lang_math_tan );
method_entry(java_lang_math_abs );
method_entry(java_lang_math_sqrt );
method_entry(java_lang_math_log );
method_entry(java_lang_math_log10 );
Interpreter::_native_entry_begin = Interpreter::code()->code_end();
method_entry(native);
method_entry(native_synchronized);
Interpreter::_native_entry_end = Interpreter::code()->code_end();
}
#undef method_entry
}
#endif // CC_INTERP

View file

@ -0,0 +1,83 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
#ifdef CC_INTERP
// This file contains the platform-independant parts
// of the c++ interpreter
class CppInterpreter: public AbstractInterpreter {
friend class VMStructs;
friend class Interpreter; // contains()
friend class InterpreterGenerator; // result handlers
friend class CppInterpreterGenerator; // result handlers
public:
protected:
// tosca result -> stack result
static address _tosca_to_stack[number_of_result_handlers]; // converts tosca to C++ interpreter stack result
// stack result -> stack result
static address _stack_to_stack[number_of_result_handlers]; // pass result between C++ interpreter calls
// stack result -> native abi result
static address _stack_to_native_abi[number_of_result_handlers]; // converts C++ interpreter results to native abi
// this is to allow frame and only frame to use contains().
friend class frame;
public:
// Initialization/debugging
static void initialize();
// this only returns whether a pc is within generated code for the interpreter.
// This is a moderately dubious interface for the c++ interpreter. Only
// frame code and debug.cpp should be using it.
static bool contains(address pc);
public:
// No displatch table to switch so no need for these to do anything special
static void notice_safepoints() {}
static void ignore_safepoints() {}
static address native_result_to_tosca() { return (address)_native_abi_to_tosca; } // aka result handler
static address tosca_result_to_stack() { return (address)_tosca_to_stack; }
static address stack_result_to_stack() { return (address)_stack_to_stack; }
static address stack_result_to_native() { return (address)_stack_to_native_abi; }
static address native_result_to_tosca(int index) { return _native_abi_to_tosca[index]; } // aka result handler
static address tosca_result_to_stack(int index) { return _tosca_to_stack[index]; }
static address stack_result_to_stack(int index) { return _stack_to_stack[index]; }
static address stack_result_to_native(int index) { return _stack_to_native_abi[index]; }
static address return_entry (TosState state, int length);
static address deopt_entry (TosState state, int length);
#include "incls/_cppInterpreter_pd.hpp.incl"
};
#endif // CC_INTERP

View file

@ -0,0 +1,47 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// This file contains the platform-independant parts
// of the template interpreter generator.
#ifdef CC_INTERP
class CppInterpreterGenerator: public AbstractInterpreterGenerator {
protected:
// shared code sequences
// Converter for native abi result to tosca result
address generate_result_handler_for(BasicType type);
address generate_tosca_to_stack_converter(BasicType type);
address generate_stack_to_stack_converter(BasicType type);
address generate_stack_to_native_abi_converter(BasicType type);
void generate_all();
public:
CppInterpreterGenerator(StubQueue* _code);
#include "incls/_cppInterpreterGenerator_pd.hpp.incl"
};
#endif // CC_INTERP

View file

@ -0,0 +1,409 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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/_interpreter.cpp.incl"
# define __ _masm->
//------------------------------------------------------------------------------------------------------------------------
// Implementation of InterpreterCodelet
void InterpreterCodelet::initialize(const char* description, Bytecodes::Code bytecode) {
_description = description;
_bytecode = bytecode;
}
void InterpreterCodelet::verify() {
}
void InterpreterCodelet::print() {
if (PrintInterpreter) {
tty->cr();
tty->print_cr("----------------------------------------------------------------------");
}
if (description() != NULL) tty->print("%s ", description());
if (bytecode() >= 0 ) tty->print("%d %s ", bytecode(), Bytecodes::name(bytecode()));
tty->print_cr("[" INTPTR_FORMAT ", " INTPTR_FORMAT "] %d bytes",
code_begin(), code_end(), code_size());
if (PrintInterpreter) {
tty->cr();
Disassembler::decode(code_begin(), code_end(), tty);
}
}
//------------------------------------------------------------------------------------------------------------------------
// Implementation of platform independent aspects of Interpreter
void AbstractInterpreter::initialize() {
if (_code != NULL) return;
// make sure 'imported' classes are initialized
if (CountBytecodes || TraceBytecodes || StopInterpreterAt) BytecodeCounter::reset();
if (PrintBytecodeHistogram) BytecodeHistogram::reset();
if (PrintBytecodePairHistogram) BytecodePairHistogram::reset();
InvocationCounter::reinitialize(DelayCompilationDuringStartup);
}
void AbstractInterpreter::print() {
tty->cr();
tty->print_cr("----------------------------------------------------------------------");
tty->print_cr("Interpreter");
tty->cr();
tty->print_cr("code size = %6dK bytes", (int)_code->used_space()/1024);
tty->print_cr("total space = %6dK bytes", (int)_code->total_space()/1024);
tty->print_cr("wasted space = %6dK bytes", (int)_code->available_space()/1024);
tty->cr();
tty->print_cr("# of codelets = %6d" , _code->number_of_stubs());
tty->print_cr("avg codelet size = %6d bytes", _code->used_space() / _code->number_of_stubs());
tty->cr();
_code->print();
tty->print_cr("----------------------------------------------------------------------");
tty->cr();
}
void interpreter_init() {
Interpreter::initialize();
#ifndef PRODUCT
if (TraceBytecodes) BytecodeTracer::set_closure(BytecodeTracer::std_closure());
#endif // PRODUCT
// need to hit every safepoint in order to call zapping routine
// register the interpreter
VTune::register_stub(
"Interpreter",
AbstractInterpreter::code()->code_start(),
AbstractInterpreter::code()->code_end()
);
Forte::register_stub(
"Interpreter",
AbstractInterpreter::code()->code_start(),
AbstractInterpreter::code()->code_end()
);
// notify JVMTI profiler
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated("Interpreter",
AbstractInterpreter::code()->code_start(),
AbstractInterpreter::code()->code_end());
}
}
//------------------------------------------------------------------------------------------------------------------------
// Implementation of interpreter
StubQueue* AbstractInterpreter::_code = NULL;
bool AbstractInterpreter::_notice_safepoints = false;
address AbstractInterpreter::_rethrow_exception_entry = NULL;
address AbstractInterpreter::_native_entry_begin = NULL;
address AbstractInterpreter::_native_entry_end = NULL;
address AbstractInterpreter::_slow_signature_handler;
address AbstractInterpreter::_entry_table [AbstractInterpreter::number_of_method_entries];
address AbstractInterpreter::_native_abi_to_tosca [AbstractInterpreter::number_of_result_handlers];
//------------------------------------------------------------------------------------------------------------------------
// Generation of complete interpreter
AbstractInterpreterGenerator::AbstractInterpreterGenerator(StubQueue* _code) {
_masm = NULL;
}
static const BasicType types[Interpreter::number_of_result_handlers] = {
T_BOOLEAN,
T_CHAR ,
T_BYTE ,
T_SHORT ,
T_INT ,
T_LONG ,
T_VOID ,
T_FLOAT ,
T_DOUBLE ,
T_OBJECT
};
void AbstractInterpreterGenerator::generate_all() {
{ CodeletMark cm(_masm, "slow signature handler");
Interpreter::_slow_signature_handler = generate_slow_signature_handler();
}
}
//------------------------------------------------------------------------------------------------------------------------
// Entry points
AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m) {
// Abstract method?
if (m->is_abstract()) return abstract;
// Native method?
// Note: This test must come _before_ the test for intrinsic
// methods. See also comments below.
if (m->is_native()) {
return m->is_synchronized() ? native_synchronized : native;
}
// Synchronized?
if (m->is_synchronized()) {
return zerolocals_synchronized;
}
if (RegisterFinalizersAtInit && m->code_size() == 1 &&
m->intrinsic_id() == vmIntrinsics::_Object_init) {
// We need to execute the special return bytecode to check for
// finalizer registration so create a normal frame.
return zerolocals;
}
// Empty method?
if (m->is_empty_method()) {
return empty;
}
// Accessor method?
if (m->is_accessor()) {
assert(m->size_of_parameters() == 1, "fast code for accessors assumes parameter size = 1");
return accessor;
}
// Special intrinsic method?
// Note: This test must come _after_ the test for native methods,
// otherwise we will run into problems with JDK 1.2, see also
// AbstractInterpreterGenerator::generate_method_entry() for
// for details.
switch (m->intrinsic_id()) {
case vmIntrinsics::_dsin : return java_lang_math_sin ;
case vmIntrinsics::_dcos : return java_lang_math_cos ;
case vmIntrinsics::_dtan : return java_lang_math_tan ;
case vmIntrinsics::_dabs : return java_lang_math_abs ;
case vmIntrinsics::_dsqrt : return java_lang_math_sqrt ;
case vmIntrinsics::_dlog : return java_lang_math_log ;
case vmIntrinsics::_dlog10: return java_lang_math_log10;
}
// Note: for now: zero locals for all non-empty methods
return zerolocals;
}
// Return true if the interpreter can prove that the given bytecode has
// not yet been executed (in Java semantics, not in actual operation).
bool AbstractInterpreter::is_not_reached(methodHandle method, int bci) {
address bcp = method->bcp_from(bci);
if (!Bytecode_at(bcp)->must_rewrite()) {
// might have been reached
return false;
}
// the bytecode might not be rewritten if the method is an accessor, etc.
address ientry = method->interpreter_entry();
if (ientry != entry_for_kind(AbstractInterpreter::zerolocals) &&
ientry != entry_for_kind(AbstractInterpreter::zerolocals_synchronized))
return false; // interpreter does not run this method!
// otherwise, we can be sure this bytecode has never been executed
return true;
}
#ifndef PRODUCT
void AbstractInterpreter::print_method_kind(MethodKind kind) {
switch (kind) {
case zerolocals : tty->print("zerolocals" ); break;
case zerolocals_synchronized: tty->print("zerolocals_synchronized"); break;
case native : tty->print("native" ); break;
case native_synchronized : tty->print("native_synchronized" ); break;
case empty : tty->print("empty" ); break;
case accessor : tty->print("accessor" ); break;
case abstract : tty->print("abstract" ); break;
case java_lang_math_sin : tty->print("java_lang_math_sin" ); break;
case java_lang_math_cos : tty->print("java_lang_math_cos" ); break;
case java_lang_math_tan : tty->print("java_lang_math_tan" ); break;
case java_lang_math_abs : tty->print("java_lang_math_abs" ); break;
case java_lang_math_sqrt : tty->print("java_lang_math_sqrt" ); break;
case java_lang_math_log : tty->print("java_lang_math_log" ); break;
case java_lang_math_log10 : tty->print("java_lang_math_log10" ); break;
default : ShouldNotReachHere();
}
}
#endif // PRODUCT
static BasicType constant_pool_type(methodOop method, int index) {
constantTag tag = method->constants()->tag_at(index);
if (tag.is_int ()) return T_INT;
else if (tag.is_float ()) return T_FLOAT;
else if (tag.is_long ()) return T_LONG;
else if (tag.is_double ()) return T_DOUBLE;
else if (tag.is_string ()) return T_OBJECT;
else if (tag.is_unresolved_string()) return T_OBJECT;
else if (tag.is_klass ()) return T_OBJECT;
else if (tag.is_unresolved_klass ()) return T_OBJECT;
ShouldNotReachHere();
return T_ILLEGAL;
}
//------------------------------------------------------------------------------------------------------------------------
// Deoptimization support
// If deoptimization happens, this method returns the point where to continue in
// interpreter. For calls (invokexxxx, newxxxx) the continuation is at next
// bci and the top of stack is in eax/edx/FPU tos.
// For putfield/getfield, put/getstatic, the continuation is at the same
// bci and the TOS is on stack.
// Note: deopt_entry(type, 0) means reexecute bytecode
// deopt_entry(type, length) means continue at next bytecode
address AbstractInterpreter::continuation_for(methodOop method, address bcp, int callee_parameters, bool is_top_frame, bool& use_next_mdp) {
assert(method->contains(bcp), "just checkin'");
Bytecodes::Code code = Bytecodes::java_code_at(bcp);
int bci = method->bci_from(bcp);
int length = -1; // initial value for debugging
// compute continuation length
length = Bytecodes::length_at(bcp);
// compute result type
BasicType type = T_ILLEGAL;
// when continuing after a compiler safepoint, re-execute the bytecode
// (an invoke is continued after the safepoint)
use_next_mdp = true;
switch (code) {
case Bytecodes::_lookupswitch:
case Bytecodes::_tableswitch:
case Bytecodes::_fast_binaryswitch:
case Bytecodes::_fast_linearswitch:
// recompute condtional expression folded into _if<cond>
case Bytecodes::_lcmp :
case Bytecodes::_fcmpl :
case Bytecodes::_fcmpg :
case Bytecodes::_dcmpl :
case Bytecodes::_dcmpg :
case Bytecodes::_ifnull :
case Bytecodes::_ifnonnull :
case Bytecodes::_goto :
case Bytecodes::_goto_w :
case Bytecodes::_ifeq :
case Bytecodes::_ifne :
case Bytecodes::_iflt :
case Bytecodes::_ifge :
case Bytecodes::_ifgt :
case Bytecodes::_ifle :
case Bytecodes::_if_icmpeq :
case Bytecodes::_if_icmpne :
case Bytecodes::_if_icmplt :
case Bytecodes::_if_icmpge :
case Bytecodes::_if_icmpgt :
case Bytecodes::_if_icmple :
case Bytecodes::_if_acmpeq :
case Bytecodes::_if_acmpne :
// special cases
case Bytecodes::_getfield :
case Bytecodes::_putfield :
case Bytecodes::_getstatic :
case Bytecodes::_putstatic :
case Bytecodes::_aastore :
// reexecute the operation and TOS value is on stack
assert(is_top_frame, "must be top frame");
use_next_mdp = false;
return Interpreter::deopt_entry(vtos, 0);
break;
#ifdef COMPILER1
case Bytecodes::_athrow :
assert(is_top_frame, "must be top frame");
use_next_mdp = false;
return Interpreter::rethrow_exception_entry();
break;
#endif /* COMPILER1 */
case Bytecodes::_invokevirtual :
case Bytecodes::_invokespecial :
case Bytecodes::_invokestatic :
case Bytecodes::_invokeinterface: {
Thread *thread = Thread::current();
ResourceMark rm(thread);
methodHandle mh(thread, method);
type = Bytecode_invoke_at(mh, bci)->result_type(thread);
// since the cache entry might not be initialized:
// (NOT needed for the old calling convension)
if (!is_top_frame) {
int index = Bytes::get_native_u2(bcp+1);
method->constants()->cache()->entry_at(index)->set_parameter_size(callee_parameters);
}
break;
}
case Bytecodes::_ldc :
type = constant_pool_type( method, *(bcp+1) );
break;
case Bytecodes::_ldc_w : // fall through
case Bytecodes::_ldc2_w:
type = constant_pool_type( method, Bytes::get_Java_u2(bcp+1) );
break;
default:
type = Bytecodes::result_type(code);
break;
}
// return entry point for computed continuation state & bytecode length
return
is_top_frame
? Interpreter::deopt_entry (as_TosState(type), length)
: Interpreter::return_entry(as_TosState(type), length);
}
void AbstractInterpreterGenerator::bang_stack_shadow_pages(bool native_call) {
// Quick & dirty stack overflow checking: bang the stack & handle trap.
// Note that we do the banging after the frame is setup, since the exception
// handling code expects to find a valid interpreter frame on the stack.
// Doing the banging earlier fails if the caller frame is not an interpreter
// frame.
// (Also, the exception throwing code expects to unlock any synchronized
// method receiever, so do the banging after locking the receiver.)
// Bang each page in the shadow zone. We can't assume it's been done for
// an interpreter frame with greater than a page of locals, so each page
// needs to be checked. Only true for non-native.
if (UseStackBanging) {
const int start_page = native_call ? StackShadowPages : 1;
const int page_size = os::vm_page_size();
for (int pages = start_page; pages <= StackShadowPages ; pages++) {
__ bang_stack_with_offset(pages*page_size);
}
}
}

View file

@ -0,0 +1,134 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// This file contains the platform-independant parts
// of the interpreter and the interpreter generator.
//------------------------------------------------------------------------------------------------------------------------
// An InterpreterCodelet is a piece of interpreter code. All
// interpreter code is generated into little codelets which
// contain extra information for debugging and printing purposes.
class InterpreterCodelet: public Stub {
friend class VMStructs;
private:
int _size; // the size in bytes
const char* _description; // a description of the codelet, for debugging & printing
Bytecodes::Code _bytecode; // associated bytecode if any
public:
// Initialization/finalization
void initialize(int size) { _size = size; }
void finalize() { ShouldNotCallThis(); }
// General info/converters
int size() const { return _size; }
static int code_size_to_size(int code_size) { return round_to(sizeof(InterpreterCodelet), CodeEntryAlignment) + code_size; }
// Code info
address code_begin() const { return (address)this + round_to(sizeof(InterpreterCodelet), CodeEntryAlignment); }
address code_end() const { return (address)this + size(); }
// Debugging
void verify();
void print();
// Interpreter-specific initialization
void initialize(const char* description, Bytecodes::Code bytecode);
// Interpreter-specific attributes
int code_size() const { return code_end() - code_begin(); }
const char* description() const { return _description; }
Bytecodes::Code bytecode() const { return _bytecode; }
};
// Define a prototype interface
DEF_STUB_INTERFACE(InterpreterCodelet);
//------------------------------------------------------------------------------------------------------------------------
// A CodeletMark serves as an automatic creator/initializer for Codelets
// (As a subclass of ResourceMark it automatically GC's the allocated
// code buffer and assemblers).
class CodeletMark: ResourceMark {
private:
InterpreterCodelet* _clet;
InterpreterMacroAssembler** _masm;
CodeBuffer _cb;
int codelet_size() {
// Request the whole code buffer (minus a little for alignment).
// The commit call below trims it back for each codelet.
int codelet_size = AbstractInterpreter::code()->available_space() - 2*K;
// Guarantee there's a little bit of code space left.
guarantee (codelet_size > 0 && (size_t)codelet_size > 2*K,
"not enough space for interpreter generation");
return codelet_size;
}
public:
CodeletMark(
InterpreterMacroAssembler*& masm,
const char* description,
Bytecodes::Code bytecode = Bytecodes::_illegal):
_clet((InterpreterCodelet*)AbstractInterpreter::code()->request(codelet_size())),
_cb(_clet->code_begin(), _clet->code_size())
{ // request all space (add some slack for Codelet data)
assert (_clet != NULL, "we checked not enough space already");
// initialize Codelet attributes
_clet->initialize(description, bytecode);
// create assembler for code generation
masm = new InterpreterMacroAssembler(&_cb);
_masm = &masm;
}
~CodeletMark() {
// align so printing shows nop's instead of random code at the end (Codelets are aligned)
(*_masm)->align(wordSize);
// make sure all code is in code buffer
(*_masm)->flush();
// commit Codelet
AbstractInterpreter::code()->commit((*_masm)->code()->pure_code_size());
// make sure nobody can use _masm outside a CodeletMark lifespan
*_masm = NULL;
}
};
// Wrapper classes to produce Interpreter/InterpreterGenerator from either
// the c++ interpreter or the template interpreter.
class Interpreter: public CC_INTERP_ONLY(CppInterpreter) NOT_CC_INTERP(TemplateInterpreter) {
public:
// Debugging/printing
static InterpreterCodelet* codelet_containing(address pc) { return (InterpreterCodelet*)_code->stub_containing(pc); }
#include "incls/_interpreter_pd.hpp.incl"
};

View file

@ -0,0 +1,38 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// This file contains the platform-independant parts
// of the interpreter generator.
class InterpreterGenerator: public CC_INTERP_ONLY(CppInterpreterGenerator)
NOT_CC_INTERP(TemplateInterpreterGenerator) {
public:
InterpreterGenerator(StubQueue* _code);
#include "incls/_interpreterGenerator_pd.hpp.incl"
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,148 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// The InterpreterRuntime is called by the interpreter for everything
// that cannot/should not be dealt with in assembly and needs C support.
class InterpreterRuntime: AllStatic {
friend class BytecodeClosure; // for method and bcp
friend class PrintingClosure; // for method and bcp
private:
// Helper functions to access current interpreter state
static frame last_frame(JavaThread *thread) { return thread->last_frame(); }
static methodOop method(JavaThread *thread) { return last_frame(thread).interpreter_frame_method(); }
static address bcp(JavaThread *thread) { return last_frame(thread).interpreter_frame_bcp(); }
static void set_bcp_and_mdp(address bcp, JavaThread*thread);
static Bytecodes::Code code(JavaThread *thread) { return Bytecodes::code_at(bcp(thread)); }
static bool already_resolved(JavaThread *thread) { return cache_entry(thread)->is_resolved(code(thread)); }
static int one_byte_index(JavaThread *thread) { return bcp(thread)[1]; }
static int two_byte_index(JavaThread *thread) { return Bytes::get_Java_u2(bcp(thread) + 1); }
static int number_of_dimensions(JavaThread *thread) { return bcp(thread)[3]; }
static ConstantPoolCacheEntry* cache_entry(JavaThread *thread) { return method(thread)->constants()->cache()->entry_at(Bytes::get_native_u2(bcp(thread) + 1)); }
static void note_trap(JavaThread *thread, int reason, TRAPS);
public:
// Constants
static void ldc (JavaThread* thread, bool wide);
// Allocation
static void _new (JavaThread* thread, constantPoolOopDesc* pool, int index);
static void newarray (JavaThread* thread, BasicType type, jint size);
static void anewarray (JavaThread* thread, constantPoolOopDesc* pool, int index, jint size);
static void multianewarray(JavaThread* thread, jint* first_size_address);
static void register_finalizer(JavaThread* thread, oopDesc* obj);
// Quicken instance-of and check-cast bytecodes
static void quicken_io_cc(JavaThread* thread);
// Exceptions thrown by the interpreter
static void throw_AbstractMethodError(JavaThread* thread);
static void throw_IncompatibleClassChangeError(JavaThread* thread);
static void throw_StackOverflowError(JavaThread* thread);
static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, char* name, jint index);
static void throw_ClassCastException(JavaThread* thread, oopDesc* obj);
static void create_exception(JavaThread* thread, char* name, char* message);
static void create_klass_exception(JavaThread* thread, char* name, oopDesc* obj);
static address exception_handler_for_exception(JavaThread* thread, oopDesc* exception);
static void throw_pending_exception(JavaThread* thread);
// Statics & fields
static void resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode);
// Synchronization
static void monitorenter(JavaThread* thread, BasicObjectLock* elem);
static void monitorexit (JavaThread* thread, BasicObjectLock* elem);
static void throw_illegal_monitor_state_exception(JavaThread* thread);
static void new_illegal_monitor_state_exception(JavaThread* thread);
// Calls
static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode);
// Breakpoints
static void _breakpoint(JavaThread* thread, methodOopDesc* method, address bcp);
static Bytecodes::Code get_original_bytecode_at(JavaThread* thread, methodOopDesc* method, address bcp);
static void set_original_bytecode_at(JavaThread* thread, methodOopDesc* method, address bcp, Bytecodes::Code new_code);
static bool is_breakpoint(JavaThread *thread) { return Bytecodes::code_or_bp_at(bcp(thread)) == Bytecodes::_breakpoint; }
// Safepoints
static void at_safepoint(JavaThread* thread);
// Debugger support
static void post_field_access(JavaThread *thread, oopDesc* obj,
ConstantPoolCacheEntry *cp_entry);
static void post_field_modification(JavaThread *thread, oopDesc* obj,
ConstantPoolCacheEntry *cp_entry, jvalue *value);
static void post_method_entry(JavaThread *thread);
static void post_method_exit (JavaThread *thread);
static int interpreter_contains(address pc);
// Native signature handlers
static void prepare_native_call(JavaThread* thread, methodOopDesc* method);
static address slow_signature_handler(JavaThread* thread,
methodOopDesc* method,
intptr_t* from, intptr_t* to);
#if defined(IA32) || defined(AMD64)
// Popframe support (only needed on x86 and AMD64)
static void popframe_move_outgoing_args(JavaThread* thread, void* src_address, void* dest_address);
#endif
// Platform dependent stuff
#include "incls/_interpreterRT_pd.hpp.incl"
// Interpreter's frequency counter overflow
static nmethod* frequency_counter_overflow(JavaThread* thread, address branch_bcp);
// Interpreter profiling support
static jint bcp_to_di(methodOopDesc* method, address cur_bcp);
static jint profile_method(JavaThread* thread, address cur_bcp);
static void update_mdp_for_ret(JavaThread* thread, int bci);
#ifdef ASSERT
static void verify_mdp(methodOopDesc* method, address bcp, address mdp);
#endif // ASSERT
};
class SignatureHandlerLibrary: public AllStatic {
public:
enum { buffer_size = 1*K }; // the size of the temporary code buffer
enum { blob_size = 32*K }; // the size of a handler code blob.
private:
static BufferBlob* _handler_blob; // the current buffer blob containing the generated handlers
static address _handler; // next available address within _handler_blob;
static GrowableArray<uint64_t>* _fingerprints; // the fingerprint collection
static GrowableArray<address>* _handlers; // the corresponding handlers
static address _buffer; // the temporary code buffer
static address set_handler_blob();
static void initialize();
static address set_handler(CodeBuffer* buffer);
static void pd_set_handler(address handler);
public:
static void add(methodHandle method);
};

View file

@ -0,0 +1,170 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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/_invocationCounter.cpp.incl"
// Implementation of InvocationCounter
void InvocationCounter::init() {
_counter = 0; // reset all the bits, including the sticky carry
reset();
}
void InvocationCounter::reset() {
// Only reset the state and don't make the method look like it's never
// been executed
set_state(wait_for_compile);
}
void InvocationCounter::set_carry() {
_counter |= carry_mask;
// The carry bit now indicates that this counter had achieved a very
// large value. Now reduce the value, so that the method can be
// executed many more times before re-entering the VM.
int old_count = count();
int new_count = MIN2(old_count, (int) (CompileThreshold / 2));
if (old_count != new_count) set(state(), new_count);
}
void InvocationCounter::set_state(State state) {
assert(0 <= state && state < number_of_states, "illegal state");
int init = _init[state];
// prevent from going to zero, to distinguish from never-executed methods
if (init == 0 && count() > 0) init = 1;
int carry = (_counter & carry_mask); // the carry bit is sticky
_counter = (init << number_of_noncount_bits) | carry | state;
}
void InvocationCounter::print() {
tty->print_cr("invocation count: up = %d, limit = %d, carry = %s, state = %s",
count(), limit(),
carry() ? "true" : "false",
state_as_string(state()));
}
void InvocationCounter::print_short() {
tty->print(" [%d%s;%s]", count(), carry()?"+carry":"", state_as_short_string(state()));
}
// Initialization
int InvocationCounter::_init [InvocationCounter::number_of_states];
InvocationCounter::Action InvocationCounter::_action[InvocationCounter::number_of_states];
int InvocationCounter::InterpreterInvocationLimit;
int InvocationCounter::InterpreterBackwardBranchLimit;
int InvocationCounter::InterpreterProfileLimit;
// Tier1 limits
int InvocationCounter::Tier1InvocationLimit;
int InvocationCounter::Tier1BackEdgeLimit;
const char* InvocationCounter::state_as_string(State state) {
switch (state) {
case wait_for_nothing : return "wait_for_nothing";
case wait_for_compile : return "wait_for_compile";
}
ShouldNotReachHere();
return NULL;
}
const char* InvocationCounter::state_as_short_string(State state) {
switch (state) {
case wait_for_nothing : return "not comp.";
case wait_for_compile : return "compileable";
}
ShouldNotReachHere();
return NULL;
}
static address do_nothing(methodHandle method, TRAPS) {
// dummy action for inactive invocation counters
method->invocation_counter()->set_carry();
method->invocation_counter()->set_state(InvocationCounter::wait_for_nothing);
return NULL;
}
static address do_decay(methodHandle method, TRAPS) {
// decay invocation counters so compilation gets delayed
method->invocation_counter()->decay();
return NULL;
}
void InvocationCounter::def(State state, int init, Action action) {
assert(0 <= state && state < number_of_states, "illegal state");
assert(0 <= init && init < count_limit, "initial value out of range");
_init [state] = init;
_action[state] = action;
}
address dummy_invocation_counter_overflow(methodHandle m, TRAPS) {
ShouldNotReachHere();
return NULL;
}
void InvocationCounter::reinitialize(bool delay_overflow) {
// define states
guarantee((int)number_of_states <= (int)state_limit, "adjust number_of_state_bits");
def(wait_for_nothing, 0, do_nothing);
if (delay_overflow) {
def(wait_for_compile, 0, do_decay);
} else {
def(wait_for_compile, 0, dummy_invocation_counter_overflow);
}
InterpreterInvocationLimit = CompileThreshold << number_of_noncount_bits;
InterpreterProfileLimit = ((CompileThreshold * InterpreterProfilePercentage) / 100)<< number_of_noncount_bits;
Tier1InvocationLimit = Tier2CompileThreshold << number_of_noncount_bits;
Tier1BackEdgeLimit = Tier2BackEdgeThreshold << number_of_noncount_bits;
// When methodData is collected, the backward branch limit is compared against a
// methodData counter, rather than an InvocationCounter. In the former case, we
// don't need the shift by number_of_noncount_bits, but we do need to adjust
// the factor by which we scale the threshold.
if (ProfileInterpreter) {
InterpreterBackwardBranchLimit = (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100;
} else {
InterpreterBackwardBranchLimit = ((CompileThreshold * OnStackReplacePercentage) / 100) << number_of_noncount_bits;
}
assert(0 <= InterpreterBackwardBranchLimit,
"OSR threshold should be non-negative");
assert(0 <= InterpreterProfileLimit &&
InterpreterProfileLimit <= InterpreterInvocationLimit,
"profile threshold should be less than the compilation threshold "
"and non-negative");
}
void invocationCounter_init() {
InvocationCounter::reinitialize(DelayCompilationDuringStartup);
}

View file

@ -0,0 +1,137 @@
/*
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// InvocationCounters are used to trigger actions when a limit (threshold) is reached.
// For different states, different limits and actions can be defined in the initialization
// routine of InvocationCounters.
//
// Implementation notes: For space reasons, state & counter are both encoded in one word,
// The state is encoded using some of the least significant bits, the counter is using the
// more significant bits. The counter is incremented before a method is activated and an
// action is triggered when when count() > limit().
class InvocationCounter VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
private: // bit no: |31 3| 2 | 1 0 |
unsigned int _counter; // format: [count|carry|state]
enum PrivateConstants {
number_of_state_bits = 2,
number_of_carry_bits = 1,
number_of_noncount_bits = number_of_state_bits + number_of_carry_bits,
number_of_count_bits = BitsPerInt - number_of_noncount_bits,
state_limit = nth_bit(number_of_state_bits),
count_grain = nth_bit(number_of_state_bits + number_of_carry_bits),
count_limit = nth_bit(number_of_count_bits - 1),
carry_mask = right_n_bits(number_of_carry_bits) << number_of_state_bits,
state_mask = right_n_bits(number_of_state_bits),
status_mask = right_n_bits(number_of_state_bits + number_of_carry_bits),
count_mask = ((int)(-1) ^ status_mask)
};
public:
static int InterpreterInvocationLimit; // CompileThreshold scaled for interpreter use
static int Tier1InvocationLimit; // CompileThreshold scaled for tier1 use
static int Tier1BackEdgeLimit; // BackEdgeThreshold scaled for tier1 use
static int InterpreterBackwardBranchLimit; // A separate threshold for on stack replacement
static int InterpreterProfileLimit; // Profiling threshold scaled for interpreter use
typedef address (*Action)(methodHandle method, TRAPS);
enum PublicConstants {
count_increment = count_grain, // use this value to increment the 32bit _counter word
count_mask_value = count_mask // use this value to mask the backedge counter
};
enum State {
wait_for_nothing, // do nothing when count() > limit()
wait_for_compile, // introduce nmethod when count() > limit()
number_of_states // must be <= state_limit
};
// Manipulation
void reset(); // sets state to wait state
void init(); // sets state into original state
void set_state(State state); // sets state and initializes counter correspondingly
inline void set(State state, int count); // sets state and counter
inline void decay(); // decay counter (divide by two)
void set_carry(); // set the sticky carry bit
// Accessors
State state() const { return (State)(_counter & state_mask); }
bool carry() const { return (_counter & carry_mask) != 0; }
int limit() const { return CompileThreshold; }
Action action() const { return _action[state()]; }
int count() const { return _counter >> number_of_noncount_bits; }
int get_InvocationLimit() const { return InterpreterInvocationLimit >> number_of_noncount_bits; }
int get_BackwardBranchLimit() const { return InterpreterBackwardBranchLimit >> number_of_noncount_bits; }
int get_ProfileLimit() const { return InterpreterProfileLimit >> number_of_noncount_bits; }
// Test counter using scaled limits like the asm interpreter would do rather than doing
// the shifts to normalize the counter.
bool reached_InvocationLimit() const { return _counter >= (unsigned int) InterpreterInvocationLimit; }
bool reached_BackwardBranchLimit() const { return _counter >= (unsigned int) InterpreterBackwardBranchLimit; }
// Do this just like asm interpreter does for max speed
bool reached_ProfileLimit(InvocationCounter *back_edge_count) const {
return (_counter && count_mask) + back_edge_count->_counter >= (unsigned int) InterpreterProfileLimit;
}
void increment() { _counter += count_increment; }
// Printing
void print();
void print_short();
// Miscellaneous
static ByteSize counter_offset() { return byte_offset_of(InvocationCounter, _counter); }
static void reinitialize(bool delay_overflow);
private:
static int _init [number_of_states]; // the counter limits
static Action _action[number_of_states]; // the actions
static void def(State state, int init, Action action);
static const char* state_as_string(State state);
static const char* state_as_short_string(State state);
};
inline void InvocationCounter::set(State state, int count) {
assert(0 <= state && state < number_of_states, "illegal state");
int carry = (_counter & carry_mask); // the carry bit is sticky
_counter = (count << number_of_noncount_bits) | carry | state;
}
inline void InvocationCounter::decay() {
int c = count();
int new_count = c >> 1;
// prevent from going to zero, to distinguish from never-executed methods
if (c > 0 && new_count == 0) new_count = 1;
set(state(), new_count);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,171 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// All the necessary definitions for run-time link resolution.
// LinkInfo & its subclasses provide all the information gathered
// for a particular link after resolving it. A link is any reference
// made from within the bytecodes of a method to an object outside of
// that method. If the info is invalid, the link has not been resolved
// successfully.
class LinkInfo VALUE_OBJ_CLASS_SPEC {
};
// Link information for getfield/putfield & getstatic/putstatic bytecodes.
class FieldAccessInfo: public LinkInfo {
protected:
KlassHandle _klass;
symbolHandle _name;
AccessFlags _access_flags;
int _field_index; // original index in the klass
int _field_offset;
BasicType _field_type;
public:
void set(KlassHandle klass, symbolHandle name, int field_index, int field_offset,
BasicType field_type, AccessFlags access_flags);
KlassHandle klass() const { return _klass; }
symbolHandle name() const { return _name; }
int field_index() const { return _field_index; }
int field_offset() const { return _field_offset; }
BasicType field_type() const { return _field_type; }
AccessFlags access_flags() const { return _access_flags; }
// debugging
void print() PRODUCT_RETURN;
};
// Link information for all calls.
class CallInfo: public LinkInfo {
private:
KlassHandle _resolved_klass; // static receiver klass
KlassHandle _selected_klass; // dynamic receiver class (same as static, or subklass)
methodHandle _resolved_method; // static target method
methodHandle _selected_method; // dynamic (actual) target method
int _vtable_index; // vtable index of selected method
void set_static( KlassHandle resolved_klass, methodHandle resolved_method , TRAPS);
void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method , TRAPS);
void set_virtual( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS);
void set_common( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS);
friend class LinkResolver;
public:
KlassHandle resolved_klass() const { return _resolved_klass; }
KlassHandle selected_klass() const { return _selected_klass; }
methodHandle resolved_method() const { return _resolved_method; }
methodHandle selected_method() const { return _selected_method; }
BasicType result_type() const { return selected_method()->result_type(); }
bool has_vtable_index() const { return _vtable_index >= 0; }
bool is_statically_bound() const { return _vtable_index == methodOopDesc::nonvirtual_vtable_index; }
int vtable_index() const {
// Even for interface calls the vtable index could be non-negative.
// See CallInfo::set_interface.
assert(has_vtable_index() || is_statically_bound(), "");
return _vtable_index;
}
};
// The LinkResolver is used to resolve constant-pool references at run-time.
// It does all necessary link-time checks & throws exceptions if necessary.
class LinkResolver: AllStatic {
private:
static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
static void lookup_method_in_interfaces (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
static int vtable_index_of_miranda_method(KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, TRAPS);
static void resolve_klass_no_update (KlassHandle& result, constantPoolHandle pool, int index, TRAPS); // no update of constantPool entry
static void resolve_pool (KlassHandle& resolved_klass, symbolHandle& method_name, symbolHandle& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS);
static void resolve_interface_method(methodHandle& resolved_method, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, TRAPS);
static void resolve_method (methodHandle& resolved_method, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, TRAPS);
static void linktime_resolve_static_method (methodHandle& resolved_method, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, TRAPS);
static void linktime_resolve_special_method (methodHandle& resolved_method, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, TRAPS);
static void linktime_resolve_virtual_method (methodHandle &resolved_method, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature,KlassHandle current_klass, bool check_access, TRAPS);
static void linktime_resolve_interface_method (methodHandle& resolved_method, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, TRAPS);
static void runtime_resolve_special_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, bool check_access, TRAPS);
static void runtime_resolve_virtual_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS);
static void runtime_resolve_interface_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS);
static void check_field_accessability (KlassHandle ref_klass, KlassHandle resolved_klass, KlassHandle sel_klass, fieldDescriptor& fd, TRAPS);
static void check_method_accessability (KlassHandle ref_klass, KlassHandle resolved_klass, KlassHandle sel_klass, methodHandle sel_method, TRAPS);
public:
// constant pool resolving
static void check_klass_accessability(KlassHandle ref_klass, KlassHandle sel_klass, TRAPS);
// static resolving for all calls except interface calls
static void resolve_method (methodHandle& method_result, KlassHandle& klass_result, constantPoolHandle pool, int index, TRAPS);
static void resolve_interface_method(methodHandle& method_result, KlassHandle& klass_result, constantPoolHandle pool, int index, TRAPS);
// runtime/static resolving for fields
static void resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, TRAPS);
// takes an extra bool argument "update_pool" to decide whether to update the constantPool during klass resolution.
static void resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, bool update_pool, TRAPS);
// runtime resolving:
// resolved_klass = specified class (i.e., static receiver class)
// current_klass = sending method holder (i.e., class containing the method containing the call being resolved)
static void resolve_static_call (CallInfo& result, KlassHandle& resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, bool initialize_klass, TRAPS);
static void resolve_special_call (CallInfo& result, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, TRAPS);
static void resolve_virtual_call (CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, bool check_null_and_abstract, TRAPS);
static void resolve_interface_call(CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, bool check_null_and_abstract, TRAPS);
// same as above for compile-time resolution; but returns null handle instead of throwing an exception on error
// also, does not initialize klass (i.e., no side effects)
static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass);
static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass);
static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass);
static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass);
// same as above for compile-time resolution; returns vtable_index if current_klass if linked
static int resolve_virtual_vtable_index (KlassHandle receiver_klass, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass);
// static resolving for compiler (does not throw exceptions, returns null handle if unsuccessful)
static methodHandle linktime_resolve_virtual_method_or_null (KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access);
static methodHandle linktime_resolve_interface_method_or_null(KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access);
// runtime resolving from constant pool
static void resolve_invokestatic (CallInfo& result, constantPoolHandle pool, int index, TRAPS);
static void resolve_invokespecial (CallInfo& result, constantPoolHandle pool, int index, TRAPS);
static void resolve_invokevirtual (CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS);
static void resolve_invokeinterface(CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS);
static void resolve_invoke (CallInfo& result, Handle recv, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS);
};

View file

@ -0,0 +1,643 @@
/*
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
* 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/_oopMapCache.cpp.incl"
class OopMapCacheEntry: private InterpreterOopMap {
friend class InterpreterOopMap;
friend class OopMapForCacheEntry;
friend class OopMapCache;
friend class VerifyClosure;
protected:
// Initialization
void fill(methodHandle method, int bci);
// fills the bit mask for native calls
void fill_for_native(methodHandle method);
void set_mask(CellTypeState* vars, CellTypeState* stack, int stack_top);
// Deallocate bit masks and initialize fields
void flush();
private:
void allocate_bit_mask(); // allocates the bit mask on C heap f necessary
void deallocate_bit_mask(); // allocates the bit mask on C heap f necessary
bool verify_mask(CellTypeState *vars, CellTypeState *stack, int max_locals, int stack_top);
public:
OopMapCacheEntry() : InterpreterOopMap() {
#ifdef ASSERT
_resource_allocate_bit_mask = false;
#endif
}
};
// Implementation of OopMapForCacheEntry
// (subclass of GenerateOopMap, initializes an OopMapCacheEntry for a given method and bci)
class OopMapForCacheEntry: public GenerateOopMap {
OopMapCacheEntry *_entry;
int _bci;
int _stack_top;
virtual bool report_results() const { return false; }
virtual bool possible_gc_point (BytecodeStream *bcs);
virtual void fill_stackmap_prolog (int nof_gc_points);
virtual void fill_stackmap_epilog ();
virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs,
CellTypeState* vars,
CellTypeState* stack,
int stack_top);
virtual void fill_init_vars (GrowableArray<intptr_t> *init_vars);
public:
OopMapForCacheEntry(methodHandle method, int bci, OopMapCacheEntry *entry);
// Computes stack map for (method,bci) and initialize entry
void compute_map(TRAPS);
int size();
};
OopMapForCacheEntry::OopMapForCacheEntry(methodHandle method, int bci, OopMapCacheEntry* entry) : GenerateOopMap(method) {
_bci = bci;
_entry = entry;
_stack_top = -1;
}
void OopMapForCacheEntry::compute_map(TRAPS) {
assert(!method()->is_native(), "cannot compute oop map for native methods");
// First check if it is a method where the stackmap is always empty
if (method()->code_size() == 0 || method()->max_locals() + method()->max_stack() == 0) {
_entry->set_mask_size(0);
} else {
ResourceMark rm;
GenerateOopMap::compute_map(CATCH);
result_for_basicblock(_bci);
}
}
bool OopMapForCacheEntry::possible_gc_point(BytecodeStream *bcs) {
return false; // We are not reporting any result. We call result_for_basicblock directly
}
void OopMapForCacheEntry::fill_stackmap_prolog(int nof_gc_points) {
// Do nothing
}
void OopMapForCacheEntry::fill_stackmap_epilog() {
// Do nothing
}
void OopMapForCacheEntry::fill_init_vars(GrowableArray<intptr_t> *init_vars) {
// Do nothing
}
void OopMapForCacheEntry::fill_stackmap_for_opcodes(BytecodeStream *bcs,
CellTypeState* vars,
CellTypeState* stack,
int stack_top) {
// Only interested in one specific bci
if (bcs->bci() == _bci) {
_entry->set_mask(vars, stack, stack_top);
_stack_top = stack_top;
}
}
int OopMapForCacheEntry::size() {
assert(_stack_top != -1, "compute_map must be called first");
return ((method()->is_static()) ? 0 : 1) + method()->max_locals() + _stack_top;
}
// Implementation of InterpreterOopMap and OopMapCacheEntry
class VerifyClosure : public OffsetClosure {
private:
OopMapCacheEntry* _entry;
bool _failed;
public:
VerifyClosure(OopMapCacheEntry* entry) { _entry = entry; _failed = false; }
void offset_do(int offset) { if (!_entry->is_oop(offset)) _failed = true; }
bool failed() const { return _failed; }
};
InterpreterOopMap::InterpreterOopMap() {
initialize();
#ifdef ASSERT
_resource_allocate_bit_mask = true;
#endif
}
InterpreterOopMap::~InterpreterOopMap() {
// The expection is that the bit mask was allocated
// last in this resource area. That would make the free of the
// bit_mask effective (see how FREE_RESOURCE_ARRAY does a free).
// If it was not allocated last, there is not a correctness problem
// but the space for the bit_mask is not freed.
assert(_resource_allocate_bit_mask, "Trying to free C heap space");
if (mask_size() > small_mask_limit) {
FREE_RESOURCE_ARRAY(uintptr_t, _bit_mask[0], mask_word_size());
}
}
bool InterpreterOopMap::is_empty() {
bool result = _method == NULL;
assert(_method != NULL || (_bci == 0 &&
(_mask_size == 0 || _mask_size == USHRT_MAX) &&
_bit_mask[0] == 0), "Should be completely empty");
return result;
}
void InterpreterOopMap::initialize() {
_method = NULL;
_mask_size = USHRT_MAX; // This value should cause a failure quickly
_bci = 0;
_expression_stack_size = 0;
for (int i = 0; i < N; i++) _bit_mask[i] = 0;
}
void InterpreterOopMap::oop_iterate(OopClosure *blk) {
if (method() != NULL) {
blk->do_oop((oop*) &_method);
}
}
void InterpreterOopMap::oop_iterate(OopClosure *blk, MemRegion mr) {
if (method() != NULL && mr.contains(&_method)) {
blk->do_oop((oop*) &_method);
}
}
void InterpreterOopMap::iterate_oop(OffsetClosure* oop_closure) {
int n = number_of_entries();
int word_index = 0;
uintptr_t value = 0;
uintptr_t mask = 0;
// iterate over entries
for (int i = 0; i < n; i++, mask <<= bits_per_entry) {
// get current word
if (mask == 0) {
value = bit_mask()[word_index++];
mask = 1;
}
// test for oop
if ((value & (mask << oop_bit_number)) != 0) oop_closure->offset_do(i);
}
}
void InterpreterOopMap::verify() {
// If we are doing mark sweep _method may not have a valid header
// $$$ This used to happen only for m/s collections; we might want to
// think of an appropriate generalization of this distinction.
guarantee(Universe::heap()->is_gc_active() ||
_method->is_oop_or_null(), "invalid oop in oopMapCache")
}
#ifdef ENABLE_ZAP_DEAD_LOCALS
void InterpreterOopMap::iterate_all(OffsetClosure* oop_closure, OffsetClosure* value_closure, OffsetClosure* dead_closure) {
int n = number_of_entries();
int word_index = 0;
uintptr_t value = 0;
uintptr_t mask = 0;
// iterate over entries
for (int i = 0; i < n; i++, mask <<= bits_per_entry) {
// get current word
if (mask == 0) {
value = bit_mask()[word_index++];
mask = 1;
}
// test for dead values & oops, and for live values
if ((value & (mask << dead_bit_number)) != 0) dead_closure->offset_do(i); // call this for all dead values or oops
else if ((value & (mask << oop_bit_number)) != 0) oop_closure->offset_do(i); // call this for all live oops
else value_closure->offset_do(i); // call this for all live values
}
}
#endif
void InterpreterOopMap::print() {
int n = number_of_entries();
tty->print("oop map for ");
method()->print_value();
tty->print(" @ %d = [%d] { ", bci(), n);
for (int i = 0; i < n; i++) {
#ifdef ENABLE_ZAP_DEAD_LOCALS
if (is_dead(i)) tty->print("%d+ ", i);
else
#endif
if (is_oop(i)) tty->print("%d ", i);
}
tty->print_cr("}");
}
class MaskFillerForNative: public NativeSignatureIterator {
private:
uintptr_t * _mask; // the bit mask to be filled
int _size; // the mask size in bits
void set_one(int i) {
i *= InterpreterOopMap::bits_per_entry;
assert(0 <= i && i < _size, "offset out of bounds");
_mask[i / BitsPerWord] |= (((uintptr_t) 1 << InterpreterOopMap::oop_bit_number) << (i % BitsPerWord));
}
public:
void pass_int() { /* ignore */ }
void pass_long() { /* ignore */ }
#ifdef _LP64
void pass_float() { /* ignore */ }
#endif
void pass_double() { /* ignore */ }
void pass_object() { set_one(offset()); }
MaskFillerForNative(methodHandle method, uintptr_t* mask, int size) : NativeSignatureIterator(method) {
_mask = mask;
_size = size;
// initialize with 0
int i = (size + BitsPerWord - 1) / BitsPerWord;
while (i-- > 0) _mask[i] = 0;
}
void generate() {
NativeSignatureIterator::iterate();
}
};
bool OopMapCacheEntry::verify_mask(CellTypeState* vars, CellTypeState* stack, int max_locals, int stack_top) {
// Check mask includes map
VerifyClosure blk(this);
iterate_oop(&blk);
if (blk.failed()) return false;
// Check if map is generated correctly
// (Use ?: operator to make sure all 'true' & 'false' are represented exactly the same so we can use == afterwards)
if (TraceOopMapGeneration && Verbose) tty->print("Locals (%d): ", max_locals);
for(int i = 0; i < max_locals; i++) {
bool v1 = is_oop(i) ? true : false;
bool v2 = vars[i].is_reference() ? true : false;
assert(v1 == v2, "locals oop mask generation error");
if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0);
#ifdef ENABLE_ZAP_DEAD_LOCALS
bool v3 = is_dead(i) ? true : false;
bool v4 = !vars[i].is_live() ? true : false;
assert(v3 == v4, "locals live mask generation error");
assert(!(v1 && v3), "dead value marked as oop");
#endif
}
if (TraceOopMapGeneration && Verbose) { tty->cr(); tty->print("Stack (%d): ", stack_top); }
for(int j = 0; j < stack_top; j++) {
bool v1 = is_oop(max_locals + j) ? true : false;
bool v2 = stack[j].is_reference() ? true : false;
assert(v1 == v2, "stack oop mask generation error");
if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0);
#ifdef ENABLE_ZAP_DEAD_LOCALS
bool v3 = is_dead(max_locals + j) ? true : false;
bool v4 = !stack[j].is_live() ? true : false;
assert(v3 == v4, "stack live mask generation error");
assert(!(v1 && v3), "dead value marked as oop");
#endif
}
if (TraceOopMapGeneration && Verbose) tty->cr();
return true;
}
void OopMapCacheEntry::allocate_bit_mask() {
if (mask_size() > small_mask_limit) {
assert(_bit_mask[0] == 0, "bit mask should be new or just flushed");
_bit_mask[0] = (intptr_t)
NEW_C_HEAP_ARRAY(uintptr_t, mask_word_size());
}
}
void OopMapCacheEntry::deallocate_bit_mask() {
if (mask_size() > small_mask_limit && _bit_mask[0] != 0) {
assert(!Thread::current()->resource_area()->contains((void*)_bit_mask[0]),
"This bit mask should not be in the resource area");
FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]);
debug_only(_bit_mask[0] = 0;)
}
}
void OopMapCacheEntry::fill_for_native(methodHandle mh) {
assert(mh->is_native(), "method must be native method");
set_mask_size(mh->size_of_parameters() * bits_per_entry);
allocate_bit_mask();
// fill mask for parameters
MaskFillerForNative mf(mh, bit_mask(), mask_size());
mf.generate();
}
void OopMapCacheEntry::fill(methodHandle method, int bci) {
HandleMark hm;
// Flush entry to deallocate an existing entry
flush();
set_method(method());
set_bci(bci);
if (method->is_native()) {
// Native method activations have oops only among the parameters and one
// extra oop following the parameters (the mirror for static native methods).
fill_for_native(method);
} else {
EXCEPTION_MARK;
OopMapForCacheEntry gen(method, bci, this);
gen.compute_map(CATCH);
}
#ifdef ASSERT
verify();
#endif
}
void OopMapCacheEntry::set_mask(CellTypeState *vars, CellTypeState *stack, int stack_top) {
// compute bit mask size
int max_locals = method()->max_locals();
int n_entries = max_locals + stack_top;
set_mask_size(n_entries * bits_per_entry);
allocate_bit_mask();
set_expression_stack_size(stack_top);
// compute bits
int word_index = 0;
uintptr_t value = 0;
uintptr_t mask = 1;
CellTypeState* cell = vars;
for (int entry_index = 0; entry_index < n_entries; entry_index++, mask <<= bits_per_entry, cell++) {
// store last word
if (mask == 0) {
bit_mask()[word_index++] = value;
value = 0;
mask = 1;
}
// switch to stack when done with locals
if (entry_index == max_locals) {
cell = stack;
}
// set oop bit
if ( cell->is_reference()) {
value |= (mask << oop_bit_number );
}
#ifdef ENABLE_ZAP_DEAD_LOCALS
// set dead bit
if (!cell->is_live()) {
value |= (mask << dead_bit_number);
assert(!cell->is_reference(), "dead value marked as oop");
}
#endif
}
// make sure last word is stored
bit_mask()[word_index] = value;
// verify bit mask
assert(verify_mask(vars, stack, max_locals, stack_top), "mask could not be verified");
}
void OopMapCacheEntry::flush() {
deallocate_bit_mask();
initialize();
}
// Implementation of OopMapCache
#ifndef PRODUCT
static long _total_memory_usage = 0;
long OopMapCache::memory_usage() {
return _total_memory_usage;
}
#endif
void InterpreterOopMap::resource_copy(OopMapCacheEntry* from) {
assert(_resource_allocate_bit_mask,
"Should not resource allocate the _bit_mask");
assert(from->method()->is_oop(), "MethodOop is bad");
set_method(from->method());
set_bci(from->bci());
set_mask_size(from->mask_size());
set_expression_stack_size(from->expression_stack_size());
// Is the bit mask contained in the entry?
if (from->mask_size() <= small_mask_limit) {
memcpy((void *)_bit_mask, (void *)from->_bit_mask,
mask_word_size() * BytesPerWord);
} else {
// The expectation is that this InterpreterOopMap is a recently created
// and empty. It is used to get a copy of a cached entry.
// If the bit mask has a value, it should be in the
// resource area.
assert(_bit_mask[0] == 0 ||
Thread::current()->resource_area()->contains((void*)_bit_mask[0]),
"The bit mask should have been allocated from a resource area");
// Allocate the bit_mask from a Resource area for performance. Allocating
// from the C heap as is done for OopMapCache has a significant
// performance impact.
_bit_mask[0] = (uintptr_t) NEW_RESOURCE_ARRAY(uintptr_t, mask_word_size());
assert(_bit_mask[0] != 0, "bit mask was not allocated");
memcpy((void*) _bit_mask[0], (void*) from->_bit_mask[0],
mask_word_size() * BytesPerWord);
}
}
inline unsigned int OopMapCache::hash_value_for(methodHandle method, int bci) {
// We use method->code_size() rather than method->identity_hash() below since
// the mark may not be present if a pointer to the method is already reversed.
return ((unsigned int) bci)
^ ((unsigned int) method->max_locals() << 2)
^ ((unsigned int) method->code_size() << 4)
^ ((unsigned int) method->size_of_parameters() << 6);
}
OopMapCache::OopMapCache() :
_mut(Mutex::leaf, "An OopMapCache lock", true)
{
_array = NEW_C_HEAP_ARRAY(OopMapCacheEntry, _size);
// Cannot call flush for initialization, since flush
// will check if memory should be deallocated
for(int i = 0; i < _size; i++) _array[i].initialize();
NOT_PRODUCT(_total_memory_usage += sizeof(OopMapCache) + (sizeof(OopMapCacheEntry) * _size);)
}
OopMapCache::~OopMapCache() {
assert(_array != NULL, "sanity check");
// Deallocate oop maps that are allocated out-of-line
flush();
// Deallocate array
NOT_PRODUCT(_total_memory_usage -= sizeof(OopMapCache) + (sizeof(OopMapCacheEntry) * _size);)
FREE_C_HEAP_ARRAY(OopMapCacheEntry, _array);
}
OopMapCacheEntry* OopMapCache::entry_at(int i) const {
return &_array[i % _size];
}
void OopMapCache::flush() {
for (int i = 0; i < _size; i++) _array[i].flush();
}
void OopMapCache::flush_obsolete_entries() {
for (int i = 0; i < _size; i++)
if (!_array[i].is_empty() && _array[i].method()->is_old()) {
// Cache entry is occupied by an old redefined method and we don't want
// to pin it down so flush the entry.
_array[i].flush();
}
}
void OopMapCache::oop_iterate(OopClosure *blk) {
for (int i = 0; i < _size; i++) _array[i].oop_iterate(blk);
}
void OopMapCache::oop_iterate(OopClosure *blk, MemRegion mr) {
for (int i = 0; i < _size; i++) _array[i].oop_iterate(blk, mr);
}
void OopMapCache::verify() {
for (int i = 0; i < _size; i++) _array[i].verify();
}
void OopMapCache::lookup(methodHandle method,
int bci,
InterpreterOopMap* entry_for) {
MutexLocker x(&_mut);
OopMapCacheEntry* entry = NULL;
int probe = hash_value_for(method, bci);
// Search hashtable for match
int i;
for(i = 0; i < _probe_depth; i++) {
entry = entry_at(probe + i);
if (entry->match(method, bci)) {
entry_for->resource_copy(entry);
assert(!entry_for->is_empty(), "A non-empty oop map should be returned");
return;
}
}
if (TraceOopMapGeneration) {
static int count = 0;
ResourceMark rm;
tty->print("%d - Computing oopmap at bci %d for ", ++count, bci);
method->print_value(); tty->cr();
}
// Entry is not in hashtable.
// Compute entry and return it
// First search for an empty slot
for(i = 0; i < _probe_depth; i++) {
entry = entry_at(probe + i);
if (entry->is_empty()) {
entry->fill(method, bci);
entry_for->resource_copy(entry);
assert(!entry_for->is_empty(), "A non-empty oop map should be returned");
if (method->is_old()) {
// The caller of lookup() will receive a copy of the interesting
// info via entry_for, but we don't keep an old redefined method in
// the cache to avoid pinning down the method.
entry->flush();
}
return;
}
}
if (TraceOopMapGeneration) {
ResourceMark rm;
tty->print_cr("*** collision in oopmap cache - flushing item ***");
}
// No empty slot (uncommon case). Use (some approximation of a) LRU algorithm
//entry_at(probe + _probe_depth - 1)->flush();
//for(i = _probe_depth - 1; i > 0; i--) {
// // Coping entry[i] = entry[i-1];
// OopMapCacheEntry *to = entry_at(probe + i);
// OopMapCacheEntry *from = entry_at(probe + i - 1);
// to->copy(from);
// }
assert(method->is_method(), "gaga");
entry = entry_at(probe + 0);
entry->fill(method, bci);
// Copy the newly cached entry to input parameter
entry_for->resource_copy(entry);
if (TraceOopMapGeneration) {
ResourceMark rm;
tty->print("Done with ");
method->print_value(); tty->cr();
}
assert(!entry_for->is_empty(), "A non-empty oop map should be returned");
if (method->is_old()) {
// The caller of lookup() will receive a copy of the interesting
// info via entry_for, but we don't keep an old redefined method in
// the cache to avoid pinning down the method.
entry->flush();
}
return;
}
void OopMapCache::compute_one_oop_map(methodHandle method, int bci, InterpreterOopMap* entry) {
// Due to the invariants above it's tricky to allocate a temporary OopMapCacheEntry on the stack
OopMapCacheEntry* tmp = NEW_C_HEAP_ARRAY(OopMapCacheEntry, 1);
tmp->initialize();
tmp->fill(method, bci);
entry->resource_copy(tmp);
FREE_C_HEAP_ARRAY(OopMapCacheEntry, tmp);
}

View file

@ -0,0 +1,190 @@
/*
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// A Cache for storing (method, bci) -> oopMap.
// The memory management system uses the cache when locating object
// references in an interpreted frame.
//
// OopMapCache's are allocated lazily per instanceKlass.
// The oopMap (InterpreterOopMap) is stored as a bit mask. If the
// bit_mask can fit into two words it is stored in
// the _bit_mask array, otherwise it is allocated on the heap.
// For OopMapCacheEntry the bit_mask is allocated in the C heap
// because these entries persist between garbage collections.
// For InterpreterOopMap the bit_mask is allocated in
// a resource area for better performance. InterpreterOopMap
// should only be created and deleted during same garbage collection.
//
// If ENABBLE_ZAP_DEAD_LOCALS is defined, two bits are used
// per entry instead of one. In all cases,
// the first bit is set to indicate oops as opposed to other
// values. If the second bit is available,
// it is set for dead values. We get the following encoding:
//
// 00 live value
// 01 live oop
// 10 dead value
// 11 <unused> (we cannot distinguish between dead oops or values with the current oop map generator)
class OffsetClosure {
public:
virtual void offset_do(int offset) = 0;
};
class InterpreterOopMap: ResourceObj {
friend class OopMapCache;
public:
enum {
N = 2, // the number of words reserved
// for inlined mask storage
small_mask_limit = N * BitsPerWord, // the maximum number of bits
// available for small masks,
// small_mask_limit can be set to 0
// for testing bit_mask allocation
#ifdef ENABLE_ZAP_DEAD_LOCALS
bits_per_entry = 2,
dead_bit_number = 1,
#else
bits_per_entry = 1,
#endif
oop_bit_number = 0
};
private:
methodOop _method; // the method for which the mask is valid
unsigned short _bci; // the bci for which the mask is valid
int _mask_size; // the mask size in bits
int _expression_stack_size; // the size of the expression stack in slots
protected:
intptr_t _bit_mask[N]; // the bit mask if
// mask_size <= small_mask_limit,
// ptr to bit mask otherwise
// "protected" so that sub classes can
// access it without using trickery in
// methd bit_mask().
#ifdef ASSERT
bool _resource_allocate_bit_mask;
#endif
// access methods
methodOop method() const { return _method; }
void set_method(methodOop v) { _method = v; }
int bci() const { return _bci; }
void set_bci(int v) { _bci = v; }
int mask_size() const { return _mask_size; }
void set_mask_size(int v) { _mask_size = v; }
int number_of_entries() const { return mask_size() / bits_per_entry; }
// Test bit mask size and return either the in-line bit mask or allocated
// bit mask.
uintptr_t* bit_mask() { return (uintptr_t*)(mask_size() <= small_mask_limit ? (intptr_t)_bit_mask : _bit_mask[0]); }
// return the word size of_bit_mask. mask_size() <= 4 * MAX_USHORT
size_t mask_word_size() {
return (mask_size() + BitsPerWord - 1) / BitsPerWord;
}
uintptr_t entry_at(int offset) { int i = offset * bits_per_entry; return bit_mask()[i / BitsPerWord] >> (i % BitsPerWord); }
void set_expression_stack_size(int sz) { _expression_stack_size = sz; }
#ifdef ENABLE_ZAP_DEAD_LOCALS
bool is_dead(int offset) { return (entry_at(offset) & (1 << dead_bit_number)) != 0; }
#endif
// Lookup
bool match(methodHandle method, int bci) { return _method == method() && _bci == bci; }
bool is_empty();
// Initialization
void initialize();
public:
InterpreterOopMap();
~InterpreterOopMap();
// Copy the OopMapCacheEntry in parameter "from" into this
// InterpreterOopMap. If the _bit_mask[0] in "from" points to
// allocated space (i.e., the bit mask was to large to hold
// in-line), allocate the space from a Resource area.
void resource_copy(OopMapCacheEntry* from);
void iterate_oop(OffsetClosure* oop_closure);
void oop_iterate(OopClosure * blk);
void oop_iterate(OopClosure * blk, MemRegion mr);
void verify();
void print();
bool is_oop (int offset) { return (entry_at(offset) & (1 << oop_bit_number )) != 0; }
int expression_stack_size() { return _expression_stack_size; }
#ifdef ENABLE_ZAP_DEAD_LOCALS
void iterate_all(OffsetClosure* oop_closure, OffsetClosure* value_closure, OffsetClosure* dead_closure);
#endif
};
class OopMapCache : public CHeapObj {
private:
enum { _size = 32, // Use fixed size for now
_probe_depth = 3 // probe depth in case of collisions
};
OopMapCacheEntry* _array;
unsigned int hash_value_for(methodHandle method, int bci);
OopMapCacheEntry* entry_at(int i) const;
Mutex _mut;
void flush();
public:
OopMapCache();
~OopMapCache(); // free up memory
// flush cache entry is occupied by an obsolete method
void flush_obsolete_entries();
// Returns the oopMap for (method, bci) in parameter "entry".
// Returns false if an oop map was not found.
void lookup(methodHandle method, int bci, InterpreterOopMap* entry);
// Compute an oop map without updating the cache or grabbing any locks (for debugging)
static void compute_one_oop_map(methodHandle method, int bci, InterpreterOopMap* entry);
// Helpers
// Iterate over the entries in the cached OopMapCacheEntry's
void oop_iterate(OopClosure *blk);
void oop_iterate(OopClosure *blk, MemRegion mr);
void verify();
// Returns total no. of bytes allocated as part of OopMapCache's
static long memory_usage() PRODUCT_RETURN0;
};

View file

@ -0,0 +1,246 @@
/*
* Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved.
* 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/_rewriter.cpp.incl"
// Computes an index_map (new_index -> original_index) for contant pool entries
// that are referred to by the interpreter at runtime via the constant pool cache.
void Rewriter::compute_index_maps(constantPoolHandle pool, intArray*& index_map, intStack*& inverse_index_map) {
const int length = pool->length();
index_map = new intArray(length, -1);
// Choose an initial value large enough that we don't get frequent
// calls to grow().
inverse_index_map = new intStack(length / 2);
for (int i = 0; i < length; i++) {
switch (pool->tag_at(i).value()) {
case JVM_CONSTANT_Fieldref : // fall through
case JVM_CONSTANT_Methodref : // fall through
case JVM_CONSTANT_InterfaceMethodref: {
index_map->at_put(i, inverse_index_map->length());
inverse_index_map->append(i);
}
}
}
}
// Creates a constant pool cache given an inverse_index_map
constantPoolCacheHandle Rewriter::new_constant_pool_cache(intArray& inverse_index_map, TRAPS) {
const int length = inverse_index_map.length();
constantPoolCacheOop cache = oopFactory::new_constantPoolCache(length, CHECK_(constantPoolCacheHandle()));
cache->initialize(inverse_index_map);
return constantPoolCacheHandle(THREAD, cache);
}
// The new finalization semantics says that registration of
// finalizable objects must be performed on successful return from the
// Object.<init> constructor. We could implement this trivially if
// <init> were never rewritten but since JVMTI allows this to occur, a
// more complicated solution is required. A special return bytecode
// is used only by Object.<init> to signal the finalization
// registration point. Additionally local 0 must be preserved so it's
// available to pass to the registration function. For simplicty we
// require that local 0 is never overwritten so it's available as an
// argument for registration.
void Rewriter::rewrite_Object_init(methodHandle method, TRAPS) {
RawBytecodeStream bcs(method);
while (!bcs.is_last_bytecode()) {
Bytecodes::Code opcode = bcs.raw_next();
switch (opcode) {
case Bytecodes::_return: *bcs.bcp() = Bytecodes::_return_register_finalizer; break;
case Bytecodes::_istore:
case Bytecodes::_lstore:
case Bytecodes::_fstore:
case Bytecodes::_dstore:
case Bytecodes::_astore:
if (bcs.get_index() != 0) continue;
// fall through
case Bytecodes::_istore_0:
case Bytecodes::_lstore_0:
case Bytecodes::_fstore_0:
case Bytecodes::_dstore_0:
case Bytecodes::_astore_0:
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(),
"can't overwrite local 0 in Object.<init>");
break;
}
}
}
// Rewrites a method given the index_map information
methodHandle Rewriter::rewrite_method(methodHandle method, intArray& index_map, TRAPS) {
int nof_jsrs = 0;
bool has_monitor_bytecodes = false;
{
// We cannot tolerate a GC in this block, because we've
// cached the bytecodes in 'code_base'. If the methodOop
// moves, the bytecodes will also move.
No_Safepoint_Verifier nsv;
Bytecodes::Code c;
// Bytecodes and their length
const address code_base = method->code_base();
const int code_length = method->code_size();
int bc_length;
for (int bci = 0; bci < code_length; bci += bc_length) {
address bcp = code_base + bci;
c = (Bytecodes::Code)(*bcp);
// Since we have the code, see if we can get the length
// directly. Some more complicated bytecodes will report
// a length of zero, meaning we need to make another method
// call to calculate the length.
bc_length = Bytecodes::length_for(c);
if (bc_length == 0) {
bc_length = Bytecodes::length_at(bcp);
// length_at will put us at the bytecode after the one modified
// by 'wide'. We don't currently examine any of the bytecodes
// modified by wide, but in case we do in the future...
if (c == Bytecodes::_wide) {
c = (Bytecodes::Code)bcp[1];
}
}
assert(bc_length != 0, "impossible bytecode length");
switch (c) {
case Bytecodes::_lookupswitch : {
#ifndef CC_INTERP
Bytecode_lookupswitch* bc = Bytecode_lookupswitch_at(bcp);
bc->set_code(
bc->number_of_pairs() < BinarySwitchThreshold
? Bytecodes::_fast_linearswitch
: Bytecodes::_fast_binaryswitch
);
#endif
break;
}
case Bytecodes::_getstatic : // fall through
case Bytecodes::_putstatic : // fall through
case Bytecodes::_getfield : // fall through
case Bytecodes::_putfield : // fall through
case Bytecodes::_invokevirtual : // fall through
case Bytecodes::_invokespecial : // fall through
case Bytecodes::_invokestatic : // fall through
case Bytecodes::_invokeinterface: {
address p = bcp + 1;
Bytes::put_native_u2(p, index_map[Bytes::get_Java_u2(p)]);
break;
}
case Bytecodes::_jsr : // fall through
case Bytecodes::_jsr_w : nof_jsrs++; break;
case Bytecodes::_monitorenter : // fall through
case Bytecodes::_monitorexit : has_monitor_bytecodes = true; break;
}
}
}
// Update access flags
if (has_monitor_bytecodes) {
method->set_has_monitor_bytecodes();
}
// The present of a jsr bytecode implies that the method might potentially
// have to be rewritten, so we run the oopMapGenerator on the method
if (nof_jsrs > 0) {
method->set_has_jsrs();
ResolveOopMapConflicts romc(method);
methodHandle original_method = method;
method = romc.do_potential_rewrite(CHECK_(methodHandle()));
if (method() != original_method()) {
// Insert invalid bytecode into original methodOop and set
// interpreter entrypoint, so that a executing this method
// will manifest itself in an easy recognizable form.
address bcp = original_method->bcp_from(0);
*bcp = (u1)Bytecodes::_shouldnotreachhere;
int kind = Interpreter::method_kind(original_method);
original_method->set_interpreter_kind(kind);
}
// Update monitor matching info.
if (romc.monitor_safe()) {
method->set_guaranteed_monitor_matching();
}
}
// Setup method entrypoints for compiler and interpreter
method->link_method(method, CHECK_(methodHandle()));
return method;
}
void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) {
// gather starting points
ResourceMark rm(THREAD);
constantPoolHandle pool (THREAD, klass->constants());
objArrayHandle methods (THREAD, klass->methods());
assert(pool->cache() == NULL, "constant pool cache must not be set yet");
// determine index maps for methodOop rewriting
intArray* index_map = NULL;
intStack* inverse_index_map = NULL;
compute_index_maps(pool, index_map, inverse_index_map);
// allocate constant pool cache
constantPoolCacheHandle cache = new_constant_pool_cache(*inverse_index_map, CHECK);
pool->set_cache(cache());
cache->set_constant_pool(pool());
if (RegisterFinalizersAtInit && klass->name() == vmSymbols::java_lang_Object()) {
int i = methods->length();
while (i-- > 0) {
methodOop method = (methodOop)methods->obj_at(i);
if (method->intrinsic_id() == vmIntrinsics::_Object_init) {
// rewrite the return bytecodes of Object.<init> to register the
// object for finalization if needed.
methodHandle m(THREAD, method);
rewrite_Object_init(m, CHECK);
break;
}
}
}
// rewrite methods
{ int i = methods->length();
while (i-- > 0) {
methodHandle m(THREAD, (methodOop)methods->obj_at(i));
m = rewrite_method(m, *index_map, CHECK);
// Method might have gotten rewritten.
methods->obj_at_put(i, m());
}
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// The Rewriter adds caches to the constant pool and rewrites bytecode indices
// pointing into the constant pool for better interpreter performance.
class Rewriter: public AllStatic {
private:
static void compute_index_maps(constantPoolHandle pool, intArray*& index_map, intStack*& inverse_index_map);
static constantPoolCacheHandle new_constant_pool_cache(intArray& inverse_index_map, TRAPS);
static methodHandle rewrite_method(methodHandle method, intArray& index_map, TRAPS);
static void rewrite_Object_init(methodHandle method, TRAPS);
public:
static void rewrite(instanceKlassHandle klass, TRAPS);
};

View file

@ -0,0 +1,597 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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/_templateInterpreter.cpp.incl"
#ifndef CC_INTERP
# define __ _masm->
void TemplateInterpreter::initialize() {
if (_code != NULL) return;
// assertions
assert((int)Bytecodes::number_of_codes <= (int)DispatchTable::length,
"dispatch table too small");
AbstractInterpreter::initialize();
TemplateTable::initialize();
// generate interpreter
{ ResourceMark rm;
TraceTime timer("Interpreter generation", TraceStartupTime);
int code_size = InterpreterCodeSize;
NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space
_code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
"Interpreter");
InterpreterGenerator g(_code);
if (PrintInterpreter) print();
}
// initialize dispatch table
_active_table = _normal_table;
}
//------------------------------------------------------------------------------------------------------------------------
// Implementation of EntryPoint
EntryPoint::EntryPoint() {
assert(number_of_states == 9, "check the code below");
_entry[btos] = NULL;
_entry[ctos] = NULL;
_entry[stos] = NULL;
_entry[atos] = NULL;
_entry[itos] = NULL;
_entry[ltos] = NULL;
_entry[ftos] = NULL;
_entry[dtos] = NULL;
_entry[vtos] = NULL;
}
EntryPoint::EntryPoint(address bentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry) {
assert(number_of_states == 9, "check the code below");
_entry[btos] = bentry;
_entry[ctos] = centry;
_entry[stos] = sentry;
_entry[atos] = aentry;
_entry[itos] = ientry;
_entry[ltos] = lentry;
_entry[ftos] = fentry;
_entry[dtos] = dentry;
_entry[vtos] = ventry;
}
void EntryPoint::set_entry(TosState state, address entry) {
assert(0 <= state && state < number_of_states, "state out of bounds");
_entry[state] = entry;
}
address EntryPoint::entry(TosState state) const {
assert(0 <= state && state < number_of_states, "state out of bounds");
return _entry[state];
}
void EntryPoint::print() {
tty->print("[");
for (int i = 0; i < number_of_states; i++) {
if (i > 0) tty->print(", ");
tty->print(INTPTR_FORMAT, _entry[i]);
}
tty->print("]");
}
bool EntryPoint::operator == (const EntryPoint& y) {
int i = number_of_states;
while (i-- > 0) {
if (_entry[i] != y._entry[i]) return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------
// Implementation of DispatchTable
EntryPoint DispatchTable::entry(int i) const {
assert(0 <= i && i < length, "index out of bounds");
return
EntryPoint(
_table[btos][i],
_table[ctos][i],
_table[stos][i],
_table[atos][i],
_table[itos][i],
_table[ltos][i],
_table[ftos][i],
_table[dtos][i],
_table[vtos][i]
);
}
void DispatchTable::set_entry(int i, EntryPoint& entry) {
assert(0 <= i && i < length, "index out of bounds");
assert(number_of_states == 9, "check the code below");
_table[btos][i] = entry.entry(btos);
_table[ctos][i] = entry.entry(ctos);
_table[stos][i] = entry.entry(stos);
_table[atos][i] = entry.entry(atos);
_table[itos][i] = entry.entry(itos);
_table[ltos][i] = entry.entry(ltos);
_table[ftos][i] = entry.entry(ftos);
_table[dtos][i] = entry.entry(dtos);
_table[vtos][i] = entry.entry(vtos);
}
bool DispatchTable::operator == (DispatchTable& y) {
int i = length;
while (i-- > 0) {
EntryPoint t = y.entry(i); // for compiler compatibility (BugId 4150096)
if (!(entry(i) == t)) return false;
}
return true;
}
address TemplateInterpreter::_remove_activation_entry = NULL;
address TemplateInterpreter::_remove_activation_preserving_args_entry = NULL;
address TemplateInterpreter::_throw_ArrayIndexOutOfBoundsException_entry = NULL;
address TemplateInterpreter::_throw_ArrayStoreException_entry = NULL;
address TemplateInterpreter::_throw_ArithmeticException_entry = NULL;
address TemplateInterpreter::_throw_ClassCastException_entry = NULL;
address TemplateInterpreter::_throw_NullPointerException_entry = NULL;
address TemplateInterpreter::_throw_StackOverflowError_entry = NULL;
address TemplateInterpreter::_throw_exception_entry = NULL;
#ifndef PRODUCT
EntryPoint TemplateInterpreter::_trace_code;
#endif // !PRODUCT
EntryPoint TemplateInterpreter::_return_entry[TemplateInterpreter::number_of_return_entries];
EntryPoint TemplateInterpreter::_earlyret_entry;
EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deopt_entries ];
EntryPoint TemplateInterpreter::_continuation_entry;
EntryPoint TemplateInterpreter::_safept_entry;
address TemplateInterpreter::_return_3_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
address TemplateInterpreter::_return_5_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
DispatchTable TemplateInterpreter::_active_table;
DispatchTable TemplateInterpreter::_normal_table;
DispatchTable TemplateInterpreter::_safept_table;
address TemplateInterpreter::_wentry_point[DispatchTable::length];
TemplateInterpreterGenerator::TemplateInterpreterGenerator(StubQueue* _code): AbstractInterpreterGenerator(_code) {
_unimplemented_bytecode = NULL;
_illegal_bytecode_sequence = NULL;
}
static const BasicType types[Interpreter::number_of_result_handlers] = {
T_BOOLEAN,
T_CHAR ,
T_BYTE ,
T_SHORT ,
T_INT ,
T_LONG ,
T_VOID ,
T_FLOAT ,
T_DOUBLE ,
T_OBJECT
};
void TemplateInterpreterGenerator::generate_all() {
AbstractInterpreterGenerator::generate_all();
{ CodeletMark cm(_masm, "error exits");
_unimplemented_bytecode = generate_error_exit("unimplemented bytecode");
_illegal_bytecode_sequence = generate_error_exit("illegal bytecode sequence - method not verified");
}
#ifndef PRODUCT
if (TraceBytecodes) {
CodeletMark cm(_masm, "bytecode tracing support");
Interpreter::_trace_code =
EntryPoint(
generate_trace_code(btos),
generate_trace_code(ctos),
generate_trace_code(stos),
generate_trace_code(atos),
generate_trace_code(itos),
generate_trace_code(ltos),
generate_trace_code(ftos),
generate_trace_code(dtos),
generate_trace_code(vtos)
);
}
#endif // !PRODUCT
{ CodeletMark cm(_masm, "return entry points");
for (int i = 0; i < Interpreter::number_of_return_entries; i++) {
Interpreter::_return_entry[i] =
EntryPoint(
generate_return_entry_for(itos, i),
generate_return_entry_for(itos, i),
generate_return_entry_for(itos, i),
generate_return_entry_for(atos, i),
generate_return_entry_for(itos, i),
generate_return_entry_for(ltos, i),
generate_return_entry_for(ftos, i),
generate_return_entry_for(dtos, i),
generate_return_entry_for(vtos, i)
);
}
}
{ CodeletMark cm(_masm, "earlyret entry points");
Interpreter::_earlyret_entry =
EntryPoint(
generate_earlyret_entry_for(btos),
generate_earlyret_entry_for(ctos),
generate_earlyret_entry_for(stos),
generate_earlyret_entry_for(atos),
generate_earlyret_entry_for(itos),
generate_earlyret_entry_for(ltos),
generate_earlyret_entry_for(ftos),
generate_earlyret_entry_for(dtos),
generate_earlyret_entry_for(vtos)
);
}
{ CodeletMark cm(_masm, "deoptimization entry points");
for (int i = 0; i < Interpreter::number_of_deopt_entries; i++) {
Interpreter::_deopt_entry[i] =
EntryPoint(
generate_deopt_entry_for(itos, i),
generate_deopt_entry_for(itos, i),
generate_deopt_entry_for(itos, i),
generate_deopt_entry_for(atos, i),
generate_deopt_entry_for(itos, i),
generate_deopt_entry_for(ltos, i),
generate_deopt_entry_for(ftos, i),
generate_deopt_entry_for(dtos, i),
generate_deopt_entry_for(vtos, i)
);
}
}
{ CodeletMark cm(_masm, "result handlers for native calls");
// The various result converter stublets.
int is_generated[Interpreter::number_of_result_handlers];
memset(is_generated, 0, sizeof(is_generated));
for (int i = 0; i < Interpreter::number_of_result_handlers; i++) {
BasicType type = types[i];
if (!is_generated[Interpreter::BasicType_as_index(type)]++) {
Interpreter::_native_abi_to_tosca[Interpreter::BasicType_as_index(type)] = generate_result_handler_for(type);
}
}
}
for (int j = 0; j < number_of_states; j++) {
const TosState states[] = {btos, ctos, stos, itos, ltos, ftos, dtos, atos, vtos};
Interpreter::_return_3_addrs_by_index[Interpreter::TosState_as_index(states[j])] = Interpreter::return_entry(states[j], 3);
Interpreter::_return_5_addrs_by_index[Interpreter::TosState_as_index(states[j])] = Interpreter::return_entry(states[j], 5);
}
{ CodeletMark cm(_masm, "continuation entry points");
Interpreter::_continuation_entry =
EntryPoint(
generate_continuation_for(btos),
generate_continuation_for(ctos),
generate_continuation_for(stos),
generate_continuation_for(atos),
generate_continuation_for(itos),
generate_continuation_for(ltos),
generate_continuation_for(ftos),
generate_continuation_for(dtos),
generate_continuation_for(vtos)
);
}
{ CodeletMark cm(_masm, "safepoint entry points");
Interpreter::_safept_entry =
EntryPoint(
generate_safept_entry_for(btos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
generate_safept_entry_for(ctos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
generate_safept_entry_for(stos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
generate_safept_entry_for(atos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
generate_safept_entry_for(itos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
generate_safept_entry_for(ltos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
generate_safept_entry_for(ftos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
generate_safept_entry_for(dtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
generate_safept_entry_for(vtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint))
);
}
{ CodeletMark cm(_masm, "exception handling");
// (Note: this is not safepoint safe because thread may return to compiled code)
generate_throw_exception();
}
{ CodeletMark cm(_masm, "throw exception entrypoints");
Interpreter::_throw_ArrayIndexOutOfBoundsException_entry = generate_ArrayIndexOutOfBounds_handler("java/lang/ArrayIndexOutOfBoundsException");
Interpreter::_throw_ArrayStoreException_entry = generate_klass_exception_handler("java/lang/ArrayStoreException" );
Interpreter::_throw_ArithmeticException_entry = generate_exception_handler("java/lang/ArithmeticException" , "/ by zero");
Interpreter::_throw_ClassCastException_entry = generate_ClassCastException_handler();
Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException" , NULL );
Interpreter::_throw_StackOverflowError_entry = generate_StackOverflowError_handler();
}
#define method_entry(kind) \
{ CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \
Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \
}
// all non-native method kinds
method_entry(zerolocals)
method_entry(zerolocals_synchronized)
method_entry(empty)
method_entry(accessor)
method_entry(abstract)
method_entry(java_lang_math_sin )
method_entry(java_lang_math_cos )
method_entry(java_lang_math_tan )
method_entry(java_lang_math_abs )
method_entry(java_lang_math_sqrt )
method_entry(java_lang_math_log )
method_entry(java_lang_math_log10)
// all native method kinds (must be one contiguous block)
Interpreter::_native_entry_begin = Interpreter::code()->code_end();
method_entry(native)
method_entry(native_synchronized)
Interpreter::_native_entry_end = Interpreter::code()->code_end();
#undef method_entry
// Bytecodes
set_entry_points_for_all_bytes();
set_safepoints_for_all_bytes();
}
//------------------------------------------------------------------------------------------------------------------------
address TemplateInterpreterGenerator::generate_error_exit(const char* msg) {
address entry = __ pc();
__ stop(msg);
return entry;
}
//------------------------------------------------------------------------------------------------------------------------
void TemplateInterpreterGenerator::set_entry_points_for_all_bytes() {
for (int i = 0; i < DispatchTable::length; i++) {
Bytecodes::Code code = (Bytecodes::Code)i;
if (Bytecodes::is_defined(code)) {
set_entry_points(code);
} else {
set_unimplemented(i);
}
}
}
void TemplateInterpreterGenerator::set_safepoints_for_all_bytes() {
for (int i = 0; i < DispatchTable::length; i++) {
Bytecodes::Code code = (Bytecodes::Code)i;
if (Bytecodes::is_defined(code)) Interpreter::_safept_table.set_entry(code, Interpreter::_safept_entry);
}
}
void TemplateInterpreterGenerator::set_unimplemented(int i) {
address e = _unimplemented_bytecode;
EntryPoint entry(e, e, e, e, e, e, e, e, e);
Interpreter::_normal_table.set_entry(i, entry);
Interpreter::_wentry_point[i] = _unimplemented_bytecode;
}
void TemplateInterpreterGenerator::set_entry_points(Bytecodes::Code code) {
CodeletMark cm(_masm, Bytecodes::name(code), code);
// initialize entry points
assert(_unimplemented_bytecode != NULL, "should have been generated before");
assert(_illegal_bytecode_sequence != NULL, "should have been generated before");
address bep = _illegal_bytecode_sequence;
address cep = _illegal_bytecode_sequence;
address sep = _illegal_bytecode_sequence;
address aep = _illegal_bytecode_sequence;
address iep = _illegal_bytecode_sequence;
address lep = _illegal_bytecode_sequence;
address fep = _illegal_bytecode_sequence;
address dep = _illegal_bytecode_sequence;
address vep = _unimplemented_bytecode;
address wep = _unimplemented_bytecode;
// code for short & wide version of bytecode
if (Bytecodes::is_defined(code)) {
Template* t = TemplateTable::template_for(code);
assert(t->is_valid(), "just checking");
set_short_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, vep);
}
if (Bytecodes::wide_is_defined(code)) {
Template* t = TemplateTable::template_for_wide(code);
assert(t->is_valid(), "just checking");
set_wide_entry_point(t, wep);
}
// set entry points
EntryPoint entry(bep, cep, sep, aep, iep, lep, fep, dep, vep);
Interpreter::_normal_table.set_entry(code, entry);
Interpreter::_wentry_point[code] = wep;
}
void TemplateInterpreterGenerator::set_wide_entry_point(Template* t, address& wep) {
assert(t->is_valid(), "template must exist");
assert(t->tos_in() == vtos, "only vtos tos_in supported for wide instructions")
wep = __ pc(); generate_and_dispatch(t);
}
void TemplateInterpreterGenerator::set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) {
assert(t->is_valid(), "template must exist");
switch (t->tos_in()) {
case btos: vep = __ pc(); __ pop(btos); bep = __ pc(); generate_and_dispatch(t); break;
case ctos: vep = __ pc(); __ pop(ctos); sep = __ pc(); generate_and_dispatch(t); break;
case stos: vep = __ pc(); __ pop(stos); sep = __ pc(); generate_and_dispatch(t); break;
case atos: vep = __ pc(); __ pop(atos); aep = __ pc(); generate_and_dispatch(t); break;
case itos: vep = __ pc(); __ pop(itos); iep = __ pc(); generate_and_dispatch(t); break;
case ltos: vep = __ pc(); __ pop(ltos); lep = __ pc(); generate_and_dispatch(t); break;
case ftos: vep = __ pc(); __ pop(ftos); fep = __ pc(); generate_and_dispatch(t); break;
case dtos: vep = __ pc(); __ pop(dtos); dep = __ pc(); generate_and_dispatch(t); break;
case vtos: set_vtos_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, vep); break;
default : ShouldNotReachHere(); break;
}
}
//------------------------------------------------------------------------------------------------------------------------
void TemplateInterpreterGenerator::generate_and_dispatch(Template* t, TosState tos_out) {
if (PrintBytecodeHistogram) histogram_bytecode(t);
#ifndef PRODUCT
// debugging code
if (CountBytecodes || TraceBytecodes || StopInterpreterAt > 0) count_bytecode();
if (PrintBytecodePairHistogram) histogram_bytecode_pair(t);
if (TraceBytecodes) trace_bytecode(t);
if (StopInterpreterAt > 0) stop_interpreter_at();
__ verify_FPU(1, t->tos_in());
#endif // !PRODUCT
int step;
if (!t->does_dispatch()) {
step = t->is_wide() ? Bytecodes::wide_length_for(t->bytecode()) : Bytecodes::length_for(t->bytecode());
if (tos_out == ilgl) tos_out = t->tos_out();
// compute bytecode size
assert(step > 0, "just checkin'");
// setup stuff for dispatching next bytecode
if (ProfileInterpreter && VerifyDataPointer
&& methodDataOopDesc::bytecode_has_profile(t->bytecode())) {
__ verify_method_data_pointer();
}
__ dispatch_prolog(tos_out, step);
}
// generate template
t->generate(_masm);
// advance
if (t->does_dispatch()) {
#ifdef ASSERT
// make sure execution doesn't go beyond this point if code is broken
__ should_not_reach_here();
#endif // ASSERT
} else {
// dispatch to next bytecode
__ dispatch_epilog(tos_out, step);
}
}
//------------------------------------------------------------------------------------------------------------------------
// Entry points
address TemplateInterpreter::return_entry(TosState state, int length) {
guarantee(0 <= length && length < Interpreter::number_of_return_entries, "illegal length");
return _return_entry[length].entry(state);
}
address TemplateInterpreter::deopt_entry(TosState state, int length) {
guarantee(0 <= length && length < Interpreter::number_of_deopt_entries, "illegal length");
return _deopt_entry[length].entry(state);
}
//------------------------------------------------------------------------------------------------------------------------
// Suport for invokes
int TemplateInterpreter::TosState_as_index(TosState state) {
assert( state < number_of_states , "Invalid state in TosState_as_index");
assert(0 <= (int)state && (int)state < TemplateInterpreter::number_of_return_addrs, "index out of bounds");
return (int)state;
}
//------------------------------------------------------------------------------------------------------------------------
// Safepoint suppport
static inline void copy_table(address* from, address* to, int size) {
// Copy non-overlapping tables. The copy has to occur word wise for MT safety.
while (size-- > 0) *to++ = *from++;
}
void TemplateInterpreter::notice_safepoints() {
if (!_notice_safepoints) {
// switch to safepoint dispatch table
_notice_safepoints = true;
copy_table((address*)&_safept_table, (address*)&_active_table, sizeof(_active_table) / sizeof(address));
}
}
// switch from the dispatch table which notices safepoints back to the
// normal dispatch table. So that we can notice single stepping points,
// keep the safepoint dispatch table if we are single stepping in JVMTI.
// Note that the should_post_single_step test is exactly as fast as the
// JvmtiExport::_enabled test and covers both cases.
void TemplateInterpreter::ignore_safepoints() {
if (_notice_safepoints) {
if (!JvmtiExport::should_post_single_step()) {
// switch to normal dispatch table
_notice_safepoints = false;
copy_table((address*)&_normal_table, (address*)&_active_table, sizeof(_active_table) / sizeof(address));
}
}
}
// If deoptimization happens, this method returns the point where to continue in
// interpreter. For calls (invokexxxx, newxxxx) the continuation is at next
// bci and the top of stack is in eax/edx/FPU tos.
// For putfield/getfield, put/getstatic, the continuation is at the same
// bci and the TOS is on stack.
// Note: deopt_entry(type, 0) means reexecute bytecode
// deopt_entry(type, length) means continue at next bytecode
address TemplateInterpreter::continuation_for(methodOop method, address bcp, int callee_parameters, bool is_top_frame, bool& use_next_mdp) {
assert(method->contains(bcp), "just checkin'");
Bytecodes::Code code = Bytecodes::java_code_at(bcp);
if (code == Bytecodes::_return) {
// This is used for deopt during registration of finalizers
// during Object.<init>. We simply need to resume execution at
// the standard return vtos bytecode to pop the frame normally.
// reexecuting the real bytecode would cause double registration
// of the finalizable object.
assert(is_top_frame, "must be on top");
return _normal_table.entry(Bytecodes::_return).entry(vtos);
} else {
return AbstractInterpreter::continuation_for(method, bcp, callee_parameters, is_top_frame, use_next_mdp);
}
}
#endif // !CC_INTERP

View file

@ -0,0 +1,177 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// This file contains the platform-independant parts
// of the template interpreter and the template interpreter generator.
#ifndef CC_INTERP
//------------------------------------------------------------------------------------------------------------------------
// A little wrapper class to group tosca-specific entry points into a unit.
// (tosca = Top-Of-Stack CAche)
class EntryPoint VALUE_OBJ_CLASS_SPEC {
private:
address _entry[number_of_states];
public:
// Construction
EntryPoint();
EntryPoint(address bentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry);
// Attributes
address entry(TosState state) const; // return target address for a given tosca state
void set_entry(TosState state, address entry); // set target address for a given tosca state
void print();
// Comparison
bool operator == (const EntryPoint& y); // for debugging only
};
//------------------------------------------------------------------------------------------------------------------------
// A little wrapper class to group tosca-specific dispatch tables into a unit.
class DispatchTable VALUE_OBJ_CLASS_SPEC {
public:
enum { length = 1 << BitsPerByte }; // an entry point for each byte value (also for undefined bytecodes)
private:
address _table[number_of_states][length]; // dispatch tables, indexed by tosca and bytecode
public:
// Attributes
EntryPoint entry(int i) const; // return entry point for a given bytecode i
void set_entry(int i, EntryPoint& entry); // set entry point for a given bytecode i
address* table_for(TosState state) { return _table[state]; }
address* table_for() { return table_for((TosState)0); }
int distance_from(address *table) { return table - table_for(); }
int distance_from(TosState state) { return distance_from(table_for(state)); }
// Comparison
bool operator == (DispatchTable& y); // for debugging only
};
class TemplateInterpreter: public AbstractInterpreter {
friend class VMStructs;
friend class InterpreterMacroAssembler;
friend class TemplateInterpreterGenerator;
friend class TemplateTable;
// friend class Interpreter;
public:
enum MoreConstants {
number_of_return_entries = 9, // number of return entry points
number_of_deopt_entries = 9, // number of deoptimization entry points
number_of_return_addrs = 9 // number of return addresses
};
protected:
static address _throw_ArrayIndexOutOfBoundsException_entry;
static address _throw_ArrayStoreException_entry;
static address _throw_ArithmeticException_entry;
static address _throw_ClassCastException_entry;
static address _throw_NullPointerException_entry;
static address _throw_exception_entry;
static address _throw_StackOverflowError_entry;
static address _remove_activation_entry; // continuation address if an exception is not handled by current frame
#ifdef HOTSWAP
static address _remove_activation_preserving_args_entry; // continuation address when current frame is being popped
#endif // HOTSWAP
#ifndef PRODUCT
static EntryPoint _trace_code;
#endif // !PRODUCT
static EntryPoint _return_entry[number_of_return_entries]; // entry points to return to from a call
static EntryPoint _earlyret_entry; // entry point to return early from a call
static EntryPoint _deopt_entry[number_of_deopt_entries]; // entry points to return to from a deoptimization
static EntryPoint _continuation_entry;
static EntryPoint _safept_entry;
static address _return_3_addrs_by_index[number_of_return_addrs]; // for invokevirtual return entries
static address _return_5_addrs_by_index[number_of_return_addrs]; // for invokeinterface return entries
static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch)
static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode)
static DispatchTable _safept_table; // the safepoint dispatch table (used to set the active table for safepoints)
static address _wentry_point[DispatchTable::length]; // wide instructions only (vtos tosca always)
public:
// Initialization/debugging
static void initialize();
// this only returns whether a pc is within generated code for the interpreter.
static bool contains(address pc) { return _code != NULL && _code->contains(pc); }
public:
static address remove_activation_early_entry(TosState state) { return _earlyret_entry.entry(state); }
#ifdef HOTSWAP
static address remove_activation_preserving_args_entry() { return _remove_activation_preserving_args_entry; }
#endif // HOTSWAP
static address remove_activation_entry() { return _remove_activation_entry; }
static address throw_exception_entry() { return _throw_exception_entry; }
static address throw_ArithmeticException_entry() { return _throw_ArithmeticException_entry; }
static address throw_NullPointerException_entry() { return _throw_NullPointerException_entry; }
static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; }
// Code generation
#ifndef PRODUCT
static address trace_code (TosState state) { return _trace_code.entry(state); }
#endif // !PRODUCT
static address continuation (TosState state) { return _continuation_entry.entry(state); }
static address* dispatch_table(TosState state) { return _active_table.table_for(state); }
static address* dispatch_table() { return _active_table.table_for(); }
static int distance_from_dispatch_table(TosState state){ return _active_table.distance_from(state); }
static address* normal_table(TosState state) { return _normal_table.table_for(state); }
static address* normal_table() { return _normal_table.table_for(); }
// Support for invokes
static address* return_3_addrs_by_index_table() { return _return_3_addrs_by_index; }
static address* return_5_addrs_by_index_table() { return _return_5_addrs_by_index; }
static int TosState_as_index(TosState state); // computes index into return_3_entry_by_index table
static address return_entry (TosState state, int length);
static address deopt_entry (TosState state, int length);
// Safepoint support
static void notice_safepoints(); // stops the thread when reaching a safepoint
static void ignore_safepoints(); // ignores safepoints
// Deoptimization support
static address continuation_for(methodOop method,
address bcp,
int callee_parameters,
bool is_top_frame,
bool& use_next_mdp);
#include "incls/_templateInterpreter_pd.hpp.incl"
};
#endif // !CC_INTERP

View file

@ -0,0 +1,90 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
// This file contains the platform-independant parts
// of the template interpreter generator.
#ifndef CC_INTERP
class TemplateInterpreterGenerator: public AbstractInterpreterGenerator {
protected:
// entry points for shared code sequence
address _unimplemented_bytecode;
address _illegal_bytecode_sequence;
// shared code sequences
// Converter for native abi result to tosca result
address generate_result_handler_for(BasicType type);
address generate_slow_signature_handler();
address generate_error_exit(const char* msg);
address generate_StackOverflowError_handler();
address generate_exception_handler(const char* name, const char* message) {
return generate_exception_handler_common(name, message, false);
}
address generate_klass_exception_handler(const char* name) {
return generate_exception_handler_common(name, NULL, true);
}
address generate_exception_handler_common(const char* name, const char* message, bool pass_oop);
address generate_ClassCastException_handler();
address generate_ArrayIndexOutOfBounds_handler(const char* name);
address generate_continuation_for(TosState state);
address generate_return_entry_for(TosState state, int step);
address generate_earlyret_entry_for(TosState state);
address generate_deopt_entry_for(TosState state, int step);
address generate_safept_entry_for(TosState state, address runtime_entry);
void generate_throw_exception();
// entry point generator
// address generate_method_entry(AbstractInterpreter::MethodKind kind);
// Instruction generation
void generate_and_dispatch (Template* t, TosState tos_out = ilgl);
void set_vtos_entry_points (Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep);
void set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep);
void set_wide_entry_point (Template* t, address& wep);
void set_entry_points(Bytecodes::Code code);
void set_unimplemented(int i);
void set_entry_points_for_all_bytes();
void set_safepoints_for_all_bytes();
// Helpers for generate_and_dispatch
address generate_trace_code(TosState state) PRODUCT_RETURN0;
void count_bytecode() PRODUCT_RETURN;
void histogram_bytecode(Template* t) PRODUCT_RETURN;
void histogram_bytecode_pair(Template* t) PRODUCT_RETURN;
void trace_bytecode(Template* t) PRODUCT_RETURN;
void stop_interpreter_at() PRODUCT_RETURN;
void generate_all();
public:
TemplateInterpreterGenerator(StubQueue* _code);
#include "incls/_templateInterpreterGenerator_pd.hpp.incl"
};
#endif // !CC_INTERP

View file

@ -0,0 +1,538 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* 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/_templateTable.cpp.incl"
#ifdef CC_INTERP
void templateTable_init() {
}
#else
//----------------------------------------------------------------------------------------------------
// Implementation of Template
void Template::initialize(int flags, TosState tos_in, TosState tos_out, generator gen, int arg) {
_flags = flags;
_tos_in = tos_in;
_tos_out = tos_out;
_gen = gen;
_arg = arg;
}
Bytecodes::Code Template::bytecode() const {
int i = this - TemplateTable::_template_table;
if (i < 0 || i >= Bytecodes::number_of_codes) i = this - TemplateTable::_template_table_wide;
return Bytecodes::cast(i);
}
void Template::generate(InterpreterMacroAssembler* masm) {
// parameter passing
TemplateTable::_desc = this;
TemplateTable::_masm = masm;
// code generation
_gen(_arg);
masm->flush();
}
//----------------------------------------------------------------------------------------------------
// Implementation of TemplateTable: Platform-independent helper routines
void TemplateTable::call_VM(Register oop_result, address entry_point) {
assert(_desc->calls_vm(), "inconsistent calls_vm information");
_masm->call_VM(oop_result, entry_point);
}
void TemplateTable::call_VM(Register oop_result, address entry_point, Register arg_1) {
assert(_desc->calls_vm(), "inconsistent calls_vm information");
_masm->call_VM(oop_result, entry_point, arg_1);
}
void TemplateTable::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2) {
assert(_desc->calls_vm(), "inconsistent calls_vm information");
_masm->call_VM(oop_result, entry_point, arg_1, arg_2);
}
void TemplateTable::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3) {
assert(_desc->calls_vm(), "inconsistent calls_vm information");
_masm->call_VM(oop_result, entry_point, arg_1, arg_2, arg_3);
}
void TemplateTable::call_VM(Register oop_result, Register last_java_sp, address entry_point) {
assert(_desc->calls_vm(), "inconsistent calls_vm information");
_masm->call_VM(oop_result, last_java_sp, entry_point);
}
void TemplateTable::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1) {
assert(_desc->calls_vm(), "inconsistent calls_vm information");
_masm->call_VM(oop_result, last_java_sp, entry_point, arg_1);
}
void TemplateTable::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2) {
assert(_desc->calls_vm(), "inconsistent calls_vm information");
_masm->call_VM(oop_result, last_java_sp, entry_point, arg_1, arg_2);
}
void TemplateTable::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3) {
assert(_desc->calls_vm(), "inconsistent calls_vm information");
_masm->call_VM(oop_result, last_java_sp, entry_point, arg_1, arg_2, arg_3);
}
//----------------------------------------------------------------------------------------------------
// Implementation of TemplateTable: Platform-independent bytecodes
void TemplateTable::float_cmp(int unordered_result) {
transition(ftos, itos);
float_cmp(true, unordered_result);
}
void TemplateTable::double_cmp(int unordered_result) {
transition(dtos, itos);
float_cmp(false, unordered_result);
}
void TemplateTable::_goto() {
transition(vtos, vtos);
branch(false, false);
}
void TemplateTable::goto_w() {
transition(vtos, vtos);
branch(false, true);
}
void TemplateTable::jsr_w() {
transition(vtos, vtos); // result is not an oop, so do not transition to atos
branch(true, true);
}
void TemplateTable::jsr() {
transition(vtos, vtos); // result is not an oop, so do not transition to atos
branch(true, false);
}
//----------------------------------------------------------------------------------------------------
// Implementation of TemplateTable: Debugging
void TemplateTable::transition(TosState tos_in, TosState tos_out) {
assert(_desc->tos_in() == tos_in , "inconsistent tos_in information");
assert(_desc->tos_out() == tos_out, "inconsistent tos_out information");
}
//----------------------------------------------------------------------------------------------------
// Implementation of TemplateTable: Initialization
bool TemplateTable::_is_initialized = false;
Template TemplateTable::_template_table [Bytecodes::number_of_codes];
Template TemplateTable::_template_table_wide[Bytecodes::number_of_codes];
Template* TemplateTable::_desc;
InterpreterMacroAssembler* TemplateTable::_masm;
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(), char filler) {
assert(filler == ' ', "just checkin'");
def(code, flags, in, out, (Template::generator)gen, 0);
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(int arg), int arg) {
// should factor out these constants
const int ubcp = 1 << Template::uses_bcp_bit;
const int disp = 1 << Template::does_dispatch_bit;
const int clvm = 1 << Template::calls_vm_bit;
const int iswd = 1 << Template::wide_bit;
// determine which table to use
bool is_wide = (flags & iswd) != 0;
// make sure that wide instructions have a vtos entry point
// (since they are executed extremely rarely, it doesn't pay out to have an
// extra set of 5 dispatch tables for the wide instructions - for simplicity
// they all go with one table)
assert(in == vtos || !is_wide, "wide instructions have vtos entry point only");
Template* t = is_wide ? template_for_wide(code) : template_for(code);
// setup entry
t->initialize(flags, in, out, gen, arg);
assert(t->bytecode() == code, "just checkin'");
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(Operation op), Operation op) {
def(code, flags, in, out, (Template::generator)gen, (int)op);
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(bool arg ), bool arg) {
def(code, flags, in, out, (Template::generator)gen, (int)arg);
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(TosState tos), TosState tos) {
def(code, flags, in, out, (Template::generator)gen, (int)tos);
}
void TemplateTable::def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(Condition cc), Condition cc) {
def(code, flags, in, out, (Template::generator)gen, (int)cc);
}
#if defined(TEMPLATE_TABLE_BUG)
//
// It appears that gcc (version 2.91) generates bad code for the template
// table init if this macro is not defined. My symptom was an assertion
// assert(Universe::heap()->is_in(obj), "sanity check") in handles.cpp line 24.
// when called from interpreterRuntime.resolve_invoke().
//
#define iload TemplateTable::iload
#define lload TemplateTable::lload
#define fload TemplateTable::fload
#define dload TemplateTable::dload
#define aload TemplateTable::aload
#define istore TemplateTable::istore
#define lstore TemplateTable::lstore
#define fstore TemplateTable::fstore
#define dstore TemplateTable::dstore
#define astore TemplateTable::astore
#endif // TEMPLATE_TABLE_BUG
void TemplateTable::initialize() {
if (_is_initialized) return;
// Initialize table
TraceTime timer("TemplateTable initialization", TraceStartupTime);
// For better readability
const char _ = ' ';
const int ____ = 0;
const int ubcp = 1 << Template::uses_bcp_bit;
const int disp = 1 << Template::does_dispatch_bit;
const int clvm = 1 << Template::calls_vm_bit;
const int iswd = 1 << Template::wide_bit;
// interpr. templates
// Java spec bytecodes ubcp|disp|clvm|iswd in out generator argument
def(Bytecodes::_nop , ____|____|____|____, vtos, vtos, nop , _ );
def(Bytecodes::_aconst_null , ____|____|____|____, vtos, atos, aconst_null , _ );
def(Bytecodes::_iconst_m1 , ____|____|____|____, vtos, itos, iconst , -1 );
def(Bytecodes::_iconst_0 , ____|____|____|____, vtos, itos, iconst , 0 );
def(Bytecodes::_iconst_1 , ____|____|____|____, vtos, itos, iconst , 1 );
def(Bytecodes::_iconst_2 , ____|____|____|____, vtos, itos, iconst , 2 );
def(Bytecodes::_iconst_3 , ____|____|____|____, vtos, itos, iconst , 3 );
def(Bytecodes::_iconst_4 , ____|____|____|____, vtos, itos, iconst , 4 );
def(Bytecodes::_iconst_5 , ____|____|____|____, vtos, itos, iconst , 5 );
def(Bytecodes::_lconst_0 , ____|____|____|____, vtos, ltos, lconst , 0 );
def(Bytecodes::_lconst_1 , ____|____|____|____, vtos, ltos, lconst , 1 );
def(Bytecodes::_fconst_0 , ____|____|____|____, vtos, ftos, fconst , 0 );
def(Bytecodes::_fconst_1 , ____|____|____|____, vtos, ftos, fconst , 1 );
def(Bytecodes::_fconst_2 , ____|____|____|____, vtos, ftos, fconst , 2 );
def(Bytecodes::_dconst_0 , ____|____|____|____, vtos, dtos, dconst , 0 );
def(Bytecodes::_dconst_1 , ____|____|____|____, vtos, dtos, dconst , 1 );
def(Bytecodes::_bipush , ubcp|____|____|____, vtos, itos, bipush , _ );
def(Bytecodes::_sipush , ubcp|____|____|____, vtos, itos, sipush , _ );
def(Bytecodes::_ldc , ubcp|____|clvm|____, vtos, vtos, ldc , false );
def(Bytecodes::_ldc_w , ubcp|____|clvm|____, vtos, vtos, ldc , true );
def(Bytecodes::_ldc2_w , ubcp|____|____|____, vtos, vtos, ldc2_w , _ );
def(Bytecodes::_iload , ubcp|____|clvm|____, vtos, itos, iload , _ );
def(Bytecodes::_lload , ubcp|____|____|____, vtos, ltos, lload , _ );
def(Bytecodes::_fload , ubcp|____|____|____, vtos, ftos, fload , _ );
def(Bytecodes::_dload , ubcp|____|____|____, vtos, dtos, dload , _ );
def(Bytecodes::_aload , ubcp|____|clvm|____, vtos, atos, aload , _ );
def(Bytecodes::_iload_0 , ____|____|____|____, vtos, itos, iload , 0 );
def(Bytecodes::_iload_1 , ____|____|____|____, vtos, itos, iload , 1 );
def(Bytecodes::_iload_2 , ____|____|____|____, vtos, itos, iload , 2 );
def(Bytecodes::_iload_3 , ____|____|____|____, vtos, itos, iload , 3 );
def(Bytecodes::_lload_0 , ____|____|____|____, vtos, ltos, lload , 0 );
def(Bytecodes::_lload_1 , ____|____|____|____, vtos, ltos, lload , 1 );
def(Bytecodes::_lload_2 , ____|____|____|____, vtos, ltos, lload , 2 );
def(Bytecodes::_lload_3 , ____|____|____|____, vtos, ltos, lload , 3 );
def(Bytecodes::_fload_0 , ____|____|____|____, vtos, ftos, fload , 0 );
def(Bytecodes::_fload_1 , ____|____|____|____, vtos, ftos, fload , 1 );
def(Bytecodes::_fload_2 , ____|____|____|____, vtos, ftos, fload , 2 );
def(Bytecodes::_fload_3 , ____|____|____|____, vtos, ftos, fload , 3 );
def(Bytecodes::_dload_0 , ____|____|____|____, vtos, dtos, dload , 0 );
def(Bytecodes::_dload_1 , ____|____|____|____, vtos, dtos, dload , 1 );
def(Bytecodes::_dload_2 , ____|____|____|____, vtos, dtos, dload , 2 );
def(Bytecodes::_dload_3 , ____|____|____|____, vtos, dtos, dload , 3 );
def(Bytecodes::_aload_0 , ubcp|____|clvm|____, vtos, atos, aload_0 , _ );
def(Bytecodes::_aload_1 , ____|____|____|____, vtos, atos, aload , 1 );
def(Bytecodes::_aload_2 , ____|____|____|____, vtos, atos, aload , 2 );
def(Bytecodes::_aload_3 , ____|____|____|____, vtos, atos, aload , 3 );
def(Bytecodes::_iaload , ____|____|____|____, itos, itos, iaload , _ );
def(Bytecodes::_laload , ____|____|____|____, itos, ltos, laload , _ );
def(Bytecodes::_faload , ____|____|____|____, itos, ftos, faload , _ );
def(Bytecodes::_daload , ____|____|____|____, itos, dtos, daload , _ );
def(Bytecodes::_aaload , ____|____|____|____, itos, atos, aaload , _ );
def(Bytecodes::_baload , ____|____|____|____, itos, itos, baload , _ );
def(Bytecodes::_caload , ____|____|____|____, itos, itos, caload , _ );
def(Bytecodes::_saload , ____|____|____|____, itos, itos, saload , _ );
def(Bytecodes::_istore , ubcp|____|clvm|____, itos, vtos, istore , _ );
def(Bytecodes::_lstore , ubcp|____|____|____, ltos, vtos, lstore , _ );
def(Bytecodes::_fstore , ubcp|____|____|____, ftos, vtos, fstore , _ );
def(Bytecodes::_dstore , ubcp|____|____|____, dtos, vtos, dstore , _ );
def(Bytecodes::_astore , ubcp|____|clvm|____, vtos, vtos, astore , _ );
def(Bytecodes::_istore_0 , ____|____|____|____, itos, vtos, istore , 0 );
def(Bytecodes::_istore_1 , ____|____|____|____, itos, vtos, istore , 1 );
def(Bytecodes::_istore_2 , ____|____|____|____, itos, vtos, istore , 2 );
def(Bytecodes::_istore_3 , ____|____|____|____, itos, vtos, istore , 3 );
def(Bytecodes::_lstore_0 , ____|____|____|____, ltos, vtos, lstore , 0 );
def(Bytecodes::_lstore_1 , ____|____|____|____, ltos, vtos, lstore , 1 );
def(Bytecodes::_lstore_2 , ____|____|____|____, ltos, vtos, lstore , 2 );
def(Bytecodes::_lstore_3 , ____|____|____|____, ltos, vtos, lstore , 3 );
def(Bytecodes::_fstore_0 , ____|____|____|____, ftos, vtos, fstore , 0 );
def(Bytecodes::_fstore_1 , ____|____|____|____, ftos, vtos, fstore , 1 );
def(Bytecodes::_fstore_2 , ____|____|____|____, ftos, vtos, fstore , 2 );
def(Bytecodes::_fstore_3 , ____|____|____|____, ftos, vtos, fstore , 3 );
def(Bytecodes::_dstore_0 , ____|____|____|____, dtos, vtos, dstore , 0 );
def(Bytecodes::_dstore_1 , ____|____|____|____, dtos, vtos, dstore , 1 );
def(Bytecodes::_dstore_2 , ____|____|____|____, dtos, vtos, dstore , 2 );
def(Bytecodes::_dstore_3 , ____|____|____|____, dtos, vtos, dstore , 3 );
def(Bytecodes::_astore_0 , ____|____|____|____, vtos, vtos, astore , 0 );
def(Bytecodes::_astore_1 , ____|____|____|____, vtos, vtos, astore , 1 );
def(Bytecodes::_astore_2 , ____|____|____|____, vtos, vtos, astore , 2 );
def(Bytecodes::_astore_3 , ____|____|____|____, vtos, vtos, astore , 3 );
def(Bytecodes::_iastore , ____|____|____|____, itos, vtos, iastore , _ );
def(Bytecodes::_lastore , ____|____|____|____, ltos, vtos, lastore , _ );
def(Bytecodes::_fastore , ____|____|____|____, ftos, vtos, fastore , _ );
def(Bytecodes::_dastore , ____|____|____|____, dtos, vtos, dastore , _ );
def(Bytecodes::_aastore , ____|____|clvm|____, vtos, vtos, aastore , _ );
def(Bytecodes::_bastore , ____|____|____|____, itos, vtos, bastore , _ );
def(Bytecodes::_castore , ____|____|____|____, itos, vtos, castore , _ );
def(Bytecodes::_sastore , ____|____|____|____, itos, vtos, sastore , _ );
def(Bytecodes::_pop , ____|____|____|____, vtos, vtos, pop , _ );
def(Bytecodes::_pop2 , ____|____|____|____, vtos, vtos, pop2 , _ );
def(Bytecodes::_dup , ____|____|____|____, vtos, vtos, dup , _ );
def(Bytecodes::_dup_x1 , ____|____|____|____, vtos, vtos, dup_x1 , _ );
def(Bytecodes::_dup_x2 , ____|____|____|____, vtos, vtos, dup_x2 , _ );
def(Bytecodes::_dup2 , ____|____|____|____, vtos, vtos, dup2 , _ );
def(Bytecodes::_dup2_x1 , ____|____|____|____, vtos, vtos, dup2_x1 , _ );
def(Bytecodes::_dup2_x2 , ____|____|____|____, vtos, vtos, dup2_x2 , _ );
def(Bytecodes::_swap , ____|____|____|____, vtos, vtos, swap , _ );
def(Bytecodes::_iadd , ____|____|____|____, itos, itos, iop2 , add );
def(Bytecodes::_ladd , ____|____|____|____, ltos, ltos, lop2 , add );
def(Bytecodes::_fadd , ____|____|____|____, ftos, ftos, fop2 , add );
def(Bytecodes::_dadd , ____|____|____|____, dtos, dtos, dop2 , add );
def(Bytecodes::_isub , ____|____|____|____, itos, itos, iop2 , sub );
def(Bytecodes::_lsub , ____|____|____|____, ltos, ltos, lop2 , sub );
def(Bytecodes::_fsub , ____|____|____|____, ftos, ftos, fop2 , sub );
def(Bytecodes::_dsub , ____|____|____|____, dtos, dtos, dop2 , sub );
def(Bytecodes::_imul , ____|____|____|____, itos, itos, iop2 , mul );
def(Bytecodes::_lmul , ____|____|____|____, ltos, ltos, lmul , _ );
def(Bytecodes::_fmul , ____|____|____|____, ftos, ftos, fop2 , mul );
def(Bytecodes::_dmul , ____|____|____|____, dtos, dtos, dop2 , mul );
def(Bytecodes::_idiv , ____|____|____|____, itos, itos, idiv , _ );
def(Bytecodes::_ldiv , ____|____|____|____, ltos, ltos, ldiv , _ );
def(Bytecodes::_fdiv , ____|____|____|____, ftos, ftos, fop2 , div );
def(Bytecodes::_ddiv , ____|____|____|____, dtos, dtos, dop2 , div );
def(Bytecodes::_irem , ____|____|____|____, itos, itos, irem , _ );
def(Bytecodes::_lrem , ____|____|____|____, ltos, ltos, lrem , _ );
def(Bytecodes::_frem , ____|____|____|____, ftos, ftos, fop2 , rem );
def(Bytecodes::_drem , ____|____|____|____, dtos, dtos, dop2 , rem );
def(Bytecodes::_ineg , ____|____|____|____, itos, itos, ineg , _ );
def(Bytecodes::_lneg , ____|____|____|____, ltos, ltos, lneg , _ );
def(Bytecodes::_fneg , ____|____|____|____, ftos, ftos, fneg , _ );
def(Bytecodes::_dneg , ____|____|____|____, dtos, dtos, dneg , _ );
def(Bytecodes::_ishl , ____|____|____|____, itos, itos, iop2 , shl );
def(Bytecodes::_lshl , ____|____|____|____, itos, ltos, lshl , _ );
def(Bytecodes::_ishr , ____|____|____|____, itos, itos, iop2 , shr );
def(Bytecodes::_lshr , ____|____|____|____, itos, ltos, lshr , _ );
def(Bytecodes::_iushr , ____|____|____|____, itos, itos, iop2 , ushr );
def(Bytecodes::_lushr , ____|____|____|____, itos, ltos, lushr , _ );
def(Bytecodes::_iand , ____|____|____|____, itos, itos, iop2 , _and );
def(Bytecodes::_land , ____|____|____|____, ltos, ltos, lop2 , _and );
def(Bytecodes::_ior , ____|____|____|____, itos, itos, iop2 , _or );
def(Bytecodes::_lor , ____|____|____|____, ltos, ltos, lop2 , _or );
def(Bytecodes::_ixor , ____|____|____|____, itos, itos, iop2 , _xor );
def(Bytecodes::_lxor , ____|____|____|____, ltos, ltos, lop2 , _xor );
def(Bytecodes::_iinc , ubcp|____|clvm|____, vtos, vtos, iinc , _ );
def(Bytecodes::_i2l , ____|____|____|____, itos, ltos, convert , _ );
def(Bytecodes::_i2f , ____|____|____|____, itos, ftos, convert , _ );
def(Bytecodes::_i2d , ____|____|____|____, itos, dtos, convert , _ );
def(Bytecodes::_l2i , ____|____|____|____, ltos, itos, convert , _ );
def(Bytecodes::_l2f , ____|____|____|____, ltos, ftos, convert , _ );
def(Bytecodes::_l2d , ____|____|____|____, ltos, dtos, convert , _ );
def(Bytecodes::_f2i , ____|____|____|____, ftos, itos, convert , _ );
def(Bytecodes::_f2l , ____|____|____|____, ftos, ltos, convert , _ );
def(Bytecodes::_f2d , ____|____|____|____, ftos, dtos, convert , _ );
def(Bytecodes::_d2i , ____|____|____|____, dtos, itos, convert , _ );
def(Bytecodes::_d2l , ____|____|____|____, dtos, ltos, convert , _ );
def(Bytecodes::_d2f , ____|____|____|____, dtos, ftos, convert , _ );
def(Bytecodes::_i2b , ____|____|____|____, itos, itos, convert , _ );
def(Bytecodes::_i2c , ____|____|____|____, itos, itos, convert , _ );
def(Bytecodes::_i2s , ____|____|____|____, itos, itos, convert , _ );
def(Bytecodes::_lcmp , ____|____|____|____, ltos, itos, lcmp , _ );
def(Bytecodes::_fcmpl , ____|____|____|____, ftos, itos, float_cmp , -1 );
def(Bytecodes::_fcmpg , ____|____|____|____, ftos, itos, float_cmp , 1 );
def(Bytecodes::_dcmpl , ____|____|____|____, dtos, itos, double_cmp , -1 );
def(Bytecodes::_dcmpg , ____|____|____|____, dtos, itos, double_cmp , 1 );
def(Bytecodes::_ifeq , ubcp|____|clvm|____, itos, vtos, if_0cmp , equal );
def(Bytecodes::_ifne , ubcp|____|clvm|____, itos, vtos, if_0cmp , not_equal );
def(Bytecodes::_iflt , ubcp|____|clvm|____, itos, vtos, if_0cmp , less );
def(Bytecodes::_ifge , ubcp|____|clvm|____, itos, vtos, if_0cmp , greater_equal);
def(Bytecodes::_ifgt , ubcp|____|clvm|____, itos, vtos, if_0cmp , greater );
def(Bytecodes::_ifle , ubcp|____|clvm|____, itos, vtos, if_0cmp , less_equal );
def(Bytecodes::_if_icmpeq , ubcp|____|clvm|____, itos, vtos, if_icmp , equal );
def(Bytecodes::_if_icmpne , ubcp|____|clvm|____, itos, vtos, if_icmp , not_equal );
def(Bytecodes::_if_icmplt , ubcp|____|clvm|____, itos, vtos, if_icmp , less );
def(Bytecodes::_if_icmpge , ubcp|____|clvm|____, itos, vtos, if_icmp , greater_equal);
def(Bytecodes::_if_icmpgt , ubcp|____|clvm|____, itos, vtos, if_icmp , greater );
def(Bytecodes::_if_icmple , ubcp|____|clvm|____, itos, vtos, if_icmp , less_equal );
def(Bytecodes::_if_acmpeq , ubcp|____|clvm|____, atos, vtos, if_acmp , equal );
def(Bytecodes::_if_acmpne , ubcp|____|clvm|____, atos, vtos, if_acmp , not_equal );
def(Bytecodes::_goto , ubcp|disp|clvm|____, vtos, vtos, _goto , _ );
def(Bytecodes::_jsr , ubcp|disp|____|____, vtos, vtos, jsr , _ ); // result is not an oop, so do not transition to atos
def(Bytecodes::_ret , ubcp|disp|____|____, vtos, vtos, ret , _ );
def(Bytecodes::_tableswitch , ubcp|disp|____|____, itos, vtos, tableswitch , _ );
def(Bytecodes::_lookupswitch , ubcp|disp|____|____, itos, itos, lookupswitch , _ );
def(Bytecodes::_ireturn , ____|disp|clvm|____, itos, itos, _return , itos );
def(Bytecodes::_lreturn , ____|disp|clvm|____, ltos, ltos, _return , ltos );
def(Bytecodes::_freturn , ____|disp|clvm|____, ftos, ftos, _return , ftos );
def(Bytecodes::_dreturn , ____|disp|clvm|____, dtos, dtos, _return , dtos );
def(Bytecodes::_areturn , ____|disp|clvm|____, atos, atos, _return , atos );
def(Bytecodes::_return , ____|disp|clvm|____, vtos, vtos, _return , vtos );
def(Bytecodes::_getstatic , ubcp|____|clvm|____, vtos, vtos, getstatic , 1 );
def(Bytecodes::_putstatic , ubcp|____|clvm|____, vtos, vtos, putstatic , 2 );
def(Bytecodes::_getfield , ubcp|____|clvm|____, vtos, vtos, getfield , 1 );
def(Bytecodes::_putfield , ubcp|____|clvm|____, vtos, vtos, putfield , 2 );
def(Bytecodes::_invokevirtual , ubcp|disp|clvm|____, vtos, vtos, invokevirtual , 2 );
def(Bytecodes::_invokespecial , ubcp|disp|clvm|____, vtos, vtos, invokespecial , 1 );
def(Bytecodes::_invokestatic , ubcp|disp|clvm|____, vtos, vtos, invokestatic , 1 );
def(Bytecodes::_invokeinterface , ubcp|disp|clvm|____, vtos, vtos, invokeinterface , 1 );
def(Bytecodes::_new , ubcp|____|clvm|____, vtos, atos, _new , _ );
def(Bytecodes::_newarray , ubcp|____|clvm|____, itos, atos, newarray , _ );
def(Bytecodes::_anewarray , ubcp|____|clvm|____, itos, atos, anewarray , _ );
def(Bytecodes::_arraylength , ____|____|____|____, atos, itos, arraylength , _ );
def(Bytecodes::_athrow , ____|disp|____|____, atos, vtos, athrow , _ );
def(Bytecodes::_checkcast , ubcp|____|clvm|____, atos, atos, checkcast , _ );
def(Bytecodes::_instanceof , ubcp|____|clvm|____, atos, itos, instanceof , _ );
def(Bytecodes::_monitorenter , ____|disp|clvm|____, atos, vtos, monitorenter , _ );
def(Bytecodes::_monitorexit , ____|____|clvm|____, atos, vtos, monitorexit , _ );
def(Bytecodes::_wide , ubcp|disp|____|____, vtos, vtos, wide , _ );
def(Bytecodes::_multianewarray , ubcp|____|clvm|____, vtos, atos, multianewarray , _ );
def(Bytecodes::_ifnull , ubcp|____|clvm|____, atos, vtos, if_nullcmp , equal );
def(Bytecodes::_ifnonnull , ubcp|____|clvm|____, atos, vtos, if_nullcmp , not_equal );
def(Bytecodes::_goto_w , ubcp|____|clvm|____, vtos, vtos, goto_w , _ );
def(Bytecodes::_jsr_w , ubcp|____|____|____, vtos, vtos, jsr_w , _ );
// wide Java spec bytecodes
def(Bytecodes::_iload , ubcp|____|____|iswd, vtos, itos, wide_iload , _ );
def(Bytecodes::_lload , ubcp|____|____|iswd, vtos, ltos, wide_lload , _ );
def(Bytecodes::_fload , ubcp|____|____|iswd, vtos, ftos, wide_fload , _ );
def(Bytecodes::_dload , ubcp|____|____|iswd, vtos, dtos, wide_dload , _ );
def(Bytecodes::_aload , ubcp|____|____|iswd, vtos, atos, wide_aload , _ );
def(Bytecodes::_istore , ubcp|____|____|iswd, vtos, vtos, wide_istore , _ );
def(Bytecodes::_lstore , ubcp|____|____|iswd, vtos, vtos, wide_lstore , _ );
def(Bytecodes::_fstore , ubcp|____|____|iswd, vtos, vtos, wide_fstore , _ );
def(Bytecodes::_dstore , ubcp|____|____|iswd, vtos, vtos, wide_dstore , _ );
def(Bytecodes::_astore , ubcp|____|____|iswd, vtos, vtos, wide_astore , _ );
def(Bytecodes::_iinc , ubcp|____|____|iswd, vtos, vtos, wide_iinc , _ );
def(Bytecodes::_ret , ubcp|disp|____|iswd, vtos, vtos, wide_ret , _ );
def(Bytecodes::_breakpoint , ubcp|disp|clvm|____, vtos, vtos, _breakpoint , _ );
// JVM bytecodes
def(Bytecodes::_fast_agetfield , ubcp|____|____|____, atos, atos, fast_accessfield , atos );
def(Bytecodes::_fast_bgetfield , ubcp|____|____|____, atos, itos, fast_accessfield , itos );
def(Bytecodes::_fast_cgetfield , ubcp|____|____|____, atos, itos, fast_accessfield , itos );
def(Bytecodes::_fast_dgetfield , ubcp|____|____|____, atos, dtos, fast_accessfield , dtos );
def(Bytecodes::_fast_fgetfield , ubcp|____|____|____, atos, ftos, fast_accessfield , ftos );
def(Bytecodes::_fast_igetfield , ubcp|____|____|____, atos, itos, fast_accessfield , itos );
def(Bytecodes::_fast_lgetfield , ubcp|____|____|____, atos, ltos, fast_accessfield , ltos );
def(Bytecodes::_fast_sgetfield , ubcp|____|____|____, atos, itos, fast_accessfield , itos );
def(Bytecodes::_fast_aputfield , ubcp|____|____|____, atos, vtos, fast_storefield , atos );
def(Bytecodes::_fast_bputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
def(Bytecodes::_fast_cputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
def(Bytecodes::_fast_dputfield , ubcp|____|____|____, dtos, vtos, fast_storefield , dtos );
def(Bytecodes::_fast_fputfield , ubcp|____|____|____, ftos, vtos, fast_storefield , ftos );
def(Bytecodes::_fast_iputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
def(Bytecodes::_fast_lputfield , ubcp|____|____|____, ltos, vtos, fast_storefield , ltos );
def(Bytecodes::_fast_sputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
def(Bytecodes::_fast_aload_0 , ____|____|____|____, vtos, atos, aload , 0 );
def(Bytecodes::_fast_iaccess_0 , ubcp|____|____|____, vtos, itos, fast_xaccess , itos );
def(Bytecodes::_fast_aaccess_0 , ubcp|____|____|____, vtos, atos, fast_xaccess , atos );
def(Bytecodes::_fast_faccess_0 , ubcp|____|____|____, vtos, ftos, fast_xaccess , ftos );
def(Bytecodes::_fast_iload , ubcp|____|____|____, vtos, itos, fast_iload , _ );
def(Bytecodes::_fast_iload2 , ubcp|____|____|____, vtos, itos, fast_iload2 , _ );
def(Bytecodes::_fast_icaload , ubcp|____|____|____, vtos, itos, fast_icaload , _ );
def(Bytecodes::_fast_invokevfinal , ubcp|disp|clvm|____, vtos, vtos, fast_invokevfinal , 2 );
def(Bytecodes::_fast_linearswitch , ubcp|disp|____|____, itos, vtos, fast_linearswitch , _ );
def(Bytecodes::_fast_binaryswitch , ubcp|disp|____|____, itos, vtos, fast_binaryswitch , _ );
def(Bytecodes::_return_register_finalizer , ____|disp|clvm|____, vtos, vtos, _return , vtos );
def(Bytecodes::_shouldnotreachhere , ____|____|____|____, vtos, vtos, shouldnotreachhere , _ );
// platform specific bytecodes
pd_initialize();
_is_initialized = true;
}
#if defined(TEMPLATE_TABLE_BUG)
#undef iload
#undef lload
#undef fload
#undef dload
#undef aload
#undef istore
#undef lstore
#undef fstore
#undef dstore
#undef astore
#endif // TEMPLATE_TABLE_BUG
void templateTable_init() {
TemplateTable::initialize();
}
void TemplateTable::unimplemented_bc() {
_masm->unimplemented( Bytecodes::name(_desc->bytecode()));
}
#endif /* !CC_INTERP */

View file

@ -0,0 +1,329 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* 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.
*
*/
#ifndef CC_INTERP
// All the necessary definitions used for (bytecode) template generation. Instead of
// spreading the implementation functionality for each bytecode in the interpreter
// and the snippet generator, a template is assigned to each bytecode which can be
// used to generate the bytecode's implementation if needed.
// A Template describes the properties of a code template for a given bytecode
// and provides a generator to generate the code template.
class Template VALUE_OBJ_CLASS_SPEC {
private:
enum Flags {
uses_bcp_bit, // set if template needs the bcp pointing to bytecode
does_dispatch_bit, // set if template dispatches on its own
calls_vm_bit, // set if template calls the vm
wide_bit // set if template belongs to a wide instruction
};
typedef void (*generator)(int arg);
int _flags; // describes interpreter template properties (bcp unknown)
TosState _tos_in; // tos cache state before template execution
TosState _tos_out; // tos cache state after template execution
generator _gen; // template code generator
int _arg; // argument for template code generator
void initialize(int flags, TosState tos_in, TosState tos_out, generator gen, int arg);
friend class TemplateTable;
public:
Bytecodes::Code bytecode() const;
bool is_valid() const { return _gen != NULL; }
bool uses_bcp() const { return (_flags & (1 << uses_bcp_bit )) != 0; }
bool does_dispatch() const { return (_flags & (1 << does_dispatch_bit)) != 0; }
bool calls_vm() const { return (_flags & (1 << calls_vm_bit )) != 0; }
bool is_wide() const { return (_flags & (1 << wide_bit )) != 0; }
TosState tos_in() const { return _tos_in; }
TosState tos_out() const { return _tos_out; }
void generate(InterpreterMacroAssembler* masm);
};
// The TemplateTable defines all Templates and provides accessor functions
// to get the template for a given bytecode.
class TemplateTable: AllStatic {
public:
enum Operation { add, sub, mul, div, rem, _and, _or, _xor, shl, shr, ushr };
enum Condition { equal, not_equal, less, less_equal, greater, greater_equal };
private:
static bool _is_initialized; // true if TemplateTable has been initialized
static Template _template_table [Bytecodes::number_of_codes];
static Template _template_table_wide[Bytecodes::number_of_codes];
static Template* _desc; // the current template to be generated
static Bytecodes::Code bytecode() { return _desc->bytecode(); }
public:
//%note templates_1
static InterpreterMacroAssembler* _masm; // the assembler used when generating templates
private:
// special registers
static inline Address at_bcp(int offset);
// helpers
static void unimplemented_bc();
static void patch_bytecode(Bytecodes::Code bc, Register scratch1,
Register scratch2, bool load_bc_in_scratch = true);
// C calls
static void call_VM(Register oop_result, address entry_point);
static void call_VM(Register oop_result, address entry_point, Register arg_1);
static void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2);
static void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3);
// these overloadings are not presently used on SPARC:
static void call_VM(Register oop_result, Register last_java_sp, address entry_point);
static void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1);
static void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2);
static void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3);
// bytecodes
static void nop();
static void aconst_null();
static void iconst(int value);
static void lconst(int value);
static void fconst(int value);
static void dconst(int value);
static void bipush();
static void sipush();
static void ldc(bool wide);
static void ldc2_w();
static void locals_index(Register reg, int offset = 1);
static void iload();
static void fast_iload();
static void fast_iload2();
static void fast_icaload();
static void lload();
static void fload();
static void dload();
static void aload();
static void locals_index_wide(Register reg);
static void wide_iload();
static void wide_lload();
static void wide_fload();
static void wide_dload();
static void wide_aload();
static void iaload();
static void laload();
static void faload();
static void daload();
static void aaload();
static void baload();
static void caload();
static void saload();
static void iload(int n);
static void lload(int n);
static void fload(int n);
static void dload(int n);
static void aload(int n);
static void aload_0();
static void istore();
static void lstore();
static void fstore();
static void dstore();
static void astore();
static void wide_istore();
static void wide_lstore();
static void wide_fstore();
static void wide_dstore();
static void wide_astore();
static void iastore();
static void lastore();
static void fastore();
static void dastore();
static void aastore();
static void bastore();
static void castore();
static void sastore();
static void istore(int n);
static void lstore(int n);
static void fstore(int n);
static void dstore(int n);
static void astore(int n);
static void pop();
static void pop2();
static void dup();
static void dup_x1();
static void dup_x2();
static void dup2();
static void dup2_x1();
static void dup2_x2();
static void swap();
static void iop2(Operation op);
static void lop2(Operation op);
static void fop2(Operation op);
static void dop2(Operation op);
static void idiv();
static void irem();
static void lmul();
static void ldiv();
static void lrem();
static void lshl();
static void lshr();
static void lushr();
static void ineg();
static void lneg();
static void fneg();
static void dneg();
static void iinc();
static void wide_iinc();
static void convert();
static void lcmp();
static void float_cmp (bool is_float, int unordered_result);
static void float_cmp (int unordered_result);
static void double_cmp(int unordered_result);
static void count_calls(Register method, Register temp);
static void branch(bool is_jsr, bool is_wide);
static void if_0cmp (Condition cc);
static void if_icmp (Condition cc);
static void if_nullcmp(Condition cc);
static void if_acmp (Condition cc);
static void _goto();
static void jsr();
static void ret();
static void wide_ret();
static void goto_w();
static void jsr_w();
static void tableswitch();
static void lookupswitch();
static void fast_linearswitch();
static void fast_binaryswitch();
static void _return(TosState state);
static void resolve_cache_and_index(int byte_no, Register cache, Register index);
static void load_invoke_cp_cache_entry(int byte_no,
Register method,
Register itable_index,
Register flags,
bool is_invokevirtual = false,
bool is_virtual_final = false);
static void load_field_cp_cache_entry(Register obj,
Register cache,
Register index,
Register offset,
Register flags,
bool is_static);
static void invokevirtual(int byte_no);
static void invokespecial(int byte_no);
static void invokestatic(int byte_no);
static void invokeinterface(int byte_no);
static void fast_invokevfinal(int byte_no);
static void getfield_or_static(int byte_no, bool is_static);
static void putfield_or_static(int byte_no, bool is_static);
static void getfield(int byte_no);
static void putfield(int byte_no);
static void getstatic(int byte_no);
static void putstatic(int byte_no);
static void pop_and_check_object(Register obj);
static void _new();
static void newarray();
static void anewarray();
static void arraylength();
static void checkcast();
static void instanceof();
static void athrow();
static void monitorenter();
static void monitorexit();
static void wide();
static void multianewarray();
static void fast_xaccess(TosState state);
static void fast_accessfield(TosState state);
static void fast_storefield(TosState state);
static void _breakpoint();
static void shouldnotreachhere();
// jvmti support
static void jvmti_post_field_access(Register cache, Register index, bool is_static, bool has_tos);
static void jvmti_post_field_mod(Register cache, Register index, bool is_static);
static void jvmti_post_fast_field_mod();
// debugging of TemplateGenerator
static void transition(TosState tos_in, TosState tos_out);// checks if in/out states expected by template generator correspond to table entries
// initialization helpers
static void def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)( ), char filler );
static void def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(int arg ), int arg );
static void def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(bool arg ), bool arg );
static void def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(TosState tos), TosState tos);
static void def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(Operation op), Operation op);
static void def(Bytecodes::Code code, int flags, TosState in, TosState out, void (*gen)(Condition cc), Condition cc);
friend class Template;
// InterpreterMacroAssembler::is_a(), etc., need TemplateTable::call_VM().
friend class InterpreterMacroAssembler;
public:
// Initialization
static void initialize();
static void pd_initialize();
// Templates
static Template* template_for (Bytecodes::Code code) { Bytecodes::check (code); return &_template_table [code]; }
static Template* template_for_wide(Bytecodes::Code code) { Bytecodes::wide_check(code); return &_template_table_wide[code]; }
// Platform specifics
#include "incls/_templateTable_pd.hpp.incl"
};
#endif /* !CC_INTERP */