mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-22 12:04:39 +02:00
Initial load
This commit is contained in:
parent
686d76f772
commit
8153779ad3
2894 changed files with 911801 additions and 0 deletions
245
hotspot/src/share/vm/interpreter/abstractInterpreter.hpp
Normal file
245
hotspot/src/share/vm/interpreter/abstractInterpreter.hpp
Normal 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);
|
||||
};
|
205
hotspot/src/share/vm/interpreter/bytecode.cpp
Normal file
205
hotspot/src/share/vm/interpreter/bytecode.cpp
Normal 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
|
376
hotspot/src/share/vm/interpreter/bytecode.hpp
Normal file
376
hotspot/src/share/vm/interpreter/bytecode.hpp
Normal 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;
|
||||
}
|
186
hotspot/src/share/vm/interpreter/bytecodeHistogram.cpp
Normal file
186
hotspot/src/share/vm/interpreter/bytecodeHistogram.cpp
Normal 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
|
92
hotspot/src/share/vm/interpreter/bytecodeHistogram.hpp
Normal file
92
hotspot/src/share/vm/interpreter/bytecodeHistogram.hpp
Normal 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
|
||||
};
|
3047
hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
Normal file
3047
hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
Normal file
File diff suppressed because it is too large
Load diff
572
hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp
Normal file
572
hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp
Normal 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
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
48
hotspot/src/share/vm/interpreter/bytecodeStream.cpp
Normal file
48
hotspot/src/share/vm/interpreter/bytecodeStream.cpp
Normal 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;
|
||||
}
|
172
hotspot/src/share/vm/interpreter/bytecodeStream.hpp
Normal file
172
hotspot/src/share/vm/interpreter/bytecodeStream.hpp
Normal 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()); }
|
||||
};
|
419
hotspot/src/share/vm/interpreter/bytecodeTracer.cpp
Normal file
419
hotspot/src/share/vm/interpreter/bytecodeTracer.cpp
Normal 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
|
58
hotspot/src/share/vm/interpreter/bytecodeTracer.hpp
Normal file
58
hotspot/src/share/vm/interpreter/bytecodeTracer.hpp
Normal 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
|
435
hotspot/src/share/vm/interpreter/bytecodes.cpp
Normal file
435
hotspot/src/share/vm/interpreter/bytecodes.cpp
Normal 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
|
358
hotspot/src/share/vm/interpreter/bytecodes.hpp
Normal file
358
hotspot/src/share/vm/interpreter/bytecodes.hpp
Normal 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 ();
|
||||
};
|
135
hotspot/src/share/vm/interpreter/cppInterpreter.cpp
Normal file
135
hotspot/src/share/vm/interpreter/cppInterpreter.cpp
Normal 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
|
83
hotspot/src/share/vm/interpreter/cppInterpreter.hpp
Normal file
83
hotspot/src/share/vm/interpreter/cppInterpreter.hpp
Normal 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
|
47
hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp
Normal file
47
hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp
Normal 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
|
409
hotspot/src/share/vm/interpreter/interpreter.cpp
Normal file
409
hotspot/src/share/vm/interpreter/interpreter.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
134
hotspot/src/share/vm/interpreter/interpreter.hpp
Normal file
134
hotspot/src/share/vm/interpreter/interpreter.hpp
Normal 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"
|
||||
};
|
38
hotspot/src/share/vm/interpreter/interpreterGenerator.hpp
Normal file
38
hotspot/src/share/vm/interpreter/interpreterGenerator.hpp
Normal 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"
|
||||
|
||||
};
|
1151
hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
Normal file
1151
hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
Normal file
File diff suppressed because it is too large
Load diff
148
hotspot/src/share/vm/interpreter/interpreterRuntime.hpp
Normal file
148
hotspot/src/share/vm/interpreter/interpreterRuntime.hpp
Normal 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);
|
||||
};
|
170
hotspot/src/share/vm/interpreter/invocationCounter.cpp
Normal file
170
hotspot/src/share/vm/interpreter/invocationCounter.cpp
Normal 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);
|
||||
}
|
137
hotspot/src/share/vm/interpreter/invocationCounter.hpp
Normal file
137
hotspot/src/share/vm/interpreter/invocationCounter.hpp
Normal 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);
|
||||
}
|
1000
hotspot/src/share/vm/interpreter/linkResolver.cpp
Normal file
1000
hotspot/src/share/vm/interpreter/linkResolver.cpp
Normal file
File diff suppressed because it is too large
Load diff
171
hotspot/src/share/vm/interpreter/linkResolver.hpp
Normal file
171
hotspot/src/share/vm/interpreter/linkResolver.hpp
Normal 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);
|
||||
};
|
643
hotspot/src/share/vm/interpreter/oopMapCache.cpp
Normal file
643
hotspot/src/share/vm/interpreter/oopMapCache.cpp
Normal 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);
|
||||
}
|
190
hotspot/src/share/vm/interpreter/oopMapCache.hpp
Normal file
190
hotspot/src/share/vm/interpreter/oopMapCache.hpp
Normal 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;
|
||||
};
|
246
hotspot/src/share/vm/interpreter/rewriter.cpp
Normal file
246
hotspot/src/share/vm/interpreter/rewriter.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
37
hotspot/src/share/vm/interpreter/rewriter.hpp
Normal file
37
hotspot/src/share/vm/interpreter/rewriter.hpp
Normal 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);
|
||||
};
|
597
hotspot/src/share/vm/interpreter/templateInterpreter.cpp
Normal file
597
hotspot/src/share/vm/interpreter/templateInterpreter.cpp
Normal 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
|
177
hotspot/src/share/vm/interpreter/templateInterpreter.hpp
Normal file
177
hotspot/src/share/vm/interpreter/templateInterpreter.hpp
Normal 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
|
|
@ -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
|
538
hotspot/src/share/vm/interpreter/templateTable.cpp
Normal file
538
hotspot/src/share/vm/interpreter/templateTable.cpp
Normal 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 */
|
329
hotspot/src/share/vm/interpreter/templateTable.hpp
Normal file
329
hotspot/src/share/vm/interpreter/templateTable.hpp
Normal 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 */
|
Loading…
Add table
Add a link
Reference in a new issue