This commit is contained in:
Tom Rodriguez 2009-04-14 12:25:54 -07:00
commit 62717f091a
81 changed files with 7128 additions and 247 deletions

View File

@ -142,34 +142,35 @@ public interface ClassConstants
// from jvm.h
public static final long JVM_RECOGNIZED_CLASS_MODIFIERS = (JVM_ACC_PUBLIC |
JVM_ACC_FINAL |
JVM_ACC_SUPER |
JVM_ACC_INTERFACE |
JVM_ACC_ABSTRACT |
JVM_ACC_ANNOTATION |
JVM_ACC_SYNTHETIC);
JVM_ACC_FINAL |
JVM_ACC_SUPER |
JVM_ACC_INTERFACE |
JVM_ACC_ABSTRACT |
JVM_ACC_ANNOTATION |
JVM_ACC_ENUM |
JVM_ACC_SYNTHETIC);
public static final long JVM_RECOGNIZED_FIELD_MODIFIERS = (JVM_ACC_PUBLIC |
JVM_ACC_PRIVATE |
JVM_ACC_PROTECTED |
JVM_ACC_STATIC |
JVM_ACC_FINAL |
JVM_ACC_VOLATILE |
JVM_ACC_TRANSIENT |
JVM_ACC_ENUM |
JVM_ACC_SYNTHETIC);
JVM_ACC_PRIVATE |
JVM_ACC_PROTECTED |
JVM_ACC_STATIC |
JVM_ACC_FINAL |
JVM_ACC_VOLATILE |
JVM_ACC_TRANSIENT |
JVM_ACC_ENUM |
JVM_ACC_SYNTHETIC);
public static final long JVM_RECOGNIZED_METHOD_MODIFIERS = (JVM_ACC_PUBLIC |
JVM_ACC_PRIVATE |
JVM_ACC_PROTECTED |
JVM_ACC_STATIC |
JVM_ACC_FINAL |
JVM_ACC_SYNCHRONIZED |
JVM_ACC_BRIDGE |
JVM_ACC_VARARGS |
JVM_ACC_NATIVE |
JVM_ACC_ABSTRACT |
JVM_ACC_STRICT |
JVM_ACC_SYNTHETIC);
JVM_ACC_PRIVATE |
JVM_ACC_PROTECTED |
JVM_ACC_STATIC |
JVM_ACC_FINAL |
JVM_ACC_SYNCHRONIZED |
JVM_ACC_BRIDGE |
JVM_ACC_VARARGS |
JVM_ACC_NATIVE |
JVM_ACC_ABSTRACT |
JVM_ACC_STRICT |
JVM_ACC_SYNTHETIC);
}

View File

@ -89,29 +89,6 @@ public class ByteCodeRewriter
// update the code buffer hotspot specific bytecode with the jvm bytecode
code[bci] = (byte) (0xFF & bytecode);
// RewriteFrequentPairs
if(hotspotcode == Bytecodes._fast_iaccess_0 ||
hotspotcode == Bytecodes._fast_aaccess_0 ||
hotspotcode == Bytecodes._fast_faccess_0) {
// rewrite next bytecode as _getfield
bci++;
code[bci] = (byte) (0xFF & Bytecodes._getfield);
bytecode = Bytecodes._getfield;
hotspotcode = Bytecodes._getfield;
} else if (hotspotcode == Bytecodes._fast_iload2) {
// rewrite next bytecode as _iload
bci++;
code[bci] = (byte) (0xFF & Bytecodes._iload);
bytecode = Bytecodes._iload;
hotspotcode = Bytecodes._iload;
} else if (hotspotcode == Bytecodes._fast_icaload) {
// rewrite next bytecode as _caload
bci++;
code[bci] = (byte) (0xFF & Bytecodes._caload);
bytecode = Bytecodes._caload;
bytecode = Bytecodes._caload;
}
short cpoolIndex = 0;
switch (bytecode) {
// bytecodes with ConstantPoolCache index

View File

@ -59,8 +59,14 @@ public class ClassDump extends Tool {
SystemDictionary dict = VM.getVM().getSystemDictionary();
dict.classesDo(new SystemDictionary.ClassVisitor() {
public void visit(Klass k) {
if (k instanceof InstanceKlass)
dumpKlass((InstanceKlass) k);
if (k instanceof InstanceKlass) {
try {
dumpKlass((InstanceKlass) k);
} catch (Exception e) {
System.out.println(k.getName().asString());
e.printStackTrace();
}
}
}
});
}

View File

@ -40,7 +40,6 @@ public class ClassWriter implements /* imports */ ClassConstants
protected InstanceKlass klass;
protected DataOutputStream dos;
protected ConstantPool cpool;
protected boolean is15Format;
// Map between class name to index of type CONSTANT_Class
protected Map classToIndex = new HashMap();
@ -73,7 +72,6 @@ public class ClassWriter implements /* imports */ ClassConstants
klass = kls;
dos = new DataOutputStream(os);
cpool = klass.getConstants();
is15Format = is15ClassFile();
}
public void write() throws IOException {
@ -82,7 +80,7 @@ public class ClassWriter implements /* imports */ ClassConstants
// write magic
dos.writeInt(0xCAFEBABE);
writeVersion(is15Format);
writeVersion();
writeConstantPool();
writeClassAccessFlags();
writeThisClass();
@ -96,43 +94,14 @@ public class ClassWriter implements /* imports */ ClassConstants
dos.flush();
}
protected boolean is15ClassFile() {
// if klass has generic signature, then it is 1.5 class file.
if (klass.getGenericSignature() != null) {
return true;
}
// if atleast one method has generic signature
// , then we have 1.5 class file.
ObjArray methods = klass.getMethods();
final int numMethods = (int) methods.getLength();
for (int m = 0; m < numMethods; m++) {
Method curMethod = (Method) methods.getObjAt(m);
if (curMethod.getGenericSignature() != null) {
return true;
}
}
// if atleast one field has non-zero generic signature index, then we have
// 1.5 class file
TypeArray fields = klass.getFields();
final int numFields = (int) fields.getLength();
for (int f = 0; f < numFields; f += InstanceKlass.NEXT_OFFSET) {
short genSigIndex = fields.getShortAt(f + InstanceKlass.GENERIC_SIGNATURE_INDEX_OFFSET);
if (genSigIndex != (short)0) return true;
}
return false;
protected void writeVersion() throws IOException {
dos.writeShort((short)klass.minorVersion());
dos.writeShort((short)klass.majorVersion());
}
protected void writeVersion(boolean is15Format) throws IOException {
if (is15Format) {
dos.writeShort(MINOR_VERSION);
dos.writeShort(MAJOR_VERSION);
} else {
dos.writeShort(MINOR_VERSION_OLD);
dos.writeShort(MAJOR_VERSION_OLD);
}
protected void writeIndex(int index) throws IOException {
if (index == 0) throw new InternalError();
dos.writeShort(index);
}
protected void writeConstantPool() throws IOException {
@ -392,8 +361,8 @@ public class ClassWriter implements /* imports */ ClassConstants
if (DEBUG) debugMessage("\tfield name = " + nameIndex + ", signature = " + signatureIndex);
short fieldAttributeCount = 0;
boolean isSyn = isSynthetic(accessFlags);
if (isSyn)
boolean hasSyn = hasSyntheticAttribute(accessFlags);
if (hasSyn)
fieldAttributeCount++;
short initvalIndex = fields.getShortAt(index + InstanceKlass.INITVAL_INDEX_OFFSET);
@ -407,18 +376,18 @@ public class ClassWriter implements /* imports */ ClassConstants
dos.writeShort(fieldAttributeCount);
// write synthetic, if applicable
if (isSyn)
if (hasSyn)
writeSynthetic();
if (initvalIndex != 0) {
dos.writeShort(_constantValueIndex);
writeIndex(_constantValueIndex);
dos.writeInt(2);
dos.writeShort(initvalIndex);
if (DEBUG) debugMessage("\tfield init value = " + initvalIndex);
}
if (genSigIndex != 0) {
dos.writeShort(_signatureIndex);
writeIndex(_signatureIndex);
dos.writeInt(2);
dos.writeShort(genSigIndex);
if (DEBUG) debugMessage("\tfield generic signature index " + genSigIndex);
@ -430,8 +399,13 @@ public class ClassWriter implements /* imports */ ClassConstants
return (accessFlags & (short) JVM_ACC_SYNTHETIC) != 0;
}
protected boolean hasSyntheticAttribute(short accessFlags) {
// Check if flags have the attribute and if the constant pool contains an entry for it.
return isSynthetic(accessFlags) && _syntheticIndex != 0;
}
protected void writeSynthetic() throws IOException {
dos.writeShort(_syntheticIndex);
writeIndex(_syntheticIndex);
dos.writeInt(0);
}
@ -459,8 +433,8 @@ public class ClassWriter implements /* imports */ ClassConstants
short methodAttributeCount = 0;
final boolean isSyn = isSynthetic((short)accessFlags);
if (isSyn)
final boolean hasSyn = hasSyntheticAttribute((short)accessFlags);
if (hasSyn)
methodAttributeCount++;
final boolean hasCheckedExceptions = m.hasCheckedExceptions();
@ -478,27 +452,11 @@ public class ClassWriter implements /* imports */ ClassConstants
dos.writeShort(methodAttributeCount);
if (DEBUG) debugMessage("\tmethod attribute count = " + methodAttributeCount);
if (isSyn) {
if (hasSyn) {
if (DEBUG) debugMessage("\tmethod is synthetic");
writeSynthetic();
}
if (hasCheckedExceptions) {
CheckedExceptionElement[] exceptions = m.getCheckedExceptions();
dos.writeShort(_exceptionsIndex);
int attrSize = 2 /* number_of_exceptions */ +
exceptions.length * 2 /* exception_index */;
dos.writeInt(attrSize);
dos.writeShort(exceptions.length);
if (DEBUG) debugMessage("\tmethod has " + exceptions.length
+ " checked exception(s)");
for (int e = 0; e < exceptions.length; e++) {
short cpIndex = (short) exceptions[e].getClassCPIndex();
dos.writeShort(cpIndex);
}
}
if (isCodeAvailable) {
byte[] code = m.getByteCode();
short codeAttrCount = 0;
@ -574,7 +532,7 @@ public class ClassWriter implements /* imports */ ClassConstants
// start writing Code
dos.writeShort(_codeIndex);
writeIndex(_codeIndex);
dos.writeInt(codeSize);
if (DEBUG) debugMessage("\tcode attribute length = " + codeSize);
@ -608,7 +566,7 @@ public class ClassWriter implements /* imports */ ClassConstants
// write LineNumberTable, if available.
if (hasLineNumberTable) {
dos.writeShort(_lineNumberTableIndex);
writeIndex(_lineNumberTableIndex);
dos.writeInt(lineNumberAttrLen);
dos.writeShort((short) lineNumberTable.length);
for (int l = 0; l < lineNumberTable.length; l++) {
@ -619,7 +577,7 @@ public class ClassWriter implements /* imports */ ClassConstants
// write LocalVariableTable, if available.
if (hasLocalVariableTable) {
dos.writeShort((short) _localVariableTableIndex);
writeIndex((short) _localVariableTableIndex);
dos.writeInt(localVarAttrLen);
dos.writeShort((short) localVariableTable.length);
for (int l = 0; l < localVariableTable.length; l++) {
@ -632,6 +590,22 @@ public class ClassWriter implements /* imports */ ClassConstants
}
}
if (hasCheckedExceptions) {
CheckedExceptionElement[] exceptions = m.getCheckedExceptions();
writeIndex(_exceptionsIndex);
int attrSize = 2 /* number_of_exceptions */ +
exceptions.length * 2 /* exception_index */;
dos.writeInt(attrSize);
dos.writeShort(exceptions.length);
if (DEBUG) debugMessage("\tmethod has " + exceptions.length
+ " checked exception(s)");
for (int e = 0; e < exceptions.length; e++) {
short cpIndex = (short) exceptions[e].getClassCPIndex();
dos.writeShort(cpIndex);
}
}
if (isGeneric) {
writeGenericSignature(m.getGenericSignature().asString());
}
@ -643,7 +617,7 @@ public class ClassWriter implements /* imports */ ClassConstants
}
protected void writeGenericSignature(String signature) throws IOException {
dos.writeShort(_signatureIndex);
writeIndex(_signatureIndex);
if (DEBUG) debugMessage("signature attribute = " + _signatureIndex);
dos.writeInt(2);
Short index = (Short) utf8ToIndex.get(signature);
@ -653,12 +627,12 @@ public class ClassWriter implements /* imports */ ClassConstants
protected void writeClassAttributes() throws IOException {
final long flags = klass.getAccessFlags();
final boolean isSyn = isSynthetic((short) flags);
final boolean hasSyn = hasSyntheticAttribute((short) flags);
// check for source file
short classAttributeCount = 0;
if (isSyn)
if (hasSyn)
classAttributeCount++;
Symbol sourceFileName = klass.getSourceFileName();
@ -677,12 +651,12 @@ public class ClassWriter implements /* imports */ ClassConstants
dos.writeShort(classAttributeCount);
if (DEBUG) debugMessage("class attribute count = " + classAttributeCount);
if (isSyn)
if (hasSyn)
writeSynthetic();
// write SourceFile, if any
if (sourceFileName != null) {
dos.writeShort(_sourceFileIndex);
writeIndex(_sourceFileIndex);
if (DEBUG) debugMessage("source file attribute = " + _sourceFileIndex);
dos.writeInt(2);
Short index = (Short) utf8ToIndex.get(sourceFileName.asString());
@ -697,7 +671,7 @@ public class ClassWriter implements /* imports */ ClassConstants
// write inner classes, if any
if (numInnerClasses != 0) {
dos.writeShort(_innerClassesIndex);
writeIndex(_innerClassesIndex);
final int innerAttrLen = 2 /* number_of_inner_classes */ +
numInnerClasses * (
2 /* inner_class_info_index */ +

View File

@ -3029,6 +3029,58 @@ void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
Register temp_reg,
Label& wrong_method_type) {
assert_different_registers(mtype_reg, mh_reg, temp_reg);
// compare method type against that of the receiver
RegisterOrConstant mhtype_offset = delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg);
ld_ptr(mh_reg, mhtype_offset, temp_reg);
cmp(temp_reg, mtype_reg);
br(Assembler::notEqual, false, Assembler::pn, wrong_method_type);
delayed()->nop();
}
void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
assert(mh_reg == G3_method_handle, "caller must put MH object in G3");
assert_different_registers(mh_reg, temp_reg);
// pick out the interpreted side of the handler
ld_ptr(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg), temp_reg);
// off we go...
ld_ptr(temp_reg, MethodHandleEntry::from_interpreted_entry_offset_in_bytes(), temp_reg);
jmp(temp_reg, 0);
// for the various stubs which take control at this point,
// see MethodHandles::generate_method_handle_stub
// (Can any caller use this delay slot? If so, add an option for supression.)
delayed()->nop();
}
RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot,
int extra_slot_offset) {
// cf. TemplateTable::prepare_invoke(), if (load_receiver).
int stackElementSize = Interpreter::stackElementWords() * wordSize;
int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
assert(offset1 - offset == stackElementSize, "correct arithmetic");
if (arg_slot.is_constant()) {
offset += arg_slot.as_constant() * stackElementSize;
return offset;
} else {
Register temp = arg_slot.as_register();
sll_ptr(temp, exact_log2(stackElementSize), temp);
if (offset != 0)
add(temp, offset, temp);
return temp;
}
}
void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
Register temp_reg,
Label& done, Label* slow_case,

View File

@ -84,6 +84,10 @@ REGISTER_DECLARATION(Register, G4_scratch , G4);
REGISTER_DECLARATION(Register, Gtemp , G5);
// JSR 292 fixed register usages:
REGISTER_DECLARATION(Register, G5_method_type , G5);
REGISTER_DECLARATION(Register, G3_method_handle , G3);
// The compiler requires that G5_megamorphic_method is G5_inline_cache_klass,
// because a single patchable "set" instruction (NativeMovConstReg,
// or NativeMovConstPatching for compiler1) instruction
@ -91,9 +95,13 @@ REGISTER_DECLARATION(Register, Gtemp , G5);
// call site is an inline cache or is megamorphic. See the function
// CompiledIC::set_to_megamorphic.
//
// On the other hand, G5_inline_cache_klass must differ from G5_method,
// because both registers are needed for an inline cache that calls
// an interpreted method.
// If a inline cache targets an interpreted method, then the
// G5 register will be used twice during the call. First,
// the call site will be patched to load a compiledICHolder
// into G5. (This is an ordered pair of ic_klass, method.)
// The c2i adapter will first check the ic_klass, then load
// G5_method with the method part of the pair just before
// jumping into the interpreter.
//
// Note that G5_method is only the method-self for the interpreter,
// and is logically unrelated to G5_megamorphic_method.
@ -1931,6 +1939,7 @@ class MacroAssembler: public Assembler {
inline void store_ptr_contents( Register s, Address& a, int offset = 0 );
inline void jumpl_to( Address& a, Register d, int offset = 0 );
inline void jump_to( Address& a, int offset = 0 );
inline void jump_indirect_to( Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0 );
// ring buffer traceable jumps
@ -2366,6 +2375,16 @@ class MacroAssembler: public Assembler {
Register temp2_reg,
Label& L_success);
// method handles (JSR 292)
void check_method_handle_type(Register mtype_reg, Register mh_reg,
Register temp_reg,
Label& wrong_method_type);
void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
// offset relative to Gargs of argument at tos[arg_slot].
// (arg_slot == 0 means the last argument, not the first).
RegisterOrConstant argument_offset(RegisterOrConstant arg_slot,
int extra_slot_offset = 0);
// Stack overflow checking

View File

@ -671,6 +671,15 @@ inline void MacroAssembler::jump_to( Address& a, int offset ) {
}
inline void MacroAssembler::jump_indirect_to( Address& a, Register temp,
int ld_offset, int jmp_offset ) {
assert_not_delayed();
//sethi(a); // sethi is caller responsibility for this one
ld_ptr(a, temp, ld_offset);
jmp(temp, jmp_offset);
}
inline void MacroAssembler::set_oop( jobject obj, Register d ) {
set_oop(allocate_oop_address(obj, d));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2007-2009 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
@ -1017,6 +1017,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
const int slop_factor = 2*wordSize;
const int fixed_size = ((sizeof(BytecodeInterpreter) + slop_factor) >> LogBytesPerWord) + // what is the slop factor?
//6815692//methodOopDesc::extra_stack_words() + // extra push slots for MH adapters
frame::memory_parameter_word_sp_offset + // register save area + param window
(native ? frame::interpreter_frame_extra_outgoing_argument_words : 0); // JNI, class
@ -1163,6 +1164,9 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
__ st_ptr(O2, XXX_STATE(_stack)); // PREPUSH
__ lduh(max_stack, O3); // Full size expression stack
guarantee(!EnableMethodHandles, "no support yet for java.dyn.MethodHandle"); //6815692
//6815692//if (EnableMethodHandles)
//6815692// __ inc(O3, methodOopDesc::extra_stack_entries());
__ sll(O3, LogBytesPerWord, O3);
__ sub(O2, O3, O3);
// __ sub(O3, wordSize, O3); // so prepush doesn't look out of bounds
@ -2017,7 +2021,9 @@ static int size_activation_helper(int callee_extra_locals, int max_stack, int mo
const int fixed_size = sizeof(BytecodeInterpreter)/wordSize + // interpreter state object
frame::memory_parameter_word_sp_offset; // register save area + param window
const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
return (round_to(max_stack +
extra_stack +
slop_factor +
fixed_size +
monitor_size +
@ -2104,7 +2110,8 @@ void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill,
// Need +1 here because stack_base points to the word just above the first expr stack entry
// and stack_limit is supposed to point to the word just below the last expr stack entry.
// See generate_compute_interpreter_state.
to_fill->_stack_limit = stack_base - (method->max_stack() + 1);
int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
to_fill->_stack_limit = stack_base - (method->max_stack() + 1 + extra_stack);
to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
// sparc specific

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -29,6 +29,7 @@
address generate_normal_entry(bool synchronized);
address generate_native_entry(bool synchronized);
address generate_abstract_entry(void);
address generate_method_handle_entry(void);
address generate_math_entry(AbstractInterpreter::MethodKind kind);
address generate_empty_entry(void);
address generate_accessor_entry(void);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -235,6 +235,19 @@ address InterpreterGenerator::generate_abstract_entry(void) {
}
// Method handle invoker
// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
address InterpreterGenerator::generate_method_handle_entry(void) {
if (!EnableMethodHandles) {
return generate_abstract_entry();
}
return generate_abstract_entry(); //6815692//
}
//----------------------------------------------------------------------------------------------------
// Entry points & stack frame layout
//
@ -364,6 +377,7 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
case Interpreter::java_lang_math_sin : break;
case Interpreter::java_lang_math_cos : break;
case Interpreter::java_lang_math_tan : break;

View File

@ -0,0 +1,70 @@
/*
* Copyright 1997-2009 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/_methodHandles_sparc.cpp.incl"
#define __ _masm->
address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
address interpreted_entry) {
__ align(wordSize);
address target = __ pc() + sizeof(Data);
while (__ pc() < target) {
__ nop();
__ align(wordSize);
}
MethodHandleEntry* me = (MethodHandleEntry*) __ pc();
me->set_end_address(__ pc()); // set a temporary end_address
me->set_from_interpreted_entry(interpreted_entry);
me->set_type_checking_entry(NULL);
return (address) me;
}
MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _masm,
address start_addr) {
MethodHandleEntry* me = (MethodHandleEntry*) start_addr;
assert(me->end_address() == start_addr, "valid ME");
// Fill in the real end_address:
__ align(wordSize);
me->set_end_address(__ pc());
return me;
}
// Code generation
address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) {
ShouldNotReachHere(); //NYI, 6815692
return NULL;
}
// Generate an "entry" field for a method handle.
// This determines how the method handle will respond to calls.
void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
ShouldNotReachHere(); //NYI, 6815692
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2002-2009 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
@ -142,6 +142,8 @@ REGISTER_DEFINITION(Register, G1_scratch);
REGISTER_DEFINITION(Register, G3_scratch);
REGISTER_DEFINITION(Register, G4_scratch);
REGISTER_DEFINITION(Register, Gtemp);
REGISTER_DEFINITION(Register, G5_method_type);
REGISTER_DEFINITION(Register, G3_method_handle);
REGISTER_DEFINITION(Register, Lentry_args);
#ifdef CC_INTERP

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2009 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
@ -937,12 +937,12 @@ void AdapterGenerator::gen_i2c_adapter(
// Inputs:
// G2_thread - TLS
// G5_method - Method oop
// O0 - Flag telling us to restore SP from O5
// O4_args - Pointer to interpreter's args
// O5 - Caller's saved SP, to be restored if needed
// G4 (Gargs) - Pointer to interpreter's args
// O0..O4 - free for scratch
// O5_savedSP - Caller's saved SP, to be restored if needed
// O6 - Current SP!
// O7 - Valid return address
// L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
// L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
// Outputs:
// G2_thread - TLS
@ -954,7 +954,7 @@ void AdapterGenerator::gen_i2c_adapter(
// F0-F7 - more outgoing args
// O4 is about to get loaded up with compiled callee's args
// Gargs is the incoming argument base, and also an outgoing argument.
__ sub(Gargs, BytesPerWord, Gargs);
#ifdef ASSERT

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -108,6 +108,24 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
}
// Arguments are: required type in G5_method_type, and
// failing object (or NULL) in G3_method_handle.
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
address entry = __ pc();
// expression stack must be empty before entering the VM if an exception
// happened
__ empty_expression_stack();
// load exception object
__ call_VM(Oexception,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_WrongMethodTypeException),
G5_method_type, // required
G3_method_handle); // actual
__ should_not_reach_here();
return entry;
}
address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
address entry = __ pc();
// expression stack must be empty before entering the VM if an exception happened
@ -448,6 +466,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
const int extra_space =
rounded_vm_local_words + // frame local scratch space
//6815692//methodOopDesc::extra_stack_words() + // extra push slots for MH adapters
frame::memory_parameter_word_sp_offset + // register save area
(native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
@ -1447,6 +1466,7 @@ static int size_activation_helper(int callee_extra_locals, int max_stack, int mo
round_to(callee_extra_locals * Interpreter::stackElementWords(), WordsPerLong);
const int max_stack_words = max_stack * Interpreter::stackElementWords();
return (round_to((max_stack_words
//6815692//+ methodOopDesc::extra_stack_words()
+ rounded_vm_local_words
+ frame::memory_parameter_word_sp_offset), WordsPerLong)
// already rounded

View File

@ -114,6 +114,9 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
// shut the door on sizing bugs
int slop = 2*BytesPerInstWord; // 32-bit offset is this much larger than a 13-bit one
assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for sethi;add");
s->set_exception_points(npe_addr, ame_addr);
return s;
@ -208,6 +211,9 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
// shut the door on sizing bugs
int slop = 2*BytesPerInstWord; // 32-bit offset is this much larger than a 13-bit one
assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for sethi;add");
s->set_exception_points(npe_addr, ame_addr);
return s;
@ -233,6 +239,50 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
return (basic + slop);
}
}
// In order to tune these parameters, run the JVM with VM options
// +PrintMiscellaneous and +WizardMode to see information about
// actual itable stubs. Look for lines like this:
// itable #1 at 0x5551212[116] left over: 8
// Reduce the constants so that the "left over" number is 8
// Do not aim at a left-over number of zero, because a very
// large vtable or itable offset (> 4K) will require an extra
// sethi/or pair of instructions.
//
// The JVM98 app. _202_jess has a megamorphic interface call.
// The itable code looks like this:
// Decoding VtableStub itbl[1]@16
// ld [ %o0 + 4 ], %g3
// save %sp, -64, %sp
// ld [ %g3 + 0xe8 ], %l2
// sll %l2, 2, %l2
// add %l2, 0x134, %l2
// and %l2, -8, %l2 ! NOT_LP64 only
// add %g3, %l2, %l2
// add %g3, 4, %g3
// ld [ %l2 ], %l5
// brz,pn %l5, throw_icce
// cmp %l5, %g5
// be %icc, success
// add %l2, 8, %l2
// loop:
// ld [ %l2 ], %l5
// brz,pn %l5, throw_icce
// cmp %l5, %g5
// bne,pn %icc, loop
// add %l2, 8, %l2
// success:
// ld [ %l2 + -4 ], %l2
// ld [ %g3 + %l2 ], %l5
// restore %l5, 0, %g5
// ld [ %g5 + 0x44 ], %g3
// jmp %g3
// nop
// throw_icce:
// sethi %hi(throw_ICCE_entry), %g3
// ! 5 more instructions here, LP64_ONLY
// jmp %g3 + %lo(throw_ICCE_entry)
// restore
}

View File

@ -7609,6 +7609,83 @@ RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_ad
}
// registers on entry:
// - rax ('check' register): required MethodType
// - rcx: method handle
// - rdx, rsi, or ?: killable temp
void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
Register temp_reg,
Label& wrong_method_type) {
if (UseCompressedOops) unimplemented(); // field accesses must decode
// compare method type against that of the receiver
cmpptr(mtype_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
jcc(Assembler::notEqual, wrong_method_type);
}
// A method handle has a "vmslots" field which gives the size of its
// argument list in JVM stack slots. This field is either located directly
// in every method handle, or else is indirectly accessed through the
// method handle's MethodType. This macro hides the distinction.
void MacroAssembler::load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
Register temp_reg) {
if (UseCompressedOops) unimplemented(); // field accesses must decode
// load mh.type.form.vmslots
if (java_dyn_MethodHandle::vmslots_offset_in_bytes() != 0) {
// hoist vmslots into every mh to avoid dependent load chain
movl(vmslots_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmslots_offset_in_bytes, temp_reg)));
} else {
Register temp2_reg = vmslots_reg;
movptr(temp2_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
movptr(temp2_reg, Address(temp2_reg, delayed_value(java_dyn_MethodType::form_offset_in_bytes, temp_reg)));
movl(vmslots_reg, Address(temp2_reg, delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, temp_reg)));
}
}
// registers on entry:
// - rcx: method handle
// - rdx: killable temp (interpreted only)
// - rax: killable temp (compiled only)
void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
assert(mh_reg == rcx, "caller must put MH object in rcx");
assert_different_registers(mh_reg, temp_reg);
if (UseCompressedOops) unimplemented(); // field accesses must decode
// pick out the interpreted side of the handler
movptr(temp_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg)));
// off we go...
jmp(Address(temp_reg, MethodHandleEntry::from_interpreted_entry_offset_in_bytes()));
// for the various stubs which take control at this point,
// see MethodHandles::generate_method_handle_stub
}
Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
int extra_slot_offset) {
// cf. TemplateTable::prepare_invoke(), if (load_receiver).
int stackElementSize = Interpreter::stackElementSize();
int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
#ifdef ASSERT
int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
assert(offset1 - offset == stackElementSize, "correct arithmetic");
#endif
Register scale_reg = noreg;
Address::ScaleFactor scale_factor = Address::no_scale;
if (arg_slot.is_constant()) {
offset += arg_slot.as_constant() * stackElementSize;
} else {
scale_reg = arg_slot.as_register();
scale_factor = Address::times(stackElementSize);
}
offset += wordSize; // return PC is on stack
return Address(rsp, scale_reg, scale_factor, offset);
}
void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
if (!VerifyOops) return;

View File

@ -1857,6 +1857,16 @@ class MacroAssembler: public Assembler {
Register temp_reg,
Label& L_success);
// method handles (JSR 292)
void check_method_handle_type(Register mtype_reg, Register mh_reg,
Register temp_reg,
Label& wrong_method_type);
void load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
Register temp_reg);
void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);
//----
void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0

View File

@ -513,10 +513,11 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
// compute full expression stack limit
const Address size_of_stack (rbx, methodOopDesc::max_stack_offset());
const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_words();
__ load_unsigned_short(rdx, size_of_stack); // get size of expression stack in words
__ negptr(rdx); // so we can subtract in next step
// Allocate expression stack
__ lea(rsp, Address(rsp, rdx, Address::times_ptr));
__ lea(rsp, Address(rsp, rdx, Address::times_ptr, -extra_stack));
__ movptr(STATE(_stack_limit), rsp);
}
@ -659,8 +660,9 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
// Always give one monitor to allow us to start interp if sync method.
// Any additional monitors need a check when moving the expression stack
const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
__ load_unsigned_short(rax, size_of_stack); // get size of expression stack in words
__ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor));
__ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), extra_stack + one_monitor));
__ lea(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size));
#ifdef ASSERT
@ -2185,6 +2187,7 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
case Interpreter::java_lang_math_sin : // fall thru
case Interpreter::java_lang_math_cos : // fall thru
@ -2224,7 +2227,8 @@ int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
const int overhead_size = sizeof(BytecodeInterpreter)/wordSize +
( frame::sender_sp_offset - frame::link_offset) + 2;
const int method_stack = (method->max_locals() + method->max_stack()) *
const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
Interpreter::stackElementWords();
return overhead_size + method_stack + stub_code;
}
@ -2289,7 +2293,8 @@ void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill,
// Need +1 here because stack_base points to the word just above the first expr stack entry
// and stack_limit is supposed to point to the word just below the last expr stack entry.
// See generate_compute_interpreter_state.
to_fill->_stack_limit = stack_base - (method->max_stack() + 1);
int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
to_fill->_stack_limit = stack_base - (method->max_stack() + extra_stack + 1);
to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
to_fill->_self_link = to_fill;
@ -2335,7 +2340,8 @@ int AbstractInterpreter::layout_activation(methodOop method,
monitor_size);
// Now with full size expression stack
int full_frame_size = short_frame_size + method->max_stack() * BytesPerWord;
int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
int full_frame_size = short_frame_size + (method->max_stack() + extra_stack) * BytesPerWord;
// and now with only live portion of the expression stack
short_frame_size = short_frame_size + tempcount * BytesPerWord;

View File

@ -555,13 +555,18 @@ void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point, Register
}
// Jump to from_interpreted entry of a call unless single stepping is possible
// in this thread in which case we must call the i2i entry
void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
// set sender sp
lea(rsi, Address(rsp, wordSize));
// record last_sp
movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), rsi);
}
// Jump to from_interpreted entry of a call unless single stepping is possible
// in this thread in which case we must call the i2i entry
void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
prepare_to_jump_from_interpreted();
if (JvmtiExport::can_post_interpreter_events()) {
Label run_compiled_code;

View File

@ -161,6 +161,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
// jump to an invoked target
void prepare_to_jump_from_interpreted();
void jump_from_interpreted(Register method, Register temp);
// Returning from interpreted functions

View File

@ -551,13 +551,18 @@ void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point,
MacroAssembler::call_VM_leaf_base(entry_point, 3);
}
// Jump to from_interpreted entry of a call unless single stepping is possible
// in this thread in which case we must call the i2i entry
void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
// set sender sp
lea(r13, Address(rsp, wordSize));
// record last_sp
movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), r13);
}
// Jump to from_interpreted entry of a call unless single stepping is possible
// in this thread in which case we must call the i2i entry
void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
prepare_to_jump_from_interpreted();
if (JvmtiExport::can_post_interpreter_events()) {
Label run_compiled_code;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2009 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
@ -176,6 +176,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
void dispatch_via (TosState state, address* table);
// jump to an invoked target
void prepare_to_jump_from_interpreted();
void jump_from_interpreted(Register method, Register temp);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -32,6 +32,7 @@
address generate_normal_entry(bool synchronized);
address generate_native_entry(bool synchronized);
address generate_abstract_entry(void);
address generate_method_handle_entry(void);
address generate_math_entry(AbstractInterpreter::MethodKind kind);
address generate_empty_entry(void);
address generate_accessor_entry(void);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -201,11 +201,12 @@ address InterpreterGenerator::generate_abstract_entry(void) {
address entry_point = __ pc();
// abstract method entry
// remove return address. Not really needed, since exception handling throws away expression stack
__ pop(rbx);
// adjust stack to what a normal return would do
__ mov(rsp, rsi);
// pop return address, reset last_sp to NULL
__ empty_expression_stack();
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
// throw exception
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
// the call_VM checks for exception, so we should never return here.
@ -214,6 +215,20 @@ address InterpreterGenerator::generate_abstract_entry(void) {
return entry_point;
}
// Method handle invoker
// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
address InterpreterGenerator::generate_method_handle_entry(void) {
if (!EnableMethodHandles) {
return generate_abstract_entry();
}
address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm);
return entry_point;
}
// This method tells the deoptimizer how big an interpreted frame must be:
int AbstractInterpreter::size_activation(methodOop method,
int tempcount,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2009 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
@ -294,6 +294,16 @@ address InterpreterGenerator::generate_abstract_entry(void) {
}
// Method handle invoker
// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
address InterpreterGenerator::generate_method_handle_entry(void) {
if (!EnableMethodHandles) {
return generate_abstract_entry();
}
return generate_abstract_entry(); //6815692//
}
// Empty method, generate a very fast return.
address InterpreterGenerator::generate_empty_entry(void) {

File diff suppressed because it is too large Load Diff

View File

@ -2219,6 +2219,16 @@ class StubGenerator: public StubCodeGenerator {
// arraycopy stubs used by compilers
generate_arraycopy_stubs();
// generic method handle stubs
if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
ek < MethodHandles::_EK_LIMIT;
ek = MethodHandles::EntryKind(1 + (int)ek)) {
StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
MethodHandles::generate_method_handle_stub(_masm, ek);
}
}
}

View File

@ -92,6 +92,33 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
return entry;
}
// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
// pc at TOS (just for debugging)
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
address entry = __ pc();
__ pop(rbx); // actual failing object is at TOS
__ pop(rax); // required type is at TOS+4
__ verify_oop(rbx);
__ verify_oop(rax);
// Various method handle types use interpreter registers as temps.
__ restore_bcp();
__ restore_locals();
// Expression stack must be empty before entering the VM for an exception.
__ empty_expression_stack();
__ empty_FPU_stack();
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_WrongMethodTypeException),
// pass required type, failing object (or NULL)
rax, rbx);
return entry;
}
address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
assert(!pass_oop || message == NULL, "either oop or message but not both");
address entry = __ pc();
@ -1370,6 +1397,7 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
case Interpreter::java_lang_math_sin : // fall thru
case Interpreter::java_lang_math_cos : // fall thru
@ -1400,7 +1428,8 @@ int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
// be sure to change this if you add/subtract anything to/from the overhead area
const int overhead_size = -frame::interpreter_frame_initial_sp_offset;
const int method_stack = (method->max_locals() + method->max_stack()) *
const int extra_stack = methodOopDesc::extra_stack_entries();
const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
Interpreter::stackElementWords();
return overhead_size + method_stack + stub_code;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2009 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
@ -100,6 +100,26 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
return entry;
}
// Arguments are: required type in rarg1, failing object (or NULL) in rarg2
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
address entry = __ pc();
__ pop(c_rarg2); // failing object is at TOS
__ pop(c_rarg1); // required type is at TOS+8
// expression stack must be empty before entering the VM if an
// exception happened
__ empty_expression_stack();
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::
throw_WrongMethodTypeException),
// pass required type, failing object (or NULL)
c_rarg1, c_rarg2);
return entry;
}
address TemplateInterpreterGenerator::generate_exception_handler_common(
const char* name, const char* message, bool pass_oop) {
assert(!pass_oop || message == NULL, "either oop or message but not both");
@ -1393,12 +1413,14 @@ address AbstractInterpreterGenerator::generate_method_entry(
case Interpreter::empty : entry_point = ((InterpreterGenerator*) this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry(); break;
case Interpreter::java_lang_math_sin : break;
case Interpreter::java_lang_math_cos : break;
case Interpreter::java_lang_math_tan : break;
case Interpreter::java_lang_math_abs : break;
case Interpreter::java_lang_math_log : break;
case Interpreter::java_lang_math_log10 : break;
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*) this)->generate_method_handle_entry();break;
case Interpreter::java_lang_math_sin : // fall thru
case Interpreter::java_lang_math_cos : // fall thru
case Interpreter::java_lang_math_tan : // fall thru
case Interpreter::java_lang_math_abs : // fall thru
case Interpreter::java_lang_math_log : // fall thru
case Interpreter::java_lang_math_log10 : // fall thru
case Interpreter::java_lang_math_sqrt : entry_point = ((InterpreterGenerator*) this)->generate_math_entry(kind); break;
default : ShouldNotReachHere(); break;
}
@ -1422,7 +1444,8 @@ int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
-(frame::interpreter_frame_initial_sp_offset) + entry_size;
const int stub_code = frame::entry_frame_after_call_words;
const int method_stack = (method->max_locals() + method->max_stack()) *
const int extra_stack = methodOopDesc::extra_stack_entries();
const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
Interpreter::stackElementWords();
return (overhead_size + method_stack + stub_code);
}

View File

@ -108,6 +108,9 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
// shut the door on sizing bugs
int slop = 3; // 32-bit offset is this much larger than an 8-bit one
assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
s->set_exception_points(npe_addr, ame_addr);
return s;
@ -181,6 +184,9 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
// shut the door on sizing bugs
int slop = 3; // 32-bit offset is this much larger than an 8-bit one
assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
s->set_exception_points(npe_addr, ame_addr);
return s;
@ -196,6 +202,41 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
// Itable stub size
return (DebugVtables ? 256 : 66) + (CountCompiledCalls ? 6 : 0);
}
// In order to tune these parameters, run the JVM with VM options
// +PrintMiscellaneous and +WizardMode to see information about
// actual itable stubs. Look for lines like this:
// itable #1 at 0x5551212[65] left over: 3
// Reduce the constants so that the "left over" number is >=3
// for the common cases.
// Do not aim at a left-over number of zero, because a
// large vtable or itable index (> 16) will require a 32-bit
// immediate displacement instead of an 8-bit one.
//
// The JVM98 app. _202_jess has a megamorphic interface call.
// The itable code looks like this:
// Decoding VtableStub itbl[1]@1
// mov 0x4(%ecx),%esi
// mov 0xe8(%esi),%edi
// lea 0x130(%esi,%edi,4),%edi
// add $0x7,%edi
// and $0xfffffff8,%edi
// lea 0x4(%esi),%esi
// mov (%edi),%ebx
// cmp %ebx,%eax
// je success
// loop:
// test %ebx,%ebx
// je throw_icce
// add $0x8,%edi
// mov (%edi),%ebx
// cmp %ebx,%eax
// jne loop
// success:
// mov 0x4(%edi),%edi
// mov (%esi,%edi,1),%ebx
// jmp *0x44(%ebx)
// throw_icce:
// jmp throw_ICCE_entry
}
int VtableStub::pd_code_alignment() {

View File

@ -106,6 +106,9 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
// shut the door on sizing bugs
int slop = 3; // 32-bit offset is this much larger than an 8-bit one
assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
s->set_exception_points(npe_addr, ame_addr);
return s;
@ -191,6 +194,9 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
// shut the door on sizing bugs
int slop = 3; // 32-bit offset is this much larger than an 8-bit one
assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
s->set_exception_points(npe_addr, ame_addr);
return s;
@ -206,6 +212,39 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
return (DebugVtables ? 512 : 72) + (CountCompiledCalls ? 13 : 0) +
(UseCompressedOops ? 32 : 0); // 2 leaqs
}
// In order to tune these parameters, run the JVM with VM options
// +PrintMiscellaneous and +WizardMode to see information about
// actual itable stubs. Look for lines like this:
// itable #1 at 0x5551212[71] left over: 3
// Reduce the constants so that the "left over" number is >=3
// for the common cases.
// Do not aim at a left-over number of zero, because a
// large vtable or itable index (>= 32) will require a 32-bit
// immediate displacement instead of an 8-bit one.
//
// The JVM98 app. _202_jess has a megamorphic interface call.
// The itable code looks like this:
// Decoding VtableStub itbl[1]@12
// mov 0x8(%rsi),%r10
// mov 0x198(%r10),%r11d
// lea 0x218(%r10,%r11,8),%r11
// lea 0x8(%r10),%r10
// mov (%r11),%rbx
// cmp %rbx,%rax
// je success
// loop:
// test %rbx,%rbx
// je throw_icce
// add $0x10,%r11
// mov (%r11),%rbx
// cmp %rbx,%rax
// jne loop
// success:
// mov 0x8(%r11),%r11d
// mov (%r10,%r11,1),%rbx
// jmpq *0x60(%rbx)
// throw_icce:
// jmpq throw_ICCE_entry
}
int VtableStub::pd_code_alignment() {

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 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
@ -674,6 +674,30 @@ int ciMethod::scale_count(int count, float prof_factor) {
return count;
}
// ------------------------------------------------------------------
// invokedynamic support
//
bool ciMethod::is_method_handle_invoke() {
check_is_loaded();
bool flag = ((flags().as_int() & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS);
#ifdef ASSERT
{
VM_ENTRY_MARK;
bool flag2 = get_methodOop()->is_method_handle_invoke();
assert(flag == flag2, "consistent");
}
#endif //ASSERT
return flag;
}
ciInstance* ciMethod::method_handle_type() {
check_is_loaded();
VM_ENTRY_MARK;
oop mtype = get_methodOop()->method_handle_type();
return CURRENT_THREAD_ENV->get_object(mtype)->as_instance();
}
// ------------------------------------------------------------------
// ciMethod::build_method_data
//

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 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
@ -207,6 +207,8 @@ class ciMethod : public ciObject {
bool check_call(int refinfo_index, bool is_static) const;
void build_method_data(); // make sure it exists in the VM also
int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC
bool is_method_handle_invoke();
ciInstance* method_handle_type();
// What kind of ciObject is this?
bool is_method() { return true; }

View File

@ -1842,6 +1842,11 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf
_has_vanilla_constructor = true;
}
if (EnableMethodHandles && m->is_method_handle_invoke()) {
THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(),
"Method handle invokers must be defined internally to the VM", nullHandle);
}
return m;
}
@ -2465,9 +2470,84 @@ void ClassFileParser::java_lang_Class_fix_post(int* next_nonstatic_oop_offset_pt
}
// Force MethodHandle.vmentry to be an unmanaged pointer.
// There is no way for a classfile to express this, so we must help it.
void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
typeArrayHandle* fields_ptr,
FieldAllocationCount *fac_ptr,
TRAPS) {
// Add fake fields for java.dyn.MethodHandle instances
//
// This is not particularly nice, but since there is no way to express
// a native wordSize field in Java, we must do it at this level.
if (!EnableMethodHandles) return;
int word_sig_index = 0;
const int cp_size = cp->length();
for (int index = 1; index < cp_size; index++) {
if (cp->tag_at(index).is_utf8() &&
cp->symbol_at(index) == vmSymbols::machine_word_signature()) {
word_sig_index = index;
break;
}
}
if (word_sig_index == 0)
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
"missing I or J signature (for vmentry) in java.dyn.MethodHandle");
bool found_vmentry = false;
const int n = (*fields_ptr)()->length();
for (int i = 0; i < n; i += instanceKlass::next_offset) {
int name_index = (*fields_ptr)->ushort_at(i + instanceKlass::name_index_offset);
int sig_index = (*fields_ptr)->ushort_at(i + instanceKlass::signature_index_offset);
int acc_flags = (*fields_ptr)->ushort_at(i + instanceKlass::access_flags_offset);
symbolOop f_name = cp->symbol_at(name_index);
symbolOop f_sig = cp->symbol_at(sig_index);
if (f_sig == vmSymbols::byte_signature() &&
f_name == vmSymbols::vmentry_name() &&
(acc_flags & JVM_ACC_STATIC) == 0) {
// Adjust the field type from byte to an unmanaged pointer.
assert(fac_ptr->nonstatic_byte_count > 0, "");
fac_ptr->nonstatic_byte_count -= 1;
(*fields_ptr)->ushort_at_put(i + instanceKlass::signature_index_offset,
word_sig_index);
if (wordSize == jintSize) {
fac_ptr->nonstatic_word_count += 1;
} else {
fac_ptr->nonstatic_double_count += 1;
}
FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i+4);
assert(atype == NONSTATIC_BYTE, "");
FieldAllocationType new_atype = NONSTATIC_WORD;
if (wordSize > jintSize) {
if (Universe::field_type_should_be_aligned(T_LONG)) {
atype = NONSTATIC_ALIGNED_DOUBLE;
} else {
atype = NONSTATIC_DOUBLE;
}
}
(*fields_ptr)->ushort_at_put(i+4, new_atype);
found_vmentry = true;
break;
}
}
if (!found_vmentry)
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
"missing vmentry byte field in java.dyn.MethodHandle");
}
instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
Handle class_loader,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
symbolHandle& parsed_name,
TRAPS) {
@ -2500,6 +2580,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
}
}
_host_klass = host_klass;
_cp_patches = cp_patches;
instanceKlassHandle nullHandle;
@ -2808,6 +2889,11 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
java_lang_Class_fix_pre(&methods, &fac, CHECK_(nullHandle));
}
// adjust the vmentry field declaration in java.dyn.MethodHandle
if (EnableMethodHandles && class_name() == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) {
java_dyn_MethodHandle_fix_pre(cp, &fields, &fac, CHECK_(nullHandle));
}
// Add a fake "discovered" field if it is not present
// for compatibility with earlier jdk's.
if (class_name() == vmSymbols::java_lang_ref_Reference()
@ -3134,7 +3220,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
this_klass->set_method_ordering(method_ordering());
this_klass->set_initial_method_idnum(methods->length());
this_klass->set_name(cp->klass_name_at(this_class_index));
if (LinkWellKnownClasses) // I am well known to myself
if (LinkWellKnownClasses || is_anonymous()) // I am well known to myself
cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
this_klass->set_protection_domain(protection_domain());
this_klass->set_fields_annotations(fields_annotations());

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -33,6 +33,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
u2 _major_version;
u2 _minor_version;
symbolHandle _class_name;
KlassHandle _host_klass;
GrowableArray<Handle>* _cp_patches; // overrides for CP entries
bool _has_finalizer;
@ -145,6 +146,11 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
// Adjust the next_nonstatic_oop_offset to place the fake fields
// before any Java fields.
void java_lang_Class_fix_post(int* next_nonstatic_oop_offset);
// Adjust the field allocation counts for java.dyn.MethodHandle to add
// a fake address (void*) field.
void java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
typeArrayHandle* fields_ptr,
FieldAllocationCount *fac_ptr, TRAPS);
// Format checker methods
void classfile_parse_error(const char* msg, TRAPS);
@ -204,6 +210,10 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
bool is_anonymous() {
assert(AnonymousClasses || _host_klass.is_null(), "");
return _host_klass.not_null();
}
bool has_cp_patch_at(int index) {
assert(AnonymousClasses, "");
assert(index >= 0, "oob");
@ -249,11 +259,13 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
Handle protection_domain,
symbolHandle& parsed_name,
TRAPS) {
return parseClassFile(name, class_loader, protection_domain, NULL, parsed_name, THREAD);
KlassHandle no_host_klass;
return parseClassFile(name, class_loader, protection_domain, no_host_klass, NULL, parsed_name, THREAD);
}
instanceKlassHandle parseClassFile(symbolHandle name,
Handle class_loader,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
symbolHandle& parsed_name,
TRAPS);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2009 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
@ -549,6 +549,63 @@ void Dictionary::reorder_dictionary() {
}
}
SymbolPropertyTable::SymbolPropertyTable(int table_size)
: Hashtable(table_size, sizeof(SymbolPropertyEntry))
{
}
SymbolPropertyTable::SymbolPropertyTable(int table_size, HashtableBucket* t,
int number_of_entries)
: Hashtable(table_size, sizeof(SymbolPropertyEntry), t, number_of_entries)
{
}
SymbolPropertyEntry* SymbolPropertyTable::find_entry(int index, unsigned int hash,
symbolHandle sym) {
assert(index == index_for(sym), "incorrect index?");
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
if (p->hash() == hash && p->symbol() == sym()) {
return p;
}
}
return NULL;
}
SymbolPropertyEntry* SymbolPropertyTable::add_entry(int index, unsigned int hash,
symbolHandle sym) {
assert_locked_or_safepoint(SystemDictionary_lock);
assert(index == index_for(sym), "incorrect index?");
assert(find_entry(index, hash, sym) == NULL, "no double entry");
SymbolPropertyEntry* p = new_entry(hash, sym());
Hashtable::add_entry(index, p);
return p;
}
void SymbolPropertyTable::oops_do(OopClosure* f) {
for (int index = 0; index < table_size(); index++) {
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
f->do_oop((oop*) p->symbol_addr());
if (p->property_oop() != NULL) {
f->do_oop(p->property_oop_addr());
}
}
}
}
void SymbolPropertyTable::methods_do(void f(methodOop)) {
for (int index = 0; index < table_size(); index++) {
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
oop prop = p->property_oop();
if (prop != NULL && prop->is_method()) {
f((methodOop)prop);
}
}
}
}
// ----------------------------------------------------------------------------
#ifndef PRODUCT

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2009 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
@ -217,3 +217,112 @@ class DictionaryEntry : public HashtableEntry {
tty->print_cr("pd set = #%d", count);
}
};
// Entry in a SymbolPropertyTable, mapping a single symbolOop
// to a managed and an unmanaged pointer.
class SymbolPropertyEntry : public HashtableEntry {
friend class VMStructs;
private:
oop _property_oop;
address _property_data;
public:
symbolOop symbol() const { return (symbolOop) literal(); }
oop property_oop() const { return _property_oop; }
void set_property_oop(oop p) { _property_oop = p; }
address property_data() const { return _property_data; }
void set_property_data(address p) { _property_data = p; }
SymbolPropertyEntry* next() const {
return (SymbolPropertyEntry*)HashtableEntry::next();
}
SymbolPropertyEntry** next_addr() {
return (SymbolPropertyEntry**)HashtableEntry::next_addr();
}
oop* symbol_addr() { return literal_addr(); }
oop* property_oop_addr() { return &_property_oop; }
void print_on(outputStream* st) const {
symbol()->print_value_on(st);
st->print(" -> ");
bool printed = false;
if (property_oop() != NULL) {
property_oop()->print_value_on(st);
printed = true;
}
if (property_data() != NULL) {
if (printed) st->print(" and ");
st->print(INTPTR_FORMAT, property_data());
printed = true;
}
st->print_cr(printed ? "" : "(empty)");
}
};
// A system-internal mapping of symbols to pointers, both managed
// and unmanaged. Used to record the auto-generation of each method
// MethodHandle.invoke(S)T, for all signatures (S)T.
class SymbolPropertyTable : public Hashtable {
friend class VMStructs;
private:
SymbolPropertyEntry* bucket(int i) {
return (SymbolPropertyEntry*) Hashtable::bucket(i);
}
// The following method is not MT-safe and must be done under lock.
SymbolPropertyEntry** bucket_addr(int i) {
return (SymbolPropertyEntry**) Hashtable::bucket_addr(i);
}
void add_entry(int index, SymbolPropertyEntry* new_entry) {
ShouldNotReachHere();
}
void set_entry(int index, SymbolPropertyEntry* new_entry) {
ShouldNotReachHere();
}
SymbolPropertyEntry* new_entry(unsigned int hash, symbolOop symbol) {
SymbolPropertyEntry* entry = (SymbolPropertyEntry*) Hashtable::new_entry(hash, symbol);
entry->set_property_oop(NULL);
entry->set_property_data(NULL);
return entry;
}
public:
SymbolPropertyTable(int table_size);
SymbolPropertyTable(int table_size, HashtableBucket* t, int number_of_entries);
void free_entry(SymbolPropertyEntry* entry) {
Hashtable::free_entry(entry);
}
unsigned int compute_hash(symbolHandle sym) {
// Use the regular identity_hash.
return Hashtable::compute_hash(sym);
}
// need not be locked; no state change
SymbolPropertyEntry* find_entry(int index, unsigned int hash, symbolHandle name);
// must be done under SystemDictionary_lock
SymbolPropertyEntry* add_entry(int index, unsigned int hash, symbolHandle name);
// GC support
void oops_do(OopClosure* f);
void methods_do(void f(methodOop));
// Sharing support
void dump(SerializeOopClosure* soc);
void restore(SerializeOopClosure* soc);
void reorder_dictionary();
#ifndef PRODUCT
void print();
#endif
void verify();
};

View File

@ -25,13 +25,24 @@
# include "incls/_precompiled.incl"
# include "incls/_javaClasses.cpp.incl"
static bool find_field(instanceKlass* ik,
symbolOop name_symbol, symbolOop signature_symbol,
fieldDescriptor* fd,
bool allow_super = false) {
if (allow_super)
return ik->find_field(name_symbol, signature_symbol, fd) != NULL;
else
return ik->find_local_field(name_symbol, signature_symbol, fd);
}
// Helpful routine for computing field offsets at run time rather than hardcoding them
static void
compute_offset(int &dest_offset,
klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol) {
klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol,
bool allow_super = false) {
fieldDescriptor fd;
instanceKlass* ik = instanceKlass::cast(klass_oop);
if (!ik->find_local_field(name_symbol, signature_symbol, &fd)) {
if (!find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
ResourceMark rm;
tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string());
fatal("Invalid layout of preloaded class");
@ -42,14 +53,16 @@ compute_offset(int &dest_offset,
// Same as above but for "optional" offsets that might not be present in certain JDK versions
static void
compute_optional_offset(int& dest_offset,
klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol) {
klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol,
bool allow_super = false) {
fieldDescriptor fd;
instanceKlass* ik = instanceKlass::cast(klass_oop);
if (ik->find_local_field(name_symbol, signature_symbol, &fd)) {
if (find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
dest_offset = fd.offset();
}
}
Handle java_lang_String::basic_create(int length, bool tenured, TRAPS) {
// Create the String object first, so there's a chance that the String
// and the char array it points to end up in the same cache line.
@ -2107,13 +2120,324 @@ void java_lang_ref_SoftReference::set_clock(jlong value) {
}
// Support for java_dyn_MethodHandle
int java_dyn_MethodHandle::_type_offset;
int java_dyn_MethodHandle::_vmtarget_offset;
int java_dyn_MethodHandle::_vmentry_offset;
int java_dyn_MethodHandle::_vmslots_offset;
int sun_dyn_MemberName::_clazz_offset;
int sun_dyn_MemberName::_name_offset;
int sun_dyn_MemberName::_type_offset;
int sun_dyn_MemberName::_flags_offset;
int sun_dyn_MemberName::_vmtarget_offset;
int sun_dyn_MemberName::_vmindex_offset;
int sun_dyn_DirectMethodHandle::_vmindex_offset;
int sun_dyn_BoundMethodHandle::_argument_offset;
int sun_dyn_BoundMethodHandle::_vmargslot_offset;
int sun_dyn_AdapterMethodHandle::_conversion_offset;
void java_dyn_MethodHandle::compute_offsets() {
klassOop k = SystemDictionary::MethodHandle_klass();
if (k != NULL && EnableMethodHandles) {
compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true);
compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature(), true);
compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::machine_word_signature(), true);
// Note: MH.vmslots (if it is present) is a hoisted copy of MH.type.form.vmslots.
// It is optional pending experiments to keep or toss.
compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), true);
}
}
void sun_dyn_MemberName::compute_offsets() {
klassOop k = SystemDictionary::MemberName_klass();
if (k != NULL && EnableMethodHandles) {
compute_offset(_clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::object_signature());
compute_offset(_flags_offset, k, vmSymbols::flags_name(), vmSymbols::int_signature());
compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature());
compute_offset(_vmindex_offset, k, vmSymbols::vmindex_name(), vmSymbols::int_signature());
}
}
void sun_dyn_DirectMethodHandle::compute_offsets() {
klassOop k = SystemDictionary::DirectMethodHandle_klass();
if (k != NULL && EnableMethodHandles) {
compute_offset(_vmindex_offset, k, vmSymbols::vmindex_name(), vmSymbols::int_signature(), true);
}
}
void sun_dyn_BoundMethodHandle::compute_offsets() {
klassOop k = SystemDictionary::BoundMethodHandle_klass();
if (k != NULL && EnableMethodHandles) {
compute_offset(_vmargslot_offset, k, vmSymbols::vmargslot_name(), vmSymbols::int_signature(), true);
compute_offset(_argument_offset, k, vmSymbols::argument_name(), vmSymbols::object_signature(), true);
}
}
void sun_dyn_AdapterMethodHandle::compute_offsets() {
klassOop k = SystemDictionary::AdapterMethodHandle_klass();
if (k != NULL && EnableMethodHandles) {
compute_offset(_conversion_offset, k, vmSymbols::conversion_name(), vmSymbols::int_signature(), true);
}
}
oop java_dyn_MethodHandle::type(oop mh) {
return mh->obj_field(_type_offset);
}
void java_dyn_MethodHandle::set_type(oop mh, oop mtype) {
mh->obj_field_put(_type_offset, mtype);
}
int java_dyn_MethodHandle::vmslots(oop mh) {
int vmslots_offset = _vmslots_offset;
if (vmslots_offset != 0) {
#ifdef ASSERT
int x = mh->int_field(vmslots_offset);
int y = compute_vmslots(mh);
assert(x == y, "correct hoisted value");
#endif
return mh->int_field(vmslots_offset);
} else {
return compute_vmslots(mh);
}
}
// if MH.vmslots exists, hoist into it the value of type.form.vmslots
void java_dyn_MethodHandle::init_vmslots(oop mh) {
int vmslots_offset = _vmslots_offset;
if (vmslots_offset != 0) {
mh->int_field_put(vmslots_offset, compute_vmslots(mh));
}
}
// fetch type.form.vmslots, which is the number of JVM stack slots
// required to carry the arguments of this MH
int java_dyn_MethodHandle::compute_vmslots(oop mh) {
oop mtype = type(mh);
if (mtype == NULL) return 0; // Java code would get NPE
oop form = java_dyn_MethodType::form(mtype);
if (form == NULL) return 0; // Java code would get NPE
return java_dyn_MethodTypeForm::vmslots(form);
}
// fetch the low-level entry point for this mh
MethodHandleEntry* java_dyn_MethodHandle::vmentry(oop mh) {
return (MethodHandleEntry*) mh->address_field(_vmentry_offset);
}
void java_dyn_MethodHandle::set_vmentry(oop mh, MethodHandleEntry* me) {
assert(_vmentry_offset != 0, "must be present");
// This is always the final step that initializes a valid method handle:
mh->release_address_field_put(_vmentry_offset, (address) me);
// There should be enough memory barriers on exit from native methods
// to ensure that the MH is fully initialized to all threads before
// Java code can publish it in global data structures.
// But just in case, we use release_address_field_put.
}
/// MemberName accessors
oop sun_dyn_MemberName::clazz(oop mname) {
assert(is_instance(mname), "wrong type");
return mname->obj_field(_clazz_offset);
}
void sun_dyn_MemberName::set_clazz(oop mname, oop clazz) {
assert(is_instance(mname), "wrong type");
mname->obj_field_put(_clazz_offset, clazz);
}
oop sun_dyn_MemberName::name(oop mname) {
assert(is_instance(mname), "wrong type");
return mname->obj_field(_name_offset);
}
void sun_dyn_MemberName::set_name(oop mname, oop name) {
assert(is_instance(mname), "wrong type");
mname->obj_field_put(_name_offset, name);
}
oop sun_dyn_MemberName::type(oop mname) {
assert(is_instance(mname), "wrong type");
return mname->obj_field(_type_offset);
}
void sun_dyn_MemberName::set_type(oop mname, oop type) {
assert(is_instance(mname), "wrong type");
mname->obj_field_put(_type_offset, type);
}
int sun_dyn_MemberName::flags(oop mname) {
assert(is_instance(mname), "wrong type");
return mname->int_field(_flags_offset);
}
void sun_dyn_MemberName::set_flags(oop mname, int flags) {
assert(is_instance(mname), "wrong type");
mname->int_field_put(_flags_offset, flags);
}
oop sun_dyn_MemberName::vmtarget(oop mname) {
assert(is_instance(mname), "wrong type");
return mname->obj_field(_vmtarget_offset);
}
void sun_dyn_MemberName::set_vmtarget(oop mname, oop ref) {
assert(is_instance(mname), "wrong type");
mname->obj_field_put(_vmtarget_offset, ref);
}
int sun_dyn_MemberName::vmindex(oop mname) {
assert(is_instance(mname), "wrong type");
return mname->int_field(_vmindex_offset);
}
void sun_dyn_MemberName::set_vmindex(oop mname, int index) {
assert(is_instance(mname), "wrong type");
mname->int_field_put(_vmindex_offset, index);
}
oop java_dyn_MethodHandle::vmtarget(oop mh) {
assert(is_instance(mh), "MH only");
return mh->obj_field(_vmtarget_offset);
}
void java_dyn_MethodHandle::set_vmtarget(oop mh, oop ref) {
assert(is_instance(mh), "MH only");
mh->obj_field_put(_vmtarget_offset, ref);
}
int sun_dyn_DirectMethodHandle::vmindex(oop mh) {
assert(is_instance(mh), "DMH only");
return mh->int_field(_vmindex_offset);
}
void sun_dyn_DirectMethodHandle::set_vmindex(oop mh, int index) {
assert(is_instance(mh), "DMH only");
mh->int_field_put(_vmindex_offset, index);
}
int sun_dyn_BoundMethodHandle::vmargslot(oop mh) {
assert(is_instance(mh), "BMH only");
return mh->int_field(_vmargslot_offset);
}
oop sun_dyn_BoundMethodHandle::argument(oop mh) {
assert(is_instance(mh), "BMH only");
return mh->obj_field(_argument_offset);
}
int sun_dyn_AdapterMethodHandle::conversion(oop mh) {
assert(is_instance(mh), "AMH only");
return mh->int_field(_conversion_offset);
}
void sun_dyn_AdapterMethodHandle::set_conversion(oop mh, int conv) {
assert(is_instance(mh), "AMH only");
mh->int_field_put(_conversion_offset, conv);
}
// Support for java_dyn_MethodType
int java_dyn_MethodType::_rtype_offset;
int java_dyn_MethodType::_ptypes_offset;
int java_dyn_MethodType::_form_offset;
void java_dyn_MethodType::compute_offsets() {
klassOop k = SystemDictionary::MethodType_klass();
if (k != NULL) {
compute_offset(_rtype_offset, k, vmSymbols::rtype_name(), vmSymbols::class_signature());
compute_offset(_ptypes_offset, k, vmSymbols::ptypes_name(), vmSymbols::class_array_signature());
compute_offset(_form_offset, k, vmSymbols::form_name(), vmSymbols::java_dyn_MethodTypeForm_signature());
}
}
void java_dyn_MethodType::print_signature(oop mt, outputStream* st) {
st->print("(");
objArrayOop pts = ptypes(mt);
for (int i = 0, limit = pts->length(); i < limit; i++) {
java_lang_Class::print_signature(pts->obj_at(i), st);
}
st->print(")");
java_lang_Class::print_signature(rtype(mt), st);
}
symbolOop java_dyn_MethodType::as_signature(oop mt, bool intern_if_not_found, TRAPS) {
ResourceMark rm;
stringStream buffer(128);
print_signature(mt, &buffer);
const char* sigstr = buffer.base();
int siglen = (int) buffer.size();
if (!intern_if_not_found)
return SymbolTable::probe(sigstr, siglen);
else
return oopFactory::new_symbol(sigstr, siglen, THREAD);
}
oop java_dyn_MethodType::rtype(oop mt) {
assert(is_instance(mt), "must be a MethodType");
return mt->obj_field(_rtype_offset);
}
objArrayOop java_dyn_MethodType::ptypes(oop mt) {
assert(is_instance(mt), "must be a MethodType");
return (objArrayOop) mt->obj_field(_ptypes_offset);
}
oop java_dyn_MethodType::form(oop mt) {
assert(is_instance(mt), "must be a MethodType");
return mt->obj_field(_form_offset);
}
oop java_dyn_MethodType::ptype(oop mt, int idx) {
return ptypes(mt)->obj_at(idx);
}
// Support for java_dyn_MethodTypeForm
int java_dyn_MethodTypeForm::_vmslots_offset;
int java_dyn_MethodTypeForm::_erasedType_offset;
void java_dyn_MethodTypeForm::compute_offsets() {
klassOop k = SystemDictionary::MethodTypeForm_klass();
if (k != NULL) {
compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), true);
compute_optional_offset(_erasedType_offset, k, vmSymbols::erasedType_name(), vmSymbols::java_dyn_MethodType_signature(), true);
}
}
int java_dyn_MethodTypeForm::vmslots(oop mtform) {
assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
return mtform->int_field(_vmslots_offset);
}
oop java_dyn_MethodTypeForm::erasedType(oop mtform) {
assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
return mtform->obj_field(_erasedType_offset);
}
// Support for java_security_AccessControlContext
int java_security_AccessControlContext::_context_offset = 0;
int java_security_AccessControlContext::_privilegedContext_offset = 0;
int java_security_AccessControlContext::_isPrivileged_offset = 0;
void java_security_AccessControlContext::compute_offsets() {
assert(_isPrivileged_offset == 0, "offsets should be initialized only once");
fieldDescriptor fd;
@ -2442,6 +2766,15 @@ void JavaClasses::compute_offsets() {
java_lang_System::compute_offsets();
java_lang_Thread::compute_offsets();
java_lang_ThreadGroup::compute_offsets();
if (EnableMethodHandles) {
java_dyn_MethodHandle::compute_offsets();
sun_dyn_MemberName::compute_offsets();
sun_dyn_DirectMethodHandle::compute_offsets();
sun_dyn_BoundMethodHandle::compute_offsets();
sun_dyn_AdapterMethodHandle::compute_offsets();
java_dyn_MethodType::compute_offsets();
java_dyn_MethodTypeForm::compute_offsets();
}
java_security_AccessControlContext::compute_offsets();
// Initialize reflection classes. The layouts of these classes
// changed with the new reflection implementation in JDK 1.4, and
@ -2459,6 +2792,9 @@ void JavaClasses::compute_offsets() {
sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets();
}
sun_misc_AtomicLongCSImpl::compute_offsets();
// generated interpreter code wants to know about the offsets we just computed:
AbstractAssembler::update_delayed_values();
}
#ifndef PRODUCT

View File

@ -151,6 +151,12 @@ class java_lang_Class : AllStatic {
// Conversion
static klassOop as_klassOop(oop java_class);
static BasicType as_BasicType(oop java_class, klassOop* reference_klass = NULL);
static BasicType as_BasicType(oop java_class, KlassHandle* reference_klass) {
klassOop refk_oop = NULL;
BasicType result = as_BasicType(java_class, &refk_oop);
(*reference_klass) = KlassHandle(refk_oop);
return result;
}
static symbolOop as_signature(oop java_class, bool intern_if_not_found, TRAPS);
static void print_signature(oop java_class, outputStream *st);
// Testing
@ -778,6 +784,284 @@ class java_lang_ref_SoftReference: public java_lang_ref_Reference {
};
// Interface to java.dyn.MethodHandle objects
class MethodHandleEntry;
class java_dyn_MethodHandle: AllStatic {
friend class JavaClasses;
private:
static int _vmentry_offset; // assembly code trampoline for MH
static int _vmtarget_offset; // class-specific target reference
static int _type_offset; // the MethodType of this MH
static int _vmslots_offset; // OPTIONAL hoisted type.form.vmslots
static void compute_offsets();
public:
// Accessors
static oop type(oop mh);
static void set_type(oop mh, oop mtype);
static oop vmtarget(oop mh);
static void set_vmtarget(oop mh, oop target);
static MethodHandleEntry* vmentry(oop mh);
static void set_vmentry(oop mh, MethodHandleEntry* data);
static int vmslots(oop mh);
static void init_vmslots(oop mh);
static int compute_vmslots(oop mh);
// Testers
static bool is_subclass(klassOop klass) {
return Klass::cast(klass)->is_subclass_of(SystemDictionary::MethodHandle_klass());
}
static bool is_instance(oop obj) {
return obj != NULL && is_subclass(obj->klass());
}
// Accessors for code generation:
static int type_offset_in_bytes() { return _type_offset; }
static int vmtarget_offset_in_bytes() { return _vmtarget_offset; }
static int vmentry_offset_in_bytes() { return _vmentry_offset; }
static int vmslots_offset_in_bytes() { return _vmslots_offset; }
};
class sun_dyn_DirectMethodHandle: public java_dyn_MethodHandle {
friend class JavaClasses;
private:
// _vmtarget_offset; // method or class or interface
static int _vmindex_offset; // negative or vtable idx or itable idx
static void compute_offsets();
public:
// Accessors
static int vmindex(oop mh);
static void set_vmindex(oop mh, int index);
// Testers
static bool is_subclass(klassOop klass) {
return Klass::cast(klass)->is_subclass_of(SystemDictionary::DirectMethodHandle_klass());
}
static bool is_instance(oop obj) {
return obj != NULL && is_subclass(obj->klass());
}
// Accessors for code generation:
static int vmindex_offset_in_bytes() { return _vmindex_offset; }
};
class sun_dyn_BoundMethodHandle: public java_dyn_MethodHandle {
friend class JavaClasses;
private:
static int _argument_offset; // argument value bound into this MH
static int _vmargslot_offset; // relevant argument slot (<= vmslots)
static void compute_offsets();
public:
static oop argument(oop mh);
static void set_argument(oop mh, oop ref);
static jint vmargslot(oop mh);
static void set_vmargslot(oop mh, jint slot);
// Testers
static bool is_subclass(klassOop klass) {
return Klass::cast(klass)->is_subclass_of(SystemDictionary::BoundMethodHandle_klass());
}
static bool is_instance(oop obj) {
return obj != NULL && is_subclass(obj->klass());
}
static int argument_offset_in_bytes() { return _argument_offset; }
static int vmargslot_offset_in_bytes() { return _vmargslot_offset; }
};
class sun_dyn_AdapterMethodHandle: public sun_dyn_BoundMethodHandle {
friend class JavaClasses;
private:
static int _conversion_offset; // type of conversion to apply
static void compute_offsets();
public:
static int conversion(oop mh);
static void set_conversion(oop mh, int conv);
// Testers
static bool is_subclass(klassOop klass) {
return Klass::cast(klass)->is_subclass_of(SystemDictionary::AdapterMethodHandle_klass());
}
static bool is_instance(oop obj) {
return obj != NULL && is_subclass(obj->klass());
}
// Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
enum {
OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype
OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument
OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another
OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive
OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI)
OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg)
OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg)
OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS)
OP_DROP_ARGS = 0x8, // remove one or more argument slots
OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI)
OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size)
OP_FLYBY = 0xB, // operate first on reified argument list (NYI)
OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI)
CONV_OP_LIMIT = 0xD, // limit of CONV_OP enumeration
CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field
CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
CONV_VMINFO_SHIFT = 0, // position of bits in CONV_VMINFO_MASK
CONV_OP_SHIFT = 8, // position of bits in CONV_OP_MASK
CONV_DEST_TYPE_SHIFT = 12, // byte 2 has the adapter BasicType (if needed)
CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed)
CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1
};
static int conversion_offset_in_bytes() { return _conversion_offset; }
};
// Interface to sun.dyn.MemberName objects
// (These are a private interface for Java code to query the class hierarchy.)
class sun_dyn_MemberName: AllStatic {
friend class JavaClasses;
private:
// From java.dyn.MemberName:
// private Class<?> clazz; // class in which the method is defined
// private String name; // may be null if not yet materialized
// private Object type; // may be null if not yet materialized
// private int flags; // modifier bits; see reflect.Modifier
// private Object vmtarget; // VM-specific target value
// private int vmindex; // method index within class or interface
static int _clazz_offset;
static int _name_offset;
static int _type_offset;
static int _flags_offset;
static int _vmtarget_offset;
static int _vmindex_offset;
static void compute_offsets();
public:
// Accessors
static oop clazz(oop mname);
static void set_clazz(oop mname, oop clazz);
static oop type(oop mname);
static void set_type(oop mname, oop type);
static oop name(oop mname);
static void set_name(oop mname, oop name);
static int flags(oop mname);
static void set_flags(oop mname, int flags);
static int modifiers(oop mname) { return (u2) flags(mname); }
static void set_modifiers(oop mname, int mods)
{ set_flags(mname, (flags(mname) &~ (u2)-1) | (u2)mods); }
static oop vmtarget(oop mname);
static void set_vmtarget(oop mname, oop target);
static int vmindex(oop mname);
static void set_vmindex(oop mname, int index);
// Testers
static bool is_subclass(klassOop klass) {
return Klass::cast(klass)->is_subclass_of(SystemDictionary::MemberName_klass());
}
static bool is_instance(oop obj) {
return obj != NULL && is_subclass(obj->klass());
}
// Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
enum {
MN_IS_METHOD = 0x00010000, // method (not constructor)
MN_IS_CONSTRUCTOR = 0x00020000, // constructor
MN_IS_FIELD = 0x00040000, // field
MN_IS_TYPE = 0x00080000, // nested type
MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers
MN_SEARCH_INTERFACES = 0x00200000, // for MHN.getMembers
VM_INDEX_UNINITIALIZED = -99
};
// Accessors for code generation:
static int clazz_offset_in_bytes() { return _clazz_offset; }
static int type_offset_in_bytes() { return _type_offset; }
static int name_offset_in_bytes() { return _name_offset; }
static int flags_offset_in_bytes() { return _flags_offset; }
static int vmtarget_offset_in_bytes() { return _vmtarget_offset; }
static int vmindex_offset_in_bytes() { return _vmindex_offset; }
};
// Interface to java.dyn.MethodType objects
class java_dyn_MethodType: AllStatic {
friend class JavaClasses;
private:
static int _rtype_offset;
static int _ptypes_offset;
static int _form_offset;
static void compute_offsets();
public:
// Accessors
static oop rtype(oop mt);
static objArrayOop ptypes(oop mt);
static oop form(oop mt);
static oop ptype(oop mt, int index);
static symbolOop as_signature(oop mt, bool intern_if_not_found, TRAPS);
static void print_signature(oop mt, outputStream* st);
static bool is_instance(oop obj) {
return obj != NULL && obj->klass() == SystemDictionary::MethodType_klass();
}
// Accessors for code generation:
static int rtype_offset_in_bytes() { return _rtype_offset; }
static int ptypes_offset_in_bytes() { return _ptypes_offset; }
static int form_offset_in_bytes() { return _form_offset; }
};
class java_dyn_MethodTypeForm: AllStatic {
friend class JavaClasses;
private:
static int _vmslots_offset; // number of argument slots needed
static int _erasedType_offset; // erasedType = canonical MethodType
static void compute_offsets();
public:
// Accessors
static int vmslots(oop mtform);
static oop erasedType(oop mtform);
// Accessors for code generation:
static int vmslots_offset_in_bytes() { return _vmslots_offset; }
static int erasedType_offset_in_bytes() { return _erasedType_offset; }
};
// Interface to java.security.AccessControlContext objects
class java_security_AccessControlContext: AllStatic {

View File

@ -31,6 +31,7 @@ PlaceholderTable* SystemDictionary::_placeholders = NULL;
Dictionary* SystemDictionary::_shared_dictionary = NULL;
LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL;
ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
int SystemDictionary::_number_of_modifications = 0;
@ -966,6 +967,8 @@ klassOop SystemDictionary::parse_stream(symbolHandle class_name,
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
class_loader,
protection_domain,
host_klass,
cp_patches,
parsed_name,
THREAD);
@ -1691,6 +1694,10 @@ void SystemDictionary::always_strong_classes_do(OopClosure* blk) {
// represent classes we're actively loading.
placeholders_do(blk);
// Visit extra methods
if (invoke_method_table() != NULL)
invoke_method_table()->oops_do(blk);
// Loader constraints. We must keep the symbolOop used in the name alive.
constraints()->always_strong_classes_do(blk);
@ -1726,6 +1733,10 @@ void SystemDictionary::oops_do(OopClosure* f) {
// Adjust dictionary
dictionary()->oops_do(f);
// Visit extra methods
if (invoke_method_table() != NULL)
invoke_method_table()->oops_do(f);
// Partially loaded classes
placeholders()->oops_do(f);
@ -1798,6 +1809,8 @@ void SystemDictionary::placeholders_do(void f(symbolOop, oop)) {
void SystemDictionary::methods_do(void f(methodOop)) {
dictionary()->methods_do(f);
if (invoke_method_table() != NULL)
invoke_method_table()->methods_do(f);
}
// ----------------------------------------------------------------------------
@ -1830,6 +1843,7 @@ void SystemDictionary::initialize(TRAPS) {
_number_of_modifications = 0;
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
_resolution_errors = new ResolutionErrorTable(_resolution_error_size);
// _invoke_method_table is allocated lazily in find_method_handle_invoke()
// Allocate private object used as system class loader lock
_system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
@ -1891,6 +1905,9 @@ void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id
wk_klass_name_limits[0] = s;
}
}
// move the starting value forward to the limit:
start_id = limit_id;
}
@ -1924,6 +1941,17 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
instanceKlass::cast(WK_KLASS(final_reference_klass))->set_reference_type(REF_FINAL);
instanceKlass::cast(WK_KLASS(phantom_reference_klass))->set_reference_type(REF_PHANTOM);
WKID meth_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass);
initialize_wk_klasses_until(meth_group_start, scan, CHECK);
if (EnableMethodHandles) {
initialize_wk_klasses_through(meth_group_start, scan, CHECK);
}
if (_well_known_klasses[meth_group_start] == NULL) {
// Skip the rest of the method handle classes, if MethodHandle is not loaded.
scan = WKID(meth_group_end+1);
}
initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK);
_box_klasses[T_BOOLEAN] = WK_KLASS(boolean_klass);
@ -2254,6 +2282,91 @@ char* SystemDictionary::check_signature_loaders(symbolHandle signature,
}
methodOop SystemDictionary::find_method_handle_invoke(symbolHandle signature,
Handle class_loader,
Handle protection_domain,
TRAPS) {
if (!EnableMethodHandles) return NULL;
assert(class_loader.is_null() && protection_domain.is_null(),
"cannot load specialized versions of MethodHandle.invoke");
if (invoke_method_table() == NULL) {
// create this side table lazily
_invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
}
unsigned int hash = invoke_method_table()->compute_hash(signature);
int index = invoke_method_table()->hash_to_index(hash);
SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature);
if (spe == NULL || spe->property_oop() == NULL) {
// Must create lots of stuff here, but outside of the SystemDictionary lock.
Handle mt = compute_method_handle_type(signature(),
class_loader, protection_domain,
CHECK_NULL);
KlassHandle mh_klass = SystemDictionaryHandles::MethodHandle_klass();
methodHandle m = methodOopDesc::make_invoke_method(mh_klass, signature,
mt, CHECK_NULL);
// Now grab the lock. We might have to throw away the new method,
// if a racing thread has managed to install one at the same time.
{
MutexLocker ml(SystemDictionary_lock, Thread::current());
spe = invoke_method_table()->find_entry(index, hash, signature);
if (spe == NULL)
spe = invoke_method_table()->add_entry(index, hash, signature);
if (spe->property_oop() == NULL)
spe->set_property_oop(m());
}
}
methodOop m = (methodOop) spe->property_oop();
assert(m->is_method(), "");
return m;
}
// Ask Java code to find or construct a java.dyn.MethodType for the given
// signature, as interpreted relative to the given class loader.
// Because of class loader constraints, all method handle usage must be
// consistent with this loader.
Handle SystemDictionary::compute_method_handle_type(symbolHandle signature,
Handle class_loader,
Handle protection_domain,
TRAPS) {
Handle empty;
int npts = ArgumentCount(signature()).size();
objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::class_klass(), npts, CHECK_(empty));
int arg = 0;
Handle rt; // the return type from the signature
for (SignatureStream ss(signature()); !ss.is_done(); ss.next()) {
oop mirror;
if (!ss.is_object()) {
mirror = Universe::java_mirror(ss.type());
} else {
symbolOop name_oop = ss.as_symbol(CHECK_(empty));
symbolHandle name(THREAD, name_oop);
klassOop klass = resolve_or_fail(name,
class_loader, protection_domain,
true, CHECK_(empty));
mirror = Klass::cast(klass)->java_mirror();
}
if (ss.at_return_type())
rt = Handle(THREAD, mirror);
else
pts->obj_at_put(arg++, mirror);
}
assert(arg == npts, "");
// call MethodType java.dyn.MethodType::makeImpl(Class rt, Class[] pts, false, true)
bool varargs = false, trusted = true;
JavaCallArguments args(Handle(THREAD, rt()));
args.push_oop(pts());
args.push_int(false);
args.push_int(trusted);
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result,
SystemDictionary::MethodType_klass(),
vmSymbols::makeImpl_name(), vmSymbols::makeImpl_signature(),
&args, CHECK_(empty));
return Handle(THREAD, (oop) result.get_jobject());
}
// Since the identity hash code for symbols changes when the symbols are
// moved from the regular perm gen (hash in the mark word) to the shared
// spaces (hash is the address), the classes loaded into the dictionary

View File

@ -63,6 +63,7 @@ class PlaceholderTable;
class LoaderConstraintTable;
class HashtableBucket;
class ResolutionErrorTable;
class SymbolPropertyTable;
// Certain classes are preloaded, such as java.lang.Object and java.lang.String.
// They are all "well-known", in the sense that no class loader is allowed
@ -131,6 +132,16 @@ class ResolutionErrorTable;
template(reflect_constant_pool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15) \
template(reflect_unsafe_static_field_accessor_impl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \
\
/* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
template(MethodHandle_klass, java_dyn_MethodHandle, Opt) \
template(MemberName_klass, sun_dyn_MemberName, Opt) \
template(MethodHandleImpl_klass, sun_dyn_MethodHandleImpl, Opt) \
template(AdapterMethodHandle_klass, sun_dyn_AdapterMethodHandle, Opt) \
template(BoundMethodHandle_klass, sun_dyn_BoundMethodHandle, Opt) \
template(DirectMethodHandle_klass, sun_dyn_DirectMethodHandle, Opt) \
template(MethodType_klass, java_dyn_MethodType, Opt) \
template(MethodTypeForm_klass, java_dyn_MethodTypeForm, Opt) \
template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
template(vector_klass, java_util_Vector, Pre) \
template(hashtable_klass, java_util_Hashtable, Pre) \
template(stringBuffer_klass, java_lang_StringBuffer, Pre) \
@ -444,6 +455,17 @@ public:
static char* check_signature_loaders(symbolHandle signature, Handle loader1,
Handle loader2, bool is_method, TRAPS);
// JSR 292
// find the java.dyn.MethodHandles::invoke method for a given signature
static methodOop find_method_handle_invoke(symbolHandle signature,
Handle class_loader,
Handle protection_domain,
TRAPS);
// ask Java to compute the java.dyn.MethodType object for a given signature
static Handle compute_method_handle_type(symbolHandle signature,
Handle class_loader,
Handle protection_domain,
TRAPS);
// Utility for printing loader "name" as part of tracing constraints
static const char* loader_name(oop loader) {
return ((loader) == NULL ? "<bootloader>" :
@ -460,6 +482,7 @@ public:
enum Constants {
_loader_constraint_size = 107, // number of entries in constraint table
_resolution_error_size = 107, // number of entries in resolution error table
_invoke_method_size = 139, // number of entries in invoke method table
_nof_buckets = 1009 // number of buckets in hash table
};
@ -489,6 +512,9 @@ public:
// Resolution errors
static ResolutionErrorTable* _resolution_errors;
// Invoke methods (JSR 292)
static SymbolPropertyTable* _invoke_method_table;
public:
// for VM_CounterDecay iteration support
friend class CounterDecay;
@ -506,6 +532,7 @@ private:
static PlaceholderTable* placeholders() { return _placeholders; }
static LoaderConstraintTable* constraints() { return _loader_constraints; }
static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
static SymbolPropertyTable* invoke_method_table() { return _invoke_method_table; }
// Basic loading operations
static klassOop resolve_instance_class_or_null(symbolHandle class_name, Handle class_loader, Handle protection_domain, TRAPS);

View File

@ -216,7 +216,26 @@
template(sun_reflect_UnsafeStaticFieldAccessorImpl, "sun/reflect/UnsafeStaticFieldAccessorImpl")\
template(base_name, "base") \
\
/* common method names */ \
/* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \
template(java_dyn_MethodHandle, "java/dyn/MethodHandle") \
template(java_dyn_MethodType, "java/dyn/MethodType") \
template(java_dyn_WrongMethodTypeException, "java/dyn/WrongMethodTypeException") \
template(java_dyn_MethodType_signature, "Ljava/dyn/MethodType;") \
template(java_dyn_MethodHandle_signature, "Ljava/dyn/MethodHandle;") \
/* internal classes known only to the JVM: */ \
template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") \
template(java_dyn_MethodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") \
template(sun_dyn_MemberName, "sun/dyn/MemberName") \
template(sun_dyn_MethodHandleImpl, "sun/dyn/MethodHandleImpl") \
template(sun_dyn_AdapterMethodHandle, "sun/dyn/AdapterMethodHandle") \
template(sun_dyn_BoundMethodHandle, "sun/dyn/BoundMethodHandle") \
template(sun_dyn_DirectMethodHandle, "sun/dyn/DirectMethodHandle") \
template(makeImpl_name, "makeImpl") /*MethodType::makeImpl*/ \
template(makeImpl_signature, "(Ljava/lang/Class;[Ljava/lang/Class;ZZ)Ljava/dyn/MethodType;") \
NOT_LP64( do_alias(machine_word_signature, int_signature) ) \
LP64_ONLY( do_alias(machine_word_signature, long_signature) ) \
\
/* common method and field names */ \
template(object_initializer_name, "<init>") \
template(class_initializer_name, "<clinit>") \
template(println_name, "println") \
@ -289,6 +308,21 @@
template(bitCount_name, "bitCount") \
template(profile_name, "profile") \
template(equals_name, "equals") \
template(toString_name, "toString") \
template(values_name, "values") \
template(receiver_name, "receiver") \
template(vmtarget_name, "vmtarget") \
template(vmentry_name, "vmentry") \
template(vmslots_name, "vmslots") \
template(vmindex_name, "vmindex") \
template(vmargslot_name, "vmargslot") \
template(flags_name, "flags") \
template(argument_name, "argument") \
template(conversion_name, "conversion") \
template(rtype_name, "rtype") \
template(ptypes_name, "ptypes") \
template(form_name, "form") \
template(erasedType_name, "erasedType") \
\
/* non-intrinsic name/signature pairs: */ \
template(register_method_name, "register") \
@ -353,6 +387,7 @@
template(void_classloader_signature, "()Ljava/lang/ClassLoader;") \
template(void_object_signature, "()Ljava/lang/Object;") \
template(void_class_signature, "()Ljava/lang/Class;") \
template(void_string_signature, "()Ljava/lang/String;") \
template(object_array_object_object_signature, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\
template(exception_void_signature, "(Ljava/lang/Exception;)V") \
template(protectiondomain_signature, "[Ljava/security/ProtectionDomain;") \

View File

@ -107,13 +107,11 @@ address VtableStubs::create_stub(bool is_vtable_stub, int vtable_index, methodOo
s = create_itable_stub(vtable_index);
}
enter(is_vtable_stub, vtable_index, s);
#ifndef PRODUCT
if (PrintAdapterHandlers) {
tty->print_cr("Decoding VtableStub %s[%d]@%d",
is_vtable_stub? "vtbl": "itbl", vtable_index, VtableStub::receiver_location());
Disassembler::decode(s->code_begin(), s->code_end());
}
#endif
}
return s->entry_point();
}

View File

@ -254,6 +254,7 @@ assembler_<arch>.cpp cardTableModRefBS.hpp
assembler_<arch>.cpp collectedHeap.inline.hpp
assembler_<arch>.cpp interfaceSupport.hpp
assembler_<arch>.cpp interpreter.hpp
assembler_<arch>.cpp methodHandles.hpp
assembler_<arch>.cpp objectMonitor.hpp
assembler_<arch>.cpp os.hpp
assembler_<arch>.cpp resourceArea.hpp
@ -1274,6 +1275,7 @@ cpCacheKlass.cpp bytecodes.hpp
cpCacheKlass.cpp collectedHeap.hpp
cpCacheKlass.cpp constantPoolOop.hpp
cpCacheKlass.cpp cpCacheKlass.hpp
cpCacheKlass.cpp genOopClosures.inline.hpp
cpCacheKlass.cpp handles.inline.hpp
cpCacheKlass.cpp javaClasses.hpp
cpCacheKlass.cpp markSweep.inline.hpp
@ -2202,6 +2204,7 @@ interpreter_<arch_model>.cpp interpreterGenerator.hpp
interpreter_<arch_model>.cpp jvmtiExport.hpp
interpreter_<arch_model>.cpp jvmtiThreadState.hpp
interpreter_<arch_model>.cpp methodDataOop.hpp
interpreter_<arch_model>.cpp methodHandles.hpp
interpreter_<arch_model>.cpp methodOop.hpp
interpreter_<arch_model>.cpp oop.inline.hpp
interpreter_<arch_model>.cpp sharedRuntime.hpp
@ -2596,6 +2599,7 @@ linkResolver.cpp handles.inline.hpp
linkResolver.cpp instanceKlass.hpp
linkResolver.cpp interpreterRuntime.hpp
linkResolver.cpp linkResolver.hpp
linkResolver.cpp methodHandles.hpp
linkResolver.cpp nativeLookup.hpp
linkResolver.cpp objArrayOop.hpp
linkResolver.cpp reflection.hpp
@ -2812,6 +2816,25 @@ methodDataOop.hpp oop.hpp
methodDataOop.hpp orderAccess.hpp
methodDataOop.hpp universe.hpp
methodHandles.hpp frame.inline.hpp
methodHandles.hpp globals.hpp
methodHandles.hpp interfaceSupport.hpp
methodHandles.hpp javaClasses.hpp
methodHandles.hpp vmSymbols.hpp
methodHandles.cpp allocation.inline.hpp
methodHandles.cpp interpreter.hpp
methodHandles.cpp javaCalls.hpp
methodHandles.cpp methodHandles.hpp
methodHandles.cpp oopFactory.hpp
methodHandles.cpp reflection.hpp
methodHandles.cpp signature.hpp
methodHandles.cpp symbolTable.hpp
methodHandles_<arch>.cpp allocation.inline.hpp
methodHandles_<arch>.cpp interpreter.hpp
methodHandles_<arch>.cpp methodHandles.hpp
methodKlass.cpp collectedHeap.inline.hpp
methodKlass.cpp constMethodKlass.hpp
methodKlass.cpp gcLocker.hpp
@ -3061,6 +3084,7 @@ oop.inline.hpp arrayKlass.hpp
oop.inline.hpp arrayOop.hpp
oop.inline.hpp atomic.hpp
oop.inline.hpp barrierSet.inline.hpp
oop.inline.hpp bytes_<arch>.hpp
oop.inline.hpp cardTableModRefBS.hpp
oop.inline.hpp collectedHeap.inline.hpp
oop.inline.hpp compactingPermGenGen.hpp
@ -3674,6 +3698,7 @@ sharedRuntime.cpp interpreterRuntime.hpp
sharedRuntime.cpp interpreter.hpp
sharedRuntime.cpp javaCalls.hpp
sharedRuntime.cpp jvmtiExport.hpp
sharedRuntime.cpp methodHandles.hpp
sharedRuntime.cpp jvmtiRedefineClassesTrace.hpp
sharedRuntime.cpp nativeInst_<arch>.hpp
sharedRuntime.cpp nativeLookup.hpp
@ -3862,6 +3887,7 @@ stubGenerator_<arch_model>.cpp frame.inline.hpp
stubGenerator_<arch_model>.cpp handles.inline.hpp
stubGenerator_<arch_model>.cpp instanceOop.hpp
stubGenerator_<arch_model>.cpp interpreter.hpp
stubGenerator_<arch_model>.cpp methodHandles.hpp
stubGenerator_<arch_model>.cpp methodOop.hpp
stubGenerator_<arch_model>.cpp nativeInst_<arch>.hpp
stubGenerator_<arch_model>.cpp objArrayKlass.hpp

View File

@ -36,6 +36,12 @@ constantPoolKlass.cpp psPromotionManager.inline.hpp
constantPoolKlass.cpp psScavenge.inline.hpp
constantPoolKlass.cpp parOopClosures.inline.hpp
constantPoolKlass.cpp cardTableRS.hpp
constantPoolKlass.cpp oop.pcgc.inline.hpp
constantPoolKlass.cpp psPromotionManager.inline.hpp
constantPoolKlass.cpp psScavenge.inline.hpp
constantPoolKlass.cpp parOopClosures.inline.hpp
genCollectedHeap.cpp concurrentMarkSweepThread.hpp
genCollectedHeap.cpp vmCMSOperations.hpp

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -61,6 +61,7 @@ class AbstractInterpreter: AllStatic {
empty, // empty method (code: _return)
accessor, // accessor method (code: _aload_0, _getfield, _(a|i)return)
abstract, // abstract method (throws an AbstractMethodException)
method_handle, // java.dyn.MethodHandles::invoke
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)
@ -91,8 +92,6 @@ class AbstractInterpreter: AllStatic {
static address _rethrow_exception_entry; // rethrows an activation in previous frame
friend class AbstractInterpreterGenerator;
friend class InterpreterGenerator;
friend class InterpreterMacroAssembler;

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -114,6 +114,7 @@ void CppInterpreterGenerator::generate_all() {
method_entry(empty);
method_entry(accessor);
method_entry(abstract);
method_entry(method_handle);
method_entry(java_lang_math_sin );
method_entry(java_lang_math_cos );
method_entry(java_lang_math_tan );

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -168,10 +168,14 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m)
// Abstract method?
if (m->is_abstract()) return abstract;
// Invoker for method handles?
if (m->is_method_handle_invoke()) return method_handle;
// Native method?
// Note: This test must come _before_ the test for intrinsic
// methods. See also comments below.
if (m->is_native()) {
assert(!m->is_method_handle_invoke(), "overlapping bits here, watch out");
return m->is_synchronized() ? native_synchronized : native;
}
@ -249,6 +253,7 @@ void AbstractInterpreter::print_method_kind(MethodKind kind) {
case empty : tty->print("empty" ); break;
case accessor : tty->print("accessor" ); break;
case abstract : tty->print("abstract" ); break;
case method_handle : tty->print("method_handle" ); 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;

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -293,6 +293,24 @@ IRT_ENTRY(void, InterpreterRuntime::throw_ClassCastException(
THROW_MSG(vmSymbols::java_lang_ClassCastException(), message);
IRT_END
// required can be either a MethodType, or a Class (for a single argument)
// actual (if not null) can be either a MethodHandle, or an arbitrary value (for a single argument)
IRT_ENTRY(void, InterpreterRuntime::throw_WrongMethodTypeException(JavaThread* thread,
oopDesc* required,
oopDesc* actual)) {
ResourceMark rm(thread);
char* message = SharedRuntime::generate_wrong_method_type_message(thread, required, actual);
if (ProfileTraps) {
note_trap(thread, Deoptimization::Reason_constraint, CHECK);
}
// create exception
THROW_MSG(vmSymbols::java_dyn_WrongMethodTypeException(), message);
}
IRT_END
// exception_handler_for_exception(...) returns the continuation address,
// the exception oop (via TLS) and sets the bci/bcp for the continuation.

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -66,6 +66,7 @@ class InterpreterRuntime: AllStatic {
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 throw_WrongMethodTypeException(JavaThread* thread, oopDesc* mtype = NULL, oopDesc* mhandle = NULL);
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);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -151,6 +151,20 @@ void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle
result = methodHandle(THREAD, ik->lookup_method_in_all_interfaces(name(), signature()));
}
void LinkResolver::lookup_implicit_method(methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS) {
if (EnableMethodHandles && MethodHandles::enabled() &&
name == vmSymbolHandles::invoke_name() && klass() == SystemDictionary::MethodHandle_klass()) {
methodOop result_oop = SystemDictionary::find_method_handle_invoke(signature,
Handle(),
Handle(),
CHECK);
if (result_oop != NULL) {
assert(result_oop->is_method_handle_invoke() && result_oop->signature() == signature(), "consistent");
result = methodHandle(THREAD, result_oop);
}
}
}
void LinkResolver::check_method_accessability(KlassHandle ref_klass,
KlassHandle resolved_klass,
KlassHandle sel_klass,
@ -239,6 +253,11 @@ void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle res
// 3. lookup method in all the interfaces implemented by the resolved klass
lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK);
if (resolved_method.is_null()) {
// JSR 292: see if this is an implicitly generated method MethodHandle.invoke(*...)
lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, CHECK);
}
if (resolved_method.is_null()) {
// 4. method lookup failed
ResourceMark rm(THREAD);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -103,6 +103,7 @@ class LinkResolver: AllStatic {
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 void lookup_implicit_method (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
static int vtable_index_of_miranda_method(KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -168,6 +168,7 @@ address TemplateInterpreter::_throw_ArrayIndexOutOfBoundsException_entry = NU
address TemplateInterpreter::_throw_ArrayStoreException_entry = NULL;
address TemplateInterpreter::_throw_ArithmeticException_entry = NULL;
address TemplateInterpreter::_throw_ClassCastException_entry = NULL;
address TemplateInterpreter::_throw_WrongMethodType_entry = NULL;
address TemplateInterpreter::_throw_NullPointerException_entry = NULL;
address TemplateInterpreter::_throw_StackOverflowError_entry = NULL;
address TemplateInterpreter::_throw_exception_entry = NULL;
@ -341,6 +342,7 @@ void TemplateInterpreterGenerator::generate_all() {
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_WrongMethodType_entry = generate_WrongMethodType_handler();
Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException" , NULL );
Interpreter::_throw_StackOverflowError_entry = generate_StackOverflowError_handler();
}
@ -358,6 +360,7 @@ void TemplateInterpreterGenerator::generate_all() {
method_entry(empty)
method_entry(accessor)
method_entry(abstract)
method_entry(method_handle)
method_entry(java_lang_math_sin )
method_entry(java_lang_math_cos )
method_entry(java_lang_math_tan )

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -77,6 +77,7 @@ class TemplateInterpreter: public AbstractInterpreter {
friend class VMStructs;
friend class InterpreterMacroAssembler;
friend class TemplateInterpreterGenerator;
friend class InterpreterGenerator;
friend class TemplateTable;
// friend class Interpreter;
public:
@ -93,6 +94,7 @@ class TemplateInterpreter: public AbstractInterpreter {
static address _throw_ArrayStoreException_entry;
static address _throw_ArithmeticException_entry;
static address _throw_ClassCastException_entry;
static address _throw_WrongMethodType_entry;
static address _throw_NullPointerException_entry;
static address _throw_exception_entry;
@ -137,6 +139,7 @@ class TemplateInterpreter: public AbstractInterpreter {
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_WrongMethodType_entry() { return _throw_WrongMethodType_entry; }
static address throw_NullPointerException_entry() { return _throw_NullPointerException_entry; }
static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; }

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -48,6 +48,7 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator {
}
address generate_exception_handler_common(const char* name, const char* message, bool pass_oop);
address generate_ClassCastException_handler();
address generate_WrongMethodType_handler();
address generate_ArrayIndexOutOfBounds_handler(const char* name);
address generate_continuation_for(TosState state);
address generate_return_entry_for(TosState state, int step);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2009 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
@ -928,6 +928,9 @@ public:
// shared classes at runtime, where constraints were previously created.
guarantee(SystemDictionary::constraints()->number_of_entries() == 0,
"loader constraints are not saved");
// Revisit and implement this if we prelink method handle call sites:
guarantee(SystemDictionary::invoke_method_table()->number_of_entries() == 0,
"invoke method table is not saved");
GenCollectedHeap* gch = GenCollectedHeap::heap();
// At this point, many classes have been loaded.

View File

@ -298,7 +298,11 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) {
m->code()->print_value_on(st);
st->cr();
}
if (m->is_native()) {
if (m->is_method_handle_invoke()) {
st->print_cr(" - invoke method type: " INTPTR_FORMAT, (address) m->method_handle_type());
// m is classified as native, but it does not have an interesting
// native_function or signature handler
} else if (m->is_native()) {
st->print_cr(" - native function: " INTPTR_FORMAT, m->native_function());
st->print_cr(" - signature handler: " INTPTR_FORMAT, m->signature_handler());
}

View File

@ -304,6 +304,12 @@ void methodOopDesc::cleanup_inline_caches() {
}
int methodOopDesc::extra_stack_words() {
// not an inline function, to avoid a header dependency on Interpreter
return extra_stack_entries() * Interpreter::stackElementSize();
}
void methodOopDesc::compute_size_of_parameters(Thread *thread) {
symbolHandle h_signature(thread, signature());
ArgumentSizeComputer asc(h_signature);
@ -564,6 +570,11 @@ void methodOopDesc::set_signature_handler(address handler) {
bool methodOopDesc::is_not_compilable(int comp_level) const {
if (is_method_handle_invoke()) {
// compilers must recognize this method specially, or not at all
return true;
}
methodDataOop mdo = method_data();
if (mdo != NULL
&& (uint)mdo->decompile_count() > (uint)PerMethodRecompilationCutoff) {
@ -651,7 +662,7 @@ void methodOopDesc::link_method(methodHandle h_method, TRAPS) {
assert(entry != NULL, "interpreter entry must be non-null");
// Sets both _i2i_entry and _from_interpreted_entry
set_interpreter_entry(entry);
if (is_native()) {
if (is_native() && !is_method_handle_invoke()) {
set_native_function(
SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
!native_bind_event_is_interesting);
@ -783,6 +794,100 @@ bool methodOopDesc::should_not_be_cached() const {
return false;
}
// Constant pool structure for invoke methods:
enum {
_imcp_invoke_name = 1, // utf8: 'invoke'
_imcp_invoke_signature, // utf8: (variable symbolOop)
_imcp_method_type_value, // string: (variable java/dyn/MethodType, sic)
_imcp_limit
};
oop methodOopDesc::method_handle_type() const {
if (!is_method_handle_invoke()) { assert(false, "caller resp."); return NULL; }
oop mt = constants()->resolved_string_at(_imcp_method_type_value);
assert(mt->klass() == SystemDictionary::MethodType_klass(), "");
return mt;
}
jint* methodOopDesc::method_type_offsets_chain() {
static jint pchase[] = { -1, -1, -1 };
if (pchase[0] == -1) {
jint step0 = in_bytes(constants_offset());
jint step1 = (constantPoolOopDesc::header_size() + _imcp_method_type_value) * HeapWordSize;
// do this in reverse to avoid races:
OrderAccess::release_store(&pchase[1], step1);
OrderAccess::release_store(&pchase[0], step0);
}
return pchase;
}
methodHandle methodOopDesc::make_invoke_method(KlassHandle holder,
symbolHandle signature,
Handle method_type, TRAPS) {
methodHandle empty;
assert(holder() == SystemDictionary::MethodHandle_klass(),
"must be a JSR 292 magic type");
if (TraceMethodHandles) {
tty->print("Creating invoke method for ");
signature->print_value();
tty->cr();
}
constantPoolHandle cp;
{
constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, IsSafeConc, CHECK_(empty));
cp = constantPoolHandle(THREAD, cp_oop);
}
cp->symbol_at_put(_imcp_invoke_name, vmSymbols::invoke_name());
cp->symbol_at_put(_imcp_invoke_signature, signature());
cp->string_at_put(_imcp_method_type_value, vmSymbols::void_signature());
cp->set_pool_holder(holder());
// set up the fancy stuff:
cp->pseudo_string_at_put(_imcp_method_type_value, method_type());
methodHandle m;
{
int flags_bits = (JVM_MH_INVOKE_BITS | JVM_ACC_PUBLIC | JVM_ACC_FINAL);
methodOop m_oop = oopFactory::new_method(0, accessFlags_from(flags_bits),
0, 0, 0, IsSafeConc, CHECK_(empty));
m = methodHandle(THREAD, m_oop);
}
m->set_constants(cp());
m->set_name_index(_imcp_invoke_name);
m->set_signature_index(_imcp_invoke_signature);
assert(m->name() == vmSymbols::invoke_name(), "");
assert(m->signature() == signature(), "");
#ifdef CC_INTERP
ResultTypeFinder rtf(signature());
m->set_result_index(rtf.type());
#endif
m->compute_size_of_parameters(THREAD);
m->set_exception_table(Universe::the_empty_int_array());
// Finally, set up its entry points.
assert(m->method_handle_type() == method_type(), "");
assert(m->can_be_statically_bound(), "");
m->set_vtable_index(methodOopDesc::nonvirtual_vtable_index);
m->link_method(m, CHECK_(empty));
#ifdef ASSERT
// Make sure the pointer chase works.
address p = (address) m();
for (jint* pchase = method_type_offsets_chain(); (*pchase) != -1; pchase++) {
p = *(address*)(p + (*pchase));
}
assert((oop)p == method_type(), "pointer chase is correct");
#endif
if (TraceMethodHandles)
m->print_on(tty);
return m;
}
methodHandle methodOopDesc:: clone_with_new_data(methodHandle m, u_char* new_code, int new_code_length,
u_char* new_compressed_linenumber_table, int new_compressed_linenumber_size, TRAPS) {

View File

@ -320,6 +320,7 @@ class methodOopDesc : public oopDesc {
enum VtableIndexFlag {
// Valid vtable indexes are non-negative (>= 0).
// These few negative values are used as sentinels.
highest_unused_vtable_index_value = -5,
invalid_vtable_index = -4, // distinct from any valid vtable index
garbage_vtable_index = -3, // not yet linked; no vtable layout yet
nonvirtual_vtable_index = -2 // there is no need for vtable dispatch
@ -523,6 +524,18 @@ class methodOopDesc : public oopDesc {
// Reflection support
bool is_overridden_in(klassOop k) const;
// JSR 292 support
bool is_method_handle_invoke() const { return access_flags().is_method_handle_invoke(); }
static methodHandle make_invoke_method(KlassHandle holder,
symbolHandle signature,
Handle method_type,
TRAPS);
// these operate only on invoke methods:
oop method_handle_type() const;
static jint* method_type_offsets_chain(); // series of pointer-offsets, terminated by -1
// presize interpreter frames for extra interpreter stack entries, if needed
static int extra_stack_entries() { return EnableMethodHandles ? (int)MethodHandlePushLimit : 0; }
static int extra_stack_words(); // = extra_stack_entries() * Interpreter::stackElementSize()
// RedefineClasses() support:
bool is_old() const { return access_flags().is_old(); }
void set_is_old() { _access_flags.set_is_old(); }

View File

@ -263,6 +263,9 @@ class oopDesc {
jdouble double_field_acquire(int offset) const;
void release_double_field_put(int offset, jdouble contents);
address address_field_acquire(int offset) const;
void release_address_field_put(int offset, address contents);
// printing functions for VM debugging
void print_on(outputStream* st) const; // First level print
void print_value_on(outputStream* st) const; // Second level print.

View File

@ -349,6 +349,9 @@ inline void oopDesc::release_float_field_put(int offset, jfloat contents) { Or
inline jdouble oopDesc::double_field_acquire(int offset) const { return OrderAccess::load_acquire(double_field_addr(offset)); }
inline void oopDesc::release_double_field_put(int offset, jdouble contents) { OrderAccess::release_store(double_field_addr(offset), contents); }
inline address oopDesc::address_field_acquire(int offset) const { return (address) OrderAccess::load_ptr_acquire(address_field_addr(offset)); }
inline void oopDesc::release_address_field_put(int offset, address contents) { OrderAccess::release_store_ptr(address_field_addr(offset), contents); }
inline int oopDesc::size_given_klass(Klass* klass) {
int lh = klass->layout_helper();
int s = lh >> LogHeapWordSize; // deliver size scaled by wordSize

View File

@ -1043,6 +1043,51 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype,
//=============================================================================
uint AllocateArrayNode::size_of() const { return sizeof(*this); }
Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this;
const Type* type = phase->type(Ideal_length());
if (type->isa_int() && type->is_int()->_hi < 0) {
if (can_reshape) {
PhaseIterGVN *igvn = phase->is_IterGVN();
// Unreachable fall through path (negative array length),
// the allocation can only throw so disconnect it.
Node* proj = proj_out(TypeFunc::Control);
Node* catchproj = NULL;
if (proj != NULL) {
for (DUIterator_Fast imax, i = proj->fast_outs(imax); i < imax; i++) {
Node *cn = proj->fast_out(i);
if (cn->is_Catch()) {
catchproj = cn->as_Multi()->proj_out(CatchProjNode::fall_through_index);
break;
}
}
}
if (catchproj != NULL && catchproj->outcnt() > 0 &&
(catchproj->outcnt() > 1 ||
catchproj->unique_out()->Opcode() != Op_Halt)) {
assert(catchproj->is_CatchProj(), "must be a CatchProjNode");
Node* nproj = catchproj->clone();
igvn->register_new_node_with_optimizer(nproj);
Node *frame = new (phase->C, 1) ParmNode( phase->C->start(), TypeFunc::FramePtr );
frame = phase->transform(frame);
// Halt & Catch Fire
Node *halt = new (phase->C, TypeFunc::Parms) HaltNode( nproj, frame );
phase->C->root()->add_req(halt);
phase->transform(halt);
igvn->replace_node(catchproj, phase->C->top());
return this;
}
} else {
// Can't correct it during regular GVN so register for IGVN
phase->C->record_for_igvn(this);
}
}
return NULL;
}
// Retrieve the length from the AllocateArrayNode. Narrow the type with a
// CastII, if appropriate. If we are not allowed to create new nodes, and
// a CastII is appropriate, return NULL.

View File

@ -762,6 +762,7 @@ public:
}
virtual int Opcode() const;
virtual uint size_of() const; // Size is bigger
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
// Dig the length operand out of a array allocation site.
Node* Ideal_length() {

View File

@ -806,8 +806,7 @@ void PhaseMacroExpand::process_users_of_allocation(AllocateNode *alloc) {
}
} else if (use->is_AddP()) {
// raw memory addresses used only by the initialization
_igvn.hash_delete(use);
_igvn.subsume_node(use, C->top());
_igvn.replace_node(use, C->top());
} else {
assert(false, "only Initialize or AddP expected");
}
@ -1291,8 +1290,7 @@ void PhaseMacroExpand::expand_allocate_common(
if (_fallthroughcatchproj != NULL) {
ctrl = _fallthroughcatchproj->clone();
transform_later(ctrl);
_igvn.hash_delete(_fallthroughcatchproj);
_igvn.subsume_node(_fallthroughcatchproj, result_region);
_igvn.replace_node(_fallthroughcatchproj, result_region);
} else {
ctrl = top();
}
@ -1303,8 +1301,7 @@ void PhaseMacroExpand::expand_allocate_common(
} else {
slow_result = _resproj->clone();
transform_later(slow_result);
_igvn.hash_delete(_resproj);
_igvn.subsume_node(_resproj, result_phi_rawoop);
_igvn.replace_node(_resproj, result_phi_rawoop);
}
// Plug slow-path into result merge point
@ -1613,18 +1610,15 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) {
assert(membar != NULL && membar->Opcode() == Op_MemBarAcquire, "");
Node* ctrlproj = membar->proj_out(TypeFunc::Control);
Node* memproj = membar->proj_out(TypeFunc::Memory);
_igvn.hash_delete(ctrlproj);
_igvn.subsume_node(ctrlproj, fallthroughproj);
_igvn.hash_delete(memproj);
_igvn.subsume_node(memproj, memproj_fallthrough);
_igvn.replace_node(ctrlproj, fallthroughproj);
_igvn.replace_node(memproj, memproj_fallthrough);
// Delete FastLock node also if this Lock node is unique user
// (a loop peeling may clone a Lock node).
Node* flock = alock->as_Lock()->fastlock_node();
if (flock->outcnt() == 1) {
assert(flock->unique_out() == alock, "sanity");
_igvn.hash_delete(flock);
_igvn.subsume_node(flock, top());
_igvn.replace_node(flock, top());
}
}
@ -1634,20 +1628,16 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) {
MemBarNode* membar = ctrl->in(0)->as_MemBar();
assert(membar->Opcode() == Op_MemBarRelease &&
mem->is_Proj() && membar == mem->in(0), "");
_igvn.hash_delete(fallthroughproj);
_igvn.subsume_node(fallthroughproj, ctrl);
_igvn.hash_delete(memproj_fallthrough);
_igvn.subsume_node(memproj_fallthrough, mem);
_igvn.replace_node(fallthroughproj, ctrl);
_igvn.replace_node(memproj_fallthrough, mem);
fallthroughproj = ctrl;
memproj_fallthrough = mem;
ctrl = membar->in(TypeFunc::Control);
mem = membar->in(TypeFunc::Memory);
}
_igvn.hash_delete(fallthroughproj);
_igvn.subsume_node(fallthroughproj, ctrl);
_igvn.hash_delete(memproj_fallthrough);
_igvn.subsume_node(memproj_fallthrough, mem);
_igvn.replace_node(fallthroughproj, ctrl);
_igvn.replace_node(memproj_fallthrough, mem);
return true;
}
@ -1879,13 +1869,12 @@ void PhaseMacroExpand::expand_lock_node(LockNode *lock) {
region->init_req(1, slow_ctrl);
// region inputs are now complete
transform_later(region);
_igvn.subsume_node(_fallthroughproj, region);
_igvn.replace_node(_fallthroughproj, region);
Node *memproj = transform_later( new(C, 1) ProjNode(call, TypeFunc::Memory) );
mem_phi->init_req(1, memproj );
transform_later(mem_phi);
_igvn.hash_delete(_memproj_fallthrough);
_igvn.subsume_node(_memproj_fallthrough, mem_phi);
_igvn.replace_node(_memproj_fallthrough, mem_phi);
}
//------------------------------expand_unlock_node----------------------
@ -1943,14 +1932,13 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) {
region->init_req(1, slow_ctrl);
// region inputs are now complete
transform_later(region);
_igvn.subsume_node(_fallthroughproj, region);
_igvn.replace_node(_fallthroughproj, region);
Node *memproj = transform_later( new(C, 1) ProjNode(call, TypeFunc::Memory) );
mem_phi->init_req(1, memproj );
mem_phi->init_req(2, mem);
transform_later(mem_phi);
_igvn.hash_delete(_memproj_fallthrough);
_igvn.subsume_node(_memproj_fallthrough, mem_phi);
_igvn.replace_node(_memproj_fallthrough, mem_phi);
}
//------------------------------expand_macro_nodes----------------------
@ -1969,9 +1957,7 @@ bool PhaseMacroExpand::expand_macro_nodes() {
if (n->is_AbstractLock()) {
success = eliminate_locking_node(n->as_AbstractLock());
} else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
_igvn.add_users_to_worklist(n);
_igvn.hash_delete(n);
_igvn.subsume_node(n, n->in(1));
_igvn.replace_node(n, n->in(1));
success = true;
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");

View File

@ -218,6 +218,26 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) {
// Don't bother trying to transform a dead node
if( ctl && ctl->is_top() ) return NodeSentinel;
PhaseIterGVN *igvn = phase->is_IterGVN();
// Wait if control on the worklist.
if (ctl && can_reshape && igvn != NULL) {
Node* bol = NULL;
Node* cmp = NULL;
if (ctl->in(0)->is_If()) {
assert(ctl->is_IfTrue() || ctl->is_IfFalse(), "sanity");
bol = ctl->in(0)->in(1);
if (bol->is_Bool())
cmp = ctl->in(0)->in(1)->in(1);
}
if (igvn->_worklist.member(ctl) ||
(bol != NULL && igvn->_worklist.member(bol)) ||
(cmp != NULL && igvn->_worklist.member(cmp)) ) {
// This control path may be dead.
// Delay this memory node transformation until the control is processed.
phase->is_IterGVN()->_worklist.push(this);
return NodeSentinel; // caller will return NULL
}
}
// Ignore if memory is dead, or self-loop
Node *mem = in(MemNode::Memory);
if( phase->type( mem ) == Type::TOP ) return NodeSentinel; // caller will return NULL
@ -227,14 +247,22 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) {
const Type *t_adr = phase->type( address );
if( t_adr == Type::TOP ) return NodeSentinel; // caller will return NULL
PhaseIterGVN *igvn = phase->is_IterGVN();
if( can_reshape && igvn != NULL && igvn->_worklist.member(address) ) {
if( can_reshape && igvn != NULL &&
(igvn->_worklist.member(address) || phase->type(address) != adr_type()) ) {
// The address's base and type may change when the address is processed.
// Delay this mem node transformation until the address is processed.
phase->is_IterGVN()->_worklist.push(this);
return NodeSentinel; // caller will return NULL
}
#ifdef ASSERT
Node* base = NULL;
if (address->is_AddP())
base = address->in(AddPNode::Base);
assert(base == NULL || t_adr->isa_rawptr() ||
!phase->type(base)->higher_equal(TypePtr::NULL_PTR), "NULL+offs not RAW address?");
#endif
// Avoid independent memory operations
Node* old_mem = mem;
@ -1307,22 +1335,20 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
set_req(MemNode::Control,ctrl);
}
// Check for useless control edge in some common special cases
if (in(MemNode::Control) != NULL) {
intptr_t ignore = 0;
Node* base = AddPNode::Ideal_base_and_offset(address, phase, ignore);
if (base != NULL
intptr_t ignore = 0;
Node* base = AddPNode::Ideal_base_and_offset(address, phase, ignore);
if (base != NULL
&& phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw) {
// Check for useless control edge in some common special cases
if (in(MemNode::Control) != NULL
&& phase->type(base)->higher_equal(TypePtr::NOTNULL)
&& phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw
&& all_controls_dominate(base, phase->C->start())) {
// A method-invariant, non-null address (constant or 'this' argument).
set_req(MemNode::Control, NULL);
}
}
if (EliminateAutoBox && can_reshape && in(Address)->is_AddP()) {
Node* base = in(Address)->in(AddPNode::Base);
if (base != NULL) {
if (EliminateAutoBox && can_reshape) {
assert(!phase->type(base)->higher_equal(TypePtr::NULL_PTR), "the autobox pointer should be non-null");
Compile::AliasType* atp = phase->C->alias_type(adr_type());
if (is_autobox_object(atp)) {
Node* result = eliminate_autobox(phase);
@ -1455,10 +1481,11 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
jt = _type;
}
if (EliminateAutoBox) {
if (EliminateAutoBox && adr->is_AddP()) {
// The pointers in the autobox arrays are always non-null
Node* base = in(Address)->in(AddPNode::Base);
if (base != NULL) {
Node* base = adr->in(AddPNode::Base);
if (base != NULL &&
!phase->type(base)->higher_equal(TypePtr::NULL_PTR)) {
Compile::AliasType* atp = phase->C->alias_type(base->adr_type());
if (is_autobox_cache(atp)) {
return jt->join(TypePtr::NOTNULL)->is_ptr();

View File

@ -2256,7 +2256,8 @@ void Scheduling::DoScheduling() {
// bother scheduling them.
Node *last = bb->_nodes[_bb_end];
if( last->is_Catch() ||
(last->is_Mach() && last->as_Mach()->ideal_Opcode() == Op_Halt) ) {
// Exclude unreachable path case when Halt node is in a separate block.
(_bb_end > 1 && last->is_Mach() && last->as_Mach()->ideal_Opcode() == Op_Halt) ) {
// There must be a prior call. Skip it.
while( !bb->_nodes[--_bb_end]->is_Call() ) {
assert( bb->_nodes[_bb_end]->is_Proj(), "skipping projections after expected call" );

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,435 @@
/*
* Copyright 2008-2009 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.
*
*/
class MacroAssembler;
class Label;
class MethodHandleEntry;
class MethodHandles: AllStatic {
// JVM support for MethodHandle, MethodType, and related types
// in java.dyn and java.dyn.hotspot.
// See also javaClasses for layouts java_dyn_Method{Handle,Type,Type::Form}.
public:
enum EntryKind {
_check_mtype, // how a caller calls a MH
_wrong_method_type, // what happens when there is a type mismatch
_invokestatic_mh, // how a MH emulates invokestatic
_invokespecial_mh, // ditto for the other invokes...
_invokevirtual_mh,
_invokeinterface_mh,
_bound_ref_mh, // reference argument is bound
_bound_int_mh, // int argument is bound (via an Integer or Float)
_bound_long_mh, // long argument is bound (via a Long or Double)
_bound_ref_direct_mh, // same as above, with direct linkage to methodOop
_bound_int_direct_mh,
_bound_long_direct_mh,
_adapter_mh_first, // adapter sequence goes here...
_adapter_retype_only = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RETYPE_ONLY,
_adapter_check_cast = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_CHECK_CAST,
_adapter_prim_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_PRIM_TO_PRIM,
_adapter_ref_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_REF_TO_PRIM,
_adapter_prim_to_ref = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_PRIM_TO_REF,
_adapter_swap_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_SWAP_ARGS,
_adapter_rot_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_ROT_ARGS,
_adapter_dup_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_DUP_ARGS,
_adapter_drop_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_DROP_ARGS,
_adapter_collect_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_COLLECT_ARGS,
_adapter_spread_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_SPREAD_ARGS,
_adapter_flyby = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_FLYBY,
_adapter_ricochet = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RICOCHET,
_adapter_mh_last = _adapter_mh_first + sun_dyn_AdapterMethodHandle::CONV_OP_LIMIT - 1,
// Optimized adapter types
// argument list reordering
_adapter_opt_swap_1,
_adapter_opt_swap_2,
_adapter_opt_rot_1_up,
_adapter_opt_rot_1_down,
_adapter_opt_rot_2_up,
_adapter_opt_rot_2_down,
// primitive single to single:
_adapter_opt_i2i, // i2c, i2z, i2b, i2s
// primitive double to single:
_adapter_opt_l2i,
_adapter_opt_d2f,
// primitive single to double:
_adapter_opt_i2l,
_adapter_opt_f2d,
// conversion between floating point and integer type is handled by Java
// reference to primitive:
_adapter_opt_unboxi,
_adapter_opt_unboxl,
// spreading (array length cases 0, 1, >=2)
_adapter_opt_spread_0,
_adapter_opt_spread_1,
_adapter_opt_spread_more,
_EK_LIMIT,
_EK_FIRST = 0
};
public:
static bool enabled() { return _enabled; }
static void set_enabled(bool z);
private:
enum { // import sun_dyn_AdapterMethodHandle::CONV_OP_*
CONV_OP_LIMIT = sun_dyn_AdapterMethodHandle::CONV_OP_LIMIT,
CONV_OP_MASK = sun_dyn_AdapterMethodHandle::CONV_OP_MASK,
CONV_VMINFO_MASK = sun_dyn_AdapterMethodHandle::CONV_VMINFO_MASK,
CONV_VMINFO_SHIFT = sun_dyn_AdapterMethodHandle::CONV_VMINFO_SHIFT,
CONV_OP_SHIFT = sun_dyn_AdapterMethodHandle::CONV_OP_SHIFT,
CONV_DEST_TYPE_SHIFT = sun_dyn_AdapterMethodHandle::CONV_DEST_TYPE_SHIFT,
CONV_SRC_TYPE_SHIFT = sun_dyn_AdapterMethodHandle::CONV_SRC_TYPE_SHIFT,
CONV_STACK_MOVE_SHIFT = sun_dyn_AdapterMethodHandle::CONV_STACK_MOVE_SHIFT,
CONV_STACK_MOVE_MASK = sun_dyn_AdapterMethodHandle::CONV_STACK_MOVE_MASK
};
static bool _enabled;
static MethodHandleEntry* _entries[_EK_LIMIT];
static const char* _entry_names[_EK_LIMIT+1];
static bool ek_valid(EntryKind ek) { return (uint)ek < (uint)_EK_LIMIT; }
static bool conv_op_valid(int op) { return (uint)op < (uint)CONV_OP_LIMIT; }
public:
static bool have_entry(EntryKind ek) { return ek_valid(ek) && _entries[ek] != NULL; }
static MethodHandleEntry* entry(EntryKind ek) { assert(ek_valid(ek), "initialized");
return _entries[ek]; }
static const char* entry_name(EntryKind ek) { assert(ek_valid(ek), "oob");
return _entry_names[ek]; }
static EntryKind adapter_entry_kind(int op) { assert(conv_op_valid(op), "oob");
return EntryKind(_adapter_mh_first + op); }
static void init_entry(EntryKind ek, MethodHandleEntry* me) {
assert(ek_valid(ek), "oob");
assert(_entries[ek] == NULL, "no double initialization");
_entries[ek] = me;
}
static jint adapter_conversion(int conv_op, BasicType src, BasicType dest,
int stack_move = 0, int vminfo = 0) {
assert(conv_op_valid(conv_op), "oob");
jint conv = ((conv_op << CONV_OP_SHIFT)
| (src << CONV_SRC_TYPE_SHIFT)
| (dest << CONV_DEST_TYPE_SHIFT)
| (stack_move << CONV_STACK_MOVE_SHIFT)
| (vminfo << CONV_VMINFO_SHIFT)
);
assert(adapter_conversion_op(conv) == conv_op, "decode conv_op");
assert(adapter_conversion_src_type(conv) == src, "decode src");
assert(adapter_conversion_dest_type(conv) == dest, "decode dest");
assert(adapter_conversion_stack_move(conv) == stack_move, "decode stack_move");
assert(adapter_conversion_vminfo(conv) == vminfo, "decode vminfo");
return conv;
}
static int adapter_conversion_op(jint conv) {
return ((conv >> CONV_OP_SHIFT) & 0xF);
}
static BasicType adapter_conversion_src_type(jint conv) {
return (BasicType)((conv >> CONV_SRC_TYPE_SHIFT) & 0xF);
}
static BasicType adapter_conversion_dest_type(jint conv) {
return (BasicType)((conv >> CONV_DEST_TYPE_SHIFT) & 0xF);
}
static int adapter_conversion_stack_move(jint conv) {
return (conv >> CONV_STACK_MOVE_SHIFT);
}
static int adapter_conversion_vminfo(jint conv) {
return (conv >> CONV_VMINFO_SHIFT) & CONV_VMINFO_MASK;
}
// Offset in words that the interpreter stack pointer moves when an argument is pushed.
// The stack_move value must always be a multiple of this.
static int stack_move_unit() {
return frame::interpreter_frame_expression_stack_direction() * Interpreter::stackElementWords();
}
enum { CONV_VMINFO_SIGN_FLAG = 0x80 };
static int adapter_subword_vminfo(BasicType dest) {
if (dest == T_BOOLEAN) return (BitsPerInt - 1);
if (dest == T_CHAR) return (BitsPerInt - 16);
if (dest == T_BYTE) return (BitsPerInt - 8) | CONV_VMINFO_SIGN_FLAG;
if (dest == T_SHORT) return (BitsPerInt - 16) | CONV_VMINFO_SIGN_FLAG;
return 0; // case T_INT
}
// Here is the transformation the i2i adapter must perform:
static int truncate_subword_from_vminfo(jint value, int vminfo) {
jint tem = value << vminfo;
if ((vminfo & CONV_VMINFO_SIGN_FLAG) != 0) {
return (jint)tem >> vminfo;
} else {
return (juint)tem >> vminfo;
}
}
static inline address from_compiled_entry(EntryKind ek);
static inline address from_interpreted_entry(EntryKind ek);
// helpers for decode_method.
static methodOop decode_methodOop(methodOop m, int& decode_flags_result);
static methodOop decode_vmtarget(oop vmtarget, int vmindex, oop mtype, klassOop& receiver_limit_result, int& decode_flags_result);
static methodOop decode_MemberName(oop mname, klassOop& receiver_limit_result, int& decode_flags_result);
static methodOop decode_MethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
static methodOop decode_DirectMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
static methodOop decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
static methodOop decode_AdapterMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
// Find out how many stack slots an mh pushes or pops.
// The result is *not* reported as a multiple of stack_move_unit();
// It is a signed net number of pushes (a difference in vmslots).
// To compare with a stack_move value, first multiply by stack_move_unit().
static int decode_MethodHandle_stack_pushes(oop mh);
public:
// working with member names
static void resolve_MemberName(Handle mname, TRAPS); // compute vmtarget/vmindex from name/type
static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing
static void init_MemberName(oop mname_oop, oop target); // compute vmtarget/vmindex from target
static void init_MemberName(oop mname_oop, methodOop m, bool do_dispatch);
static void init_MemberName(oop mname_oop, klassOop field_holder, AccessFlags mods, int offset);
static int find_MemberNames(klassOop k, symbolOop name, symbolOop sig,
int mflags, klassOop caller,
int skip, objArrayOop results);
// bit values for suppress argument to expand_MemberName:
enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 };
// called from InterpreterGenerator and StubGenerator
static address generate_method_handle_interpreter_entry(MacroAssembler* _masm);
static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek);
// argument list parsing
static int argument_slot(oop method_type, int arg);
static int argument_slot_count(oop method_type) { return argument_slot(method_type, -1); }
static int argument_slot_to_argnum(oop method_type, int argslot);
// Runtime support
enum { // bit-encoded flags from decode_method or decode_vmref
_dmf_has_receiver = 0x01, // target method has leading reference argument
_dmf_does_dispatch = 0x02, // method handle performs virtual or interface dispatch
_dmf_from_interface = 0x04, // peforms interface dispatch
_DMF_DIRECT_MASK = (_dmf_from_interface*2 - _dmf_has_receiver),
_dmf_binds_method = 0x08,
_dmf_binds_argument = 0x10,
_DMF_BOUND_MASK = (_dmf_binds_argument*2 - _dmf_binds_method),
_dmf_adapter_lsb = 0x20,
_DMF_ADAPTER_MASK = (_dmf_adapter_lsb << CONV_OP_LIMIT) - _dmf_adapter_lsb
};
static methodOop decode_method(oop x, klassOop& receiver_limit_result, int& decode_flags_result);
enum {
// format of query to getConstant:
GC_JVM_PUSH_LIMIT = 0,
GC_JVM_STACK_MOVE_LIMIT = 1,
// format of result from getTarget / encode_target:
ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self)
ETF_METHOD_NAME = 2, // ultimate method as MemberName
ETF_REFLECT_METHOD = 3 // ultimate method as java.lang.reflect object (sans refClass)
};
static int get_named_constant(int which, Handle name_box, TRAPS);
static oop encode_target(Handle mh, int format, TRAPS); // report vmtarget (to Java code)
static bool class_cast_needed(klassOop src, klassOop dst);
private:
// These checkers operate on a pair of whole MethodTypes:
static const char* check_method_type_change(oop src_mtype, int src_beg, int src_end,
int insert_argnum, oop insert_type,
int change_argnum, oop change_type,
int delete_argnum,
oop dst_mtype, int dst_beg, int dst_end);
static const char* check_method_type_insertion(oop src_mtype,
int insert_argnum, oop insert_type,
oop dst_mtype) {
oop no_ref = NULL;
return check_method_type_change(src_mtype, 0, -1,
insert_argnum, insert_type,
-1, no_ref, -1, dst_mtype, 0, -1);
}
static const char* check_method_type_conversion(oop src_mtype,
int change_argnum, oop change_type,
oop dst_mtype) {
oop no_ref = NULL;
return check_method_type_change(src_mtype, 0, -1, -1, no_ref,
change_argnum, change_type,
-1, dst_mtype, 0, -1);
}
static const char* check_method_type_passthrough(oop src_mtype, oop dst_mtype) {
oop no_ref = NULL;
return check_method_type_change(src_mtype, 0, -1,
-1, no_ref, -1, no_ref, -1,
dst_mtype, 0, -1);
}
// These checkers operate on pairs of argument or return types:
static const char* check_argument_type_change(BasicType src_type, klassOop src_klass,
BasicType dst_type, klassOop dst_klass,
int argnum);
static const char* check_argument_type_change(oop src_type, oop dst_type,
int argnum) {
klassOop src_klass = NULL, dst_klass = NULL;
BasicType src_bt = java_lang_Class::as_BasicType(src_type, &src_klass);
BasicType dst_bt = java_lang_Class::as_BasicType(dst_type, &dst_klass);
return check_argument_type_change(src_bt, src_klass,
dst_bt, dst_klass, argnum);
}
static const char* check_return_type_change(oop src_type, oop dst_type) {
return check_argument_type_change(src_type, dst_type, -1);
}
static const char* check_return_type_change(BasicType src_type, klassOop src_klass,
BasicType dst_type, klassOop dst_klass) {
return check_argument_type_change(src_type, src_klass, dst_type, dst_klass, -1);
}
static const char* check_method_receiver(methodOop m, klassOop passed_recv_type);
// These verifiers can block, and will throw an error if the checking fails:
static void verify_vmslots(Handle mh, TRAPS);
static void verify_vmargslot(Handle mh, int argnum, int argslot, TRAPS);
static void verify_method_type(methodHandle m, Handle mtype,
bool has_bound_oop,
KlassHandle bound_oop_type,
TRAPS);
static void verify_method_signature(methodHandle m, Handle mtype,
int first_ptype_pos,
KlassHandle insert_ptype, TRAPS);
static void verify_DirectMethodHandle(Handle mh, methodHandle m, TRAPS);
static void verify_BoundMethodHandle(Handle mh, Handle target, int argnum,
bool direct_to_method, TRAPS);
static void verify_BoundMethodHandle_with_receiver(Handle mh, methodHandle m, TRAPS);
static void verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS);
public:
// Fill in the fields of a DirectMethodHandle mh. (MH.type must be pre-filled.)
static void init_DirectMethodHandle(Handle mh, methodHandle method, bool do_dispatch, TRAPS);
// Fill in the fields of a BoundMethodHandle mh. (MH.type, BMH.argument must be pre-filled.)
static void init_BoundMethodHandle(Handle mh, Handle target, int argnum, TRAPS);
static void init_BoundMethodHandle_with_receiver(Handle mh,
methodHandle original_m,
KlassHandle receiver_limit,
int decode_flags,
TRAPS);
// Fill in the fields of an AdapterMethodHandle mh. (MH.type must be pre-filled.)
static void init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS);
#ifdef ASSERT
static bool spot_check_entry_names();
#endif
private:
static methodHandle dispatch_decoded_method(methodHandle m,
KlassHandle receiver_limit,
int decode_flags,
KlassHandle receiver_klass,
TRAPS);
static bool same_basic_type_for_arguments(BasicType src, BasicType dst,
bool for_return = false);
static bool same_basic_type_for_returns(BasicType src, BasicType dst) {
return same_basic_type_for_arguments(src, dst, true);
}
enum { // arg_mask values
_INSERT_NO_MASK = -1,
_INSERT_REF_MASK = 0,
_INSERT_INT_MASK = 1,
_INSERT_LONG_MASK = 3
};
static void insert_arg_slots(MacroAssembler* _masm,
RegisterOrConstant arg_slots,
int arg_mask,
Register rax_argslot,
Register rbx_temp, Register rdx_temp);
static void remove_arg_slots(MacroAssembler* _masm,
RegisterOrConstant arg_slots,
Register rax_argslot,
Register rbx_temp, Register rdx_temp);
};
// Access methods for the "entry" field of a java.dyn.MethodHandle.
// The field is primarily a jump target for compiled calls.
// However, we squirrel away some nice pointers for other uses,
// just before the jump target.
// Aspects of a method handle entry:
// - from_compiled_entry - stub used when compiled code calls the MH
// - from_interpreted_entry - stub used when the interpreter calls the MH
// - type_checking_entry - stub for runtime casting between MHForm siblings (NYI)
class MethodHandleEntry {
public:
class Data {
friend class MethodHandleEntry;
size_t _total_size; // size including Data and code stub
MethodHandleEntry* _type_checking_entry;
address _from_interpreted_entry;
MethodHandleEntry* method_entry() { return (MethodHandleEntry*)(this + 1); }
};
Data* data() { return (Data*)this - 1; }
address start_address() { return (address) data(); }
address end_address() { return start_address() + data()->_total_size; }
address from_compiled_entry() { return (address) this; }
address from_interpreted_entry() { return data()->_from_interpreted_entry; }
void set_from_interpreted_entry(address e) { data()->_from_interpreted_entry = e; }
MethodHandleEntry* type_checking_entry() { return data()->_type_checking_entry; }
void set_type_checking_entry(MethodHandleEntry* e) { data()->_type_checking_entry = e; }
void set_end_address(address end_addr) {
size_t total_size = end_addr - start_address();
assert(total_size > 0 && total_size < 0x1000, "reasonable end address");
data()->_total_size = total_size;
}
// Compiler support:
static int from_interpreted_entry_offset_in_bytes() {
return (int)( offset_of(Data, _from_interpreted_entry) - sizeof(Data) );
}
static int type_checking_entry_offset_in_bytes() {
return (int)( offset_of(Data, _from_interpreted_entry) - sizeof(Data) );
}
static address start_compiled_entry(MacroAssembler* _masm,
address interpreted_entry = NULL);
static MethodHandleEntry* finish_compiled_entry(MacroAssembler* masm, address start_addr);
};
address MethodHandles::from_compiled_entry(EntryKind ek) { return entry(ek)->from_compiled_entry(); }
address MethodHandles::from_interpreted_entry(EntryKind ek) { return entry(ek)->from_interpreted_entry(); }

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -78,6 +78,7 @@ char* NativeLookup::long_jni_name(methodHandle method) {
extern "C" {
void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
}
@ -97,6 +98,9 @@ static address lookup_special_native(char* jni_name) {
if (strstr(jni_name, "Java_sun_misc_Unsafe_registerNatives") != NULL) {
return CAST_FROM_FN_PTR(address, JVM_RegisterUnsafeMethods);
}
if (strstr(jni_name, "Java_sun_dyn_MethodHandleNatives_registerNatives") != NULL) {
return CAST_FROM_FN_PTR(address, JVM_RegisterMethodHandleMethods);
}
if (strstr(jni_name, "Java_sun_misc_Perf_registerNatives") != NULL) {
return CAST_FROM_FN_PTR(address, JVM_RegisterPerfMethods);
}

View File

@ -2627,6 +2627,13 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
}
#endif // PRODUCT
if (EnableMethodHandles && !AnonymousClasses) {
if (!FLAG_IS_DEFAULT(AnonymousClasses)) {
warning("forcing AnonymousClasses true to enable EnableMethodHandles");
}
AnonymousClasses = true;
}
if (PrintGCDetails) {
// Turn on -verbose:gc options as well
PrintGC = true;

View File

@ -3301,6 +3301,21 @@ class CommandLineFlags {
product(bool, AnonymousClasses, false, \
"support sun.misc.Unsafe.defineAnonymousClass") \
\
product(bool, EnableMethodHandles, false, \
"support method handles (true by default under JSR 292)") \
\
diagnostic(intx, MethodHandlePushLimit, 3, \
"number of additional stack slots a method handle may push") \
\
develop(bool, TraceMethodHandles, false, \
"trace internal method handle operations") \
\
diagnostic(bool, VerifyMethodHandles, trueInDebug, \
"perform extra checks when constructing method handles") \
\
diagnostic(bool, OptimizeMethodHandles, true, \
"when constructing method handles, try to improve them") \
\
product(bool, TaggedStackInterpreter, false, \
"Insert tags in interpreter execution stack for oopmap generaion")\
\

View File

@ -1471,9 +1471,73 @@ char* SharedRuntime::generate_class_cast_message(
return generate_class_cast_message(objName, targetKlass->external_name());
}
char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread,
oopDesc* required,
oopDesc* actual) {
assert(EnableMethodHandles, "");
oop singleKlass = wrong_method_type_is_for_single_argument(thread, required);
if (singleKlass != NULL) {
const char* objName = "argument or return value";
if (actual != NULL) {
// be flexible about the junk passed in:
klassOop ak = (actual->is_klass()
? (klassOop)actual
: actual->klass());
objName = Klass::cast(ak)->external_name();
}
Klass* targetKlass = Klass::cast(required->is_klass()
? (klassOop)required
: java_lang_Class::as_klassOop(required));
return generate_class_cast_message(objName, targetKlass->external_name());
} else {
// %%% need to get the MethodType string, without messing around too much
// Get a signature from the invoke instruction
const char* mhName = "method handle";
const char* targetType = "the required signature";
vframeStream vfst(thread, true);
if (!vfst.at_end()) {
Bytecode_invoke* call = Bytecode_invoke_at(vfst.method(), vfst.bci());
methodHandle target;
{
EXCEPTION_MARK;
target = call->static_target(THREAD);
if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; }
}
if (target.not_null()
&& target->is_method_handle_invoke()
&& required == target->method_handle_type()) {
targetType = target->signature()->as_C_string();
}
}
klassOop kignore; int fignore;
methodOop actual_method = MethodHandles::decode_method(actual,
kignore, fignore);
if (actual_method != NULL) {
if (actual_method->name() == vmSymbols::invoke_name())
mhName = "$";
else
mhName = actual_method->signature()->as_C_string();
if (mhName[0] == '$')
mhName = actual_method->signature()->as_C_string();
}
return generate_class_cast_message(mhName, targetType,
" cannot be called as ");
}
}
oop SharedRuntime::wrong_method_type_is_for_single_argument(JavaThread* thr,
oopDesc* required) {
if (required == NULL) return NULL;
if (required->klass() == SystemDictionary::class_klass())
return required;
if (required->is_klass())
return Klass::cast(klassOop(required))->java_mirror();
return NULL;
}
char* SharedRuntime::generate_class_cast_message(
const char* objName, const char* targetKlassName) {
const char* desc = " cannot be cast to ";
const char* objName, const char* targetKlassName, const char* desc) {
size_t msglen = strlen(objName) + strlen(desc) + strlen(targetKlassName) + 1;
char* message = NEW_RESOURCE_ARRAY(char, msglen);

View File

@ -211,11 +211,33 @@ class SharedRuntime: AllStatic {
*/
static char* generate_class_cast_message(JavaThread* thr, const char* name);
/**
* Fill in the message for a WrongMethodTypeException
*
* @param thr the current thread
* @param mtype (optional) expected method type (or argument class)
* @param mhandle (optional) actual method handle (or argument)
* @return the dynamically allocated exception message
*
* BCP for the frame on top of the stack must refer to an
* 'invokevirtual' op for a method handle, or an 'invokedyamic' op.
* The caller (or one of its callers) must use a ResourceMark
* in order to correctly free the result.
*/
static char* generate_wrong_method_type_message(JavaThread* thr,
oopDesc* mtype = NULL,
oopDesc* mhandle = NULL);
/** Return non-null if the mtype is a klass or Class, not a MethodType. */
static oop wrong_method_type_is_for_single_argument(JavaThread* thr,
oopDesc* mtype);
/**
* Fill in the "X cannot be cast to a Y" message for ClassCastException
*
* @param name the name of the class of the object attempted to be cast
* @param klass the name of the target klass attempt
* @param gripe the specific kind of problem being reported
* @return the dynamically allocated exception message (must be freed
* by the caller using a resource mark)
*
@ -224,7 +246,8 @@ class SharedRuntime: AllStatic {
* The caller (or one of it's callers) must use a ResourceMark
* in order to correctly free the result.
*/
static char* generate_class_cast_message(const char* name, const char* klass);
static char* generate_class_cast_message(const char* name, const char* klass,
const char* gripe = " cannot be cast to ");
// Resolves a call site- may patch in the destination of the call into the
// compiled code.

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 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
@ -47,6 +47,8 @@ enum {
JVM_ACC_IS_OLD = 0x00010000, // RedefineClasses() has replaced this method
JVM_ACC_IS_OBSOLETE = 0x00020000, // RedefineClasses() has made method obsolete
JVM_ACC_IS_PREFIXED_NATIVE = 0x00040000, // JVMTI has prefixed this native method
JVM_MH_INVOKE_BITS // = 0x10001100 // MethodHandle.invoke quasi-native
= (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_MONITOR_MATCH),
// klassOop flags
JVM_ACC_HAS_MIRANDA_METHODS = 0x10000000, // True if this class has miranda methods in it's vtable
@ -72,6 +74,7 @@ enum {
// flags accepted by set_field_flags()
JVM_ACC_FIELD_FLAGS = 0x00008000 | JVM_ACC_WRITTEN_FLAGS
};
@ -114,6 +117,15 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
bool is_obsolete () const { return (_flags & JVM_ACC_IS_OBSOLETE ) != 0; }
bool is_prefixed_native () const { return (_flags & JVM_ACC_IS_PREFIXED_NATIVE ) != 0; }
// JSR 292: A method of the form MethodHandle.invoke(A...)R method is
// neither bytecoded nor a JNI native, but rather a fast call through
// a lightweight method handle object. Because it is not bytecoded,
// it has the native bit set, but the monitor-match bit is also set
// to distinguish it from a JNI native (which never has the match bit set).
// The synthetic bit is also present, because such a method is never
// explicitly defined in Java code.
bool is_method_handle_invoke () const { return (_flags & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS; }
// klassOop flags
bool has_miranda_methods () const { return (_flags & JVM_ACC_HAS_MIRANDA_METHODS ) != 0; }
bool has_vanilla_constructor () const { return (_flags & JVM_ACC_HAS_VANILLA_CONSTRUCTOR) != 0; }
@ -199,6 +211,14 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
jshort as_short() { return (jshort)_flags; }
jint as_int() { return _flags; }
inline friend AccessFlags accessFlags_from(jint flags);
// Printing/debugging
void print_on(outputStream* st) const PRODUCT_RETURN;
};
inline AccessFlags accessFlags_from(jint flags) {
AccessFlags af;
af._flags = flags;
return af;
}

View File

@ -237,6 +237,9 @@ class Exceptions {
#define THROW_ARG_0(name, signature, arg) THROW_ARG_(name, signature, arg, 0)
#define THROW_MSG_CAUSE_0(name, message, cause) THROW_MSG_CAUSE_(name, message, cause, 0)
#define THROW_NULL(name) THROW_(name, NULL)
#define THROW_MSG_NULL(name, message) THROW_MSG_(name, message, NULL)
// The CATCH macro checks that no exception has been thrown by a function; it is used at
// call sites about which is statically known that the callee cannot throw an exception
// even though it is declared with TRAPS.

View File

@ -408,6 +408,15 @@ inline bool is_java_primitive(BasicType t) {
return T_BOOLEAN <= t && t <= T_LONG;
}
inline bool is_subword_type(BasicType t) {
// these guys are processed exactly like T_INT in calling sequences:
return (t == T_BOOLEAN || t == T_CHAR || t == T_BYTE || t == T_SHORT);
}
inline bool is_signed_subword_type(BasicType t) {
return (t == T_BYTE || t == T_SHORT);
}
// Convert a char from a classfile signature to a BasicType
inline BasicType char2type(char c) {
switch( c ) {

View File

@ -0,0 +1,44 @@
/*
* Copyright 2009 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.
*/
/**
* @test
* @bug 6539464
* @summary Math.log() produces inconsistent results between successive runs.
*
* @run main/othervm -Xcomp -XX:CompileOnly=Test.main Test
*/
public class Test {
static double log_value = 17197;
static double log_result = Math.log(log_value);
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1000000; i++) {
double log_result2 = Math.log(log_value);
if (log_result2 != log_result) {
throw new InternalError("Math.log produces inconsistent results: " + log_result2 + " != " + log_result);
}
}
}
}

View File

@ -26,7 +26,7 @@
* @bug 6636138
* @summary SuperWord::co_locate_pack(Node_List* p) generates memory graph that leads to memory order violation.
*
* @run main/othervm -server -Xbatch -XX:CompileOnly=Test1.init -XX:+UseSuperword Test1
* @run main/othervm -server -Xbatch -XX:CompileOnly=Test1.init Test1
*/
class Test1 {

View File

@ -26,7 +26,7 @@
* @bug 6636138
* @summary SuperWord::co_locate_pack(Node_List* p) generates memory graph that leads to memory order violation.
*
* @run main/othervm -server -Xbatch -XX:CompileOnly=Test2.shift -XX:+UseSuperword Test2
* @run main/othervm -server -Xbatch -XX:CompileOnly=Test2.shift Test2
*/
class Test2 {

View File

@ -0,0 +1,849 @@
/*
* Copyright 2009 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.
*
*/
/*
* @test
* @bug 6711117
* @summary Assertion in 64bit server vm (flat != TypePtr::BOTTOM,"cannot alias-analyze an untyped ptr")
* @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+AggressiveOpts -XX:+UseCompressedOops Test
*/
final class Test_Class_0 {
final static char var_1 = 'E';
short var_2 = 16213;
final static String var_3 = "jiiibmmsk";
public Test_Class_0()
{
var_2 ^= 'M';
final String var_18 = var_3;
var_2--;
var_2 |= (byte)('D' / (byte)var_2) - ((byte)1.6680514E38F << + ((byte)'O') & 7320241275829036032L);
func_2(((!false & false | false ? true : false) ? true : true | !true) ? var_2 : 834513107);
var_2 >>>= var_1;
"smiosoebk".codePointCount(true ^ (false ^ ! !false) ? (byte)- ((byte)430513598) : + ((byte)'_'), ~ (true ? (byte)']' : (byte)-2.8272547997066827E307));
var_2 -= true ? var_1 : var_1;
var_2 ^= var_1;
var_2 &= (var_2 |= ~ ((byte)(var_2 *= var_2)));
long var_19 = 0L;
short var_20 = var_2 += 'P';
while (var_19 < 1)
{
var_2 ^= true ? (byte)- +1.2219539475209E308 : (byte)1.2748408476894178E308;
var_19++;
var_2 = (byte)((1489358000 == (var_20 | 7816908224315289600L) ? var_1 : var_1) ^ var_19);
var_20--;
}
var_20 -= 'f';
var_20 <<= (((new Test_Class_0[(byte)var_20])[(byte)var_2]).var_2 *= false ? 'g' : 'x');
}
static float func_0()
{
((new Test_Class_0[(byte)7.774490796987995E307])[(byte)'v']).var_2 <<= false ^ !false ? (short)'v' : "".codePointCount(594464985, 579036736);
((new Test_Class_0[(byte)(((new Test_Class_0[(byte)1361657519])[(byte)2.3703713E38F]).var_2-- - (short)3.5589388134844986E307)])[((true ? !true : false) ^ (!false ? true : !true) ? !false : false) ? (byte)7.047289E37F : (byte)- ((byte)2.6620062118475144E307)]).var_2 *= 3273943364390983680L;
--((new Test_Class_0[false ? (byte)(short)1.4965069E36F : (byte)286322022])[(byte)- ((byte)2.742619E38F)]).var_2;
long var_4;
{
double var_5;
}
var_4 = (byte)1.3509231E38F;
((new Test_Class_0[(byte)'_'])[('g' | 1427123046096105472L) < var_1 >> (byte)(int)(byte)7697616672011068416L ? (byte)var_1 : (byte)1251856579]).var_2--;
switch (--((new Test_Class_0[(byte)5.0656327E37F])[(byte)'e']).var_2 != ++((new Test_Class_0[(byte)(int)1.3728667270920175E308])[(byte)+ + -1.6338179407381788E308]).var_2 | !var_3.equalsIgnoreCase("iiwwwln") ? (false ? (byte)1.8291216E38F : (byte)4.778575546584698E307) : (byte)1048254181)
{
case 99:
}
{
byte var_6 = 13;
}
var_4 = --((new Test_Class_0[!var_3.endsWith("qaoioore") ^ false ? (byte)2.827362738392923E307 : (byte)~4890175967151316992L])[(byte)(short)var_1]).var_2;
++((new Test_Class_0[(byte)(1.0075552E38F + (short)2083553541)])[(byte)(short)(byte)(short)1.6872205E38F]).var_2;
return ((new Test_Class_0[(byte)var_1])[(byte)+ +5760973323384750080L]).var_2 - (false ? (byte)'i' : (var_4 = (short)1.2458781351126844E308) + 2.131006E38F);
}
public static long func_1(String arg_0, Object arg_1, final long arg_2)
{
arg_0 = false ? arg_0 : "fgbrpgsq";
((new Test_Class_0[(byte)- ((byte)']')])[false ? (byte)757239006 : (byte)1866002020]).var_2 ^= (short)(true ? (byte)(((new Test_Class_0[(byte)1416194866])[(byte)1.2309887362692395E308]).var_2 >>= (int)~ ~ ~arg_2) : (byte)5804970709284726784L);
final long var_7 = (long)(- + ((long)+ - + - -2.5396583E38F) - - +1.8770165E38F % 2472404173160781824L < --((new Test_Class_0[(byte)5.569360482341752E307])[(byte)(double)(byte)8131142397821553664L]).var_2 ^ true ? (false ? (byte)- -1.163275451591927E308 : (byte)var_1) : (false ? (byte)1843746036 : (byte)1.0209668642291047E308));
arg_0 = (arg_0 = arg_0.substring(699480935));
switch (((new Test_Class_0[(byte)(5415649243316856832L >> 861936806)])[true | true & !false ? (byte)(short)- -7.785169683394908E307 : (byte)+ ((byte)arg_2)]).var_2++)
{
case 42:
case 102:
}
arg_1 = (true || false ? false : true) ? (arg_0 = (arg_0 = "jbfaru")) : arg_0;
arg_1 = new byte[(byte)2.669957E38F];
boolean var_8 = ! ((false ? (short)1.4259420861834744E308 : (short)7.352115508157158E307) != 1.7635658130722812E308);
arg_1 = new Object[(byte)- ((byte)(short)1.8950693E38F)];
arg_0 = arg_0;
return (byte)1.4762239057269886E308 & 4923938844759802880L;
}
double[][] func_2(final int arg_0)
{
var_2 >>>= (var_2 >>= var_2++);
float var_9 = 0F;
var_2 %= var_2;
do
{
++var_2;
var_9++;
var_2++;
} while (true && (var_9 < 1 && false));
double var_10 = 0;
final int var_11 = 11903395;
do
{
--var_2;
var_10++;
++var_2;
} while ((false & true || false) && (var_10 < 2 && ~ ((byte)'[') == (byte)(1.1943192E38F % ('c' << var_1) % (byte)((var_2 |= var_2) + 591679039 / ~5932100696448264192L))));
String var_12 = "jkwnk";
var_12 = var_3;
var_12 = (var_12 = (var_12 = var_3));
var_12 = "qrhdwx";
var_12 = var_12;
short var_13 = (true && true) ^ true | ! (!true || 1646418779 <= (byte)var_1) ? var_2 : var_2;
return new double[(byte)var_1][true || false ^ !true ^ true ? (byte)arg_0 : (byte)var_10];
}
private final int func_3()
{
long var_14 = 's' * (~ ~6656240461354863616L * 3151744928387344384L) << ~ (((var_2 >>>= 6600935261424147456L) % 1798503219359364096L | - ~3832249967647077376L / - ((byte)~1529201870915276800L)) / var_2);
{
var_14 |= !false | (byte)1078230528 >= (byte)1.3972878565417081E308 | (true | !true & !true & !false) ? var_1 : '_';
}
long var_15 = 7589204885152164864L;
var_2 ^= (var_1 < (byte)'r' ? 475314139 : 'Z') <= 1943074698 ? 'h' : var_1;
return 'V' * (false ? (byte)5.498204E37F : (byte)1.0137001669765466E308);
}
protected static boolean func_4(boolean arg_0, byte arg_1, boolean arg_2)
{
arg_1++;
arg_1 &= (((((new Test_Class_0[arg_1][arg_1][arg_1])[arg_1])[arg_1])[arg_1]).var_2 |= arg_2 ? (short)~3038084056596854784L : (short)+ (arg_1 = arg_1));
arg_0 |= true;
arg_1 %= (arg_1 |= ((new Test_Class_0[arg_1])[arg_1]).var_2--);
if (false)
{
arg_0 |= arg_2;
}
else
{
++(((new Test_Class_0[arg_1][arg_1][arg_1])[arg_1 += var_1])[(!arg_2 | (arg_0 &= false)) ^ (arg_0 | arg_0) ? arg_1 : (arg_1 <<= 3192041751921364992L)][arg_1 /= arg_1]).var_2;
}
arg_1 &= +(new byte[arg_1])[arg_1];
arg_1 <<= 3632133838014908416L;
byte[] var_16 = (new byte[arg_1][arg_1--])[arg_1];
long var_17;
arg_1 ^= ~ arg_1--;
arg_0 ^= (arg_2 ^= 1186877294 >= ((new Test_Class_0[arg_1][arg_1])[arg_1][arg_1]).var_2) & arg_2;
return var_3.startsWith(var_3);
}
public String toString()
{
String result = "[\n";
result += "Test_Class_0.var_2 = "; result += Test.Printer.print(var_2);
result += "\n";
result += "Test_Class_0.var_1 = "; result += Test.Printer.print(var_1);
result += "\n";
result += "Test_Class_0.var_3 = "; result += Test.Printer.print(var_3);
result += "";
result += "\n]";
return result;
}
}
class Test_Class_1 {
static int var_21 = 670918363;
final float var_22 = 8.650798E37F;
static int var_23 = 1774228457;
final int var_24 = 1282736974;
final byte var_25 = !false & false | true ? (byte)7.677121016144275E307 : (byte)'r';
static long var_26 = 2939310115459338240L;
final long var_27 = var_25 - 7555453173456381952L;
double var_28;
static String var_29;
public Test_Class_1()
{
var_29 = Test_Class_0.var_3;
((false ? false || ! !true : ! (! !true & !true)) ? new Test_Class_0() : new Test_Class_0()).var_2++;
var_23 -= 2.963694E38F;
}
public String toString()
{
String result = "[\n";
result += "Test_Class_1.var_21 = "; result += Test.Printer.print(var_21);
result += "\n";
result += "Test_Class_1.var_23 = "; result += Test.Printer.print(var_23);
result += "\n";
result += "Test_Class_1.var_24 = "; result += Test.Printer.print(var_24);
result += "\n";
result += "Test_Class_1.var_26 = "; result += Test.Printer.print(var_26);
result += "\n";
result += "Test_Class_1.var_27 = "; result += Test.Printer.print(var_27);
result += "\n";
result += "Test_Class_1.var_28 = "; result += Test.Printer.print(var_28);
result += "\n";
result += "Test_Class_1.var_22 = "; result += Test.Printer.print(var_22);
result += "\n";
result += "Test_Class_1.var_25 = "; result += Test.Printer.print(var_25);
result += "\n";
result += "Test_Class_1.var_29 = "; result += Test.Printer.print(var_29);
result += "";
result += "\n]";
return result;
}
}
class Test_Class_2 {
double var_30;
static byte var_31;
static char var_32;
float var_33;
double var_34 = !false & (true ? true : ! !true && false) ? 'q' - 4789231433793305600L - (var_33 = -1.0677024E38F) : 2.65473560313378E307;
final double var_35 = ~Test_Class_1.var_26 == 5.145660681364723E307 | false ? 1.4134775E38F : 1.77223030708671E308;
final int var_36 = Test_Class_1.var_23 |= Test_Class_1.var_21++;
public Test_Class_2()
{
Test_Class_0.var_3.replace(Test_Class_0.var_1, 'Q');
var_32 = (var_32 = (var_32 = '_'));
Test_Class_1.var_26 |= Test_Class_0.var_1;
Test_Class_1.var_29 = (Test_Class_1.var_29 = Test_Class_0.var_3);
var_32 = Test_Class_0.var_1;
var_33 = ((new Test_Class_0[(byte)851412948463452160L])[var_31 = new Test_Class_1().var_25]).var_2;
var_33 = ! (((!false | false) & (false || !true) ? false : ! !false) | false) ? new Test_Class_1().var_25 : (var_31 = new Test_Class_1().var_25);
float var_38 = 0F;
var_34 /= 5336005797857974272L;
for ("ccnyq".endsWith((new String[(byte)Test_Class_1.var_26])[var_31 = (var_31 = (var_31 = (byte)4.7927775E37F))]); var_38 < 2; var_32 = '^' <= Test_Class_0.var_1 ^ true ? (var_32 = Test_Class_0.var_1) : (var_32 = 'V'))
{
var_32 = true ? 'a' : (var_32 = Test_Class_0.var_1);
var_38++;
var_33 = new Test_Class_1().var_24;
var_32 = ! (true || true ? !false : (short)3.2844383E37F < 2.1400662E38F) ? (char)1.2691096999143248E308 : (! !false ^ true ? 's' : 'q');
}
var_32 = 'B';
{
var_32 = Test_Class_0.var_1;
}
var_32 = Test_Class_0.var_1;
Test_Class_1.var_29 = "ov";
Test_Class_1.var_29 = "smtolghw";
}
protected final static String func_0(final long[][] arg_0, byte arg_1, char arg_2)
{
arg_1 <<= (((new Test_Class_2[arg_1])[arg_1]).var_34 > new Test_Class_0().var_2 | true ? new Test_Class_0() : (new Test_Class_0[arg_1][arg_1])[new Test_Class_1().var_25][new Test_Class_1().var_25]).var_2;
Test_Class_1.var_26 >>>= (!true | !true | (new boolean[arg_1])[arg_1] || true ? (new Test_Class_1[arg_1])[arg_1] : new Test_Class_1()).var_27;
float var_37 = 0F;
arg_2 >>= ((new Test_Class_1[arg_1][arg_1])[arg_1][arg_1]).var_25;
do
{
((new Test_Class_2[arg_1 /= 2055714081])[arg_1]).var_34 = 'l';
var_37++;
Test_Class_1.var_29 = Test_Class_0.var_3;
} while ((false ? false : false) && var_37 < 7);
Test_Class_1.var_29 = Test_Class_0.var_3 + "";
((new Test_Class_2[new Test_Class_1().var_25][new Test_Class_1().var_25])[new Test_Class_1().var_25][arg_1 |= new Test_Class_0().var_2]).var_34 += Test_Class_0.var_1;
return "esb";
}
public String toString()
{
String result = "[\n";
result += "Test_Class_2.var_32 = "; result += Test.Printer.print(var_32);
result += "\n";
result += "Test_Class_2.var_36 = "; result += Test.Printer.print(var_36);
result += "\n";
result += "Test_Class_2.var_30 = "; result += Test.Printer.print(var_30);
result += "\n";
result += "Test_Class_2.var_34 = "; result += Test.Printer.print(var_34);
result += "\n";
result += "Test_Class_2.var_35 = "; result += Test.Printer.print(var_35);
result += "\n";
result += "Test_Class_2.var_33 = "; result += Test.Printer.print(var_33);
result += "\n";
result += "Test_Class_2.var_31 = "; result += Test.Printer.print(var_31);
result += "";
result += "\n]";
return result;
}
}
final class Test_Class_3 extends Test_Class_2 {
byte var_39 = 23;
static boolean var_40 = false;
public Test_Class_3()
{
if (true)
{
Test_Class_1.var_21 |= new Test_Class_1().var_27;
}
else
{
final float var_46 = 7.9266674E37F;
++Test_Class_1.var_26;
}
{
Test_Class_1.var_23++;
}
var_30 = ((new Test_Class_1[var_39][var_39])[var_39][var_39]).var_25;
if (var_40 &= (var_40 |= (var_40 |= var_40)))
{
Test_Class_0.var_3.indexOf(Test_Class_1.var_29 = "xfgyblg", 'X' >>> ((Test_Class_1)(new Object[var_39])[((new Test_Class_1[var_39])[var_39]).var_25]).var_27);
}
else
{
var_40 &= var_40 && var_40;
}
((Test_Class_2)(((new boolean[var_39])[var_39++] ? (var_40 &= var_40) : (var_40 &= false)) ? (new Test_Class_2[var_39][var_39])[var_39][var_39] : (new Object[var_39][var_39])[var_39][var_39])).var_33 = (var_40 ? new Test_Class_1() : new Test_Class_1()).var_25;
switch (var_39)
{
case 24:
}
var_39 += (((var_40 ^= true) ? new Test_Class_0() : new Test_Class_0()).var_2 ^= var_40 & (var_40 | false) ? var_39-- : var_36);
new Test_Class_0().var_2 %= (new Test_Class_0().var_2 += (var_39 ^= Test_Class_1.var_26));
}
private static String func_0()
{
--Test_Class_1.var_26;
{
Test_Class_1.var_29 = var_40 ? Test_Class_0.var_3 : "rahqjhqf";
}
if (var_40 ^= var_40)
{
Test_Class_1.var_26 >>= (Test_Class_2.var_32 = Test_Class_0.var_1) / new Test_Class_0().var_2;
}
else
{
++Test_Class_1.var_21;
}
++Test_Class_1.var_26;
int var_41 = 0;
++Test_Class_1.var_26;
do
{
var_40 = (var_40 = true);
var_41++;
Test_Class_0 var_42 = new Test_Class_0();
} while (var_41 < 1);
Test_Class_1.var_29 = "f";
Test_Class_1 var_43;
var_43 = (var_43 = new Test_Class_1());
Test_Class_2.var_32 = 'V';
long var_44 = 0L;
Test_Class_1.var_23--;
while (var_40 && (var_44 < 1 && var_40))
{
Test_Class_1.var_29 = "bsgewkmk";
var_44++;
Test_Class_1.var_29 = "ktegattny";
var_40 &= var_40 ^ (var_40 |= (short)4.4487427E37F < 'n') & true;
}
Test_Class_1.var_23 %= (((var_40 |= true & (var_40 &= var_40)) ^ true ? new Test_Class_0() : new Test_Class_0()).var_2 -= 1.6638270827800162E308);
float var_45;
var_32 = (Test_Class_2.var_32 = Test_Class_0.var_1);
return false ? "fluk" : "wt";
}
public String toString()
{
String result = "[\n";
result += "Test_Class_3.var_32 = "; result += Test.Printer.print(var_32);
result += "\n";
result += "Test_Class_3.var_36 = "; result += Test.Printer.print(var_36);
result += "\n";
result += "Test_Class_3.var_30 = "; result += Test.Printer.print(var_30);
result += "\n";
result += "Test_Class_3.var_34 = "; result += Test.Printer.print(var_34);
result += "\n";
result += "Test_Class_3.var_35 = "; result += Test.Printer.print(var_35);
result += "\n";
result += "Test_Class_3.var_33 = "; result += Test.Printer.print(var_33);
result += "\n";
result += "Test_Class_3.var_31 = "; result += Test.Printer.print(var_31);
result += "\n";
result += "Test_Class_3.var_39 = "; result += Test.Printer.print(var_39);
result += "\n";
result += "Test_Class_3.var_40 = "; result += Test.Printer.print(var_40);
result += "";
result += "\n]";
return result;
}
}
class Test_Class_4 {
final float var_47 = 1.9043434E38F;
final byte var_48 = 32;
final float var_49 = 2.8176504E38F;
final char var_50 = 'r';
final String var_51 = "uwgmnjpg";
static int var_52;
short[] var_53;
Test_Class_1 var_54;
public Test_Class_4()
{
final float var_55 = (3.1554042E38F == var_50 ^ (Test_Class_3.var_40 |= true) ? (Test_Class_3.var_40 ^= Test_Class_3.var_40) ^ true : Test_Class_3.var_40) ? new Test_Class_0().var_2 : 2.965321E38F;
new Test_Class_0().var_2 = (new Test_Class_0().var_2 >>= +new Test_Class_1().var_25);
((Test_Class_1.var_29 = (Test_Class_1.var_29 = (Test_Class_1.var_29 = "l"))) + "").equalsIgnoreCase(Test_Class_1.var_29 = "garnio");
double var_56 = 0;
Test_Class_1.var_29 = var_51;
while (var_56 < 1)
{
((Test_Class_3)(Test_Class_2)(new Object[var_48])[var_48]).var_33 = ++Test_Class_1.var_26;
var_56++;
Test_Class_1.var_29 = (Test_Class_1.var_29 = "fvyjrih");
float[] var_57;
}
{
((new Test_Class_2[var_48])[((new Test_Class_3[var_48][var_48])[var_48][var_48]).var_39]).var_34 *= 2.2119221943262553E307;
Test_Class_2.var_32 = true ? 'q' : 't';
((new Test_Class_3[--((Test_Class_3)new Test_Class_2()).var_39])[var_48]).var_33 = new Test_Class_0().var_2;
int var_58 = 'i' >> (var_48 << Test_Class_0.var_1);
}
Test_Class_3.var_40 &= true && var_51.equalsIgnoreCase(var_51) || new Test_Class_0().var_2 < --((new Test_Class_3[var_48])[var_48]).var_39;
((Test_Class_3)(Test_Class_2)(new Object[var_48][var_48])[var_48][var_48]).var_34 += Test_Class_1.var_26--;
var_54 = new Test_Class_1();
Test_Class_3.var_40 |= (long)(!true ^ var_47 > ((Test_Class_2)(new Object[var_48])[var_48]).var_34 ? (Test_Class_2.var_31 = (Test_Class_3.var_31 = (Test_Class_3.var_31 = var_48))) : (var_54 = new Test_Class_1()).var_25) <= var_48;
(Test_Class_3.var_40 ? (true ? new Test_Class_0() : new Test_Class_0()) : new Test_Class_0()).var_2 &= var_48;
(Test_Class_3.var_40 ? (Test_Class_3)new Test_Class_2() : (new Test_Class_3[var_48][var_48])[var_48][var_48]).var_34 += Test_Class_1.var_21;
Test_Class_3 var_59;
Test_Class_2.var_32 = 'H';
--Test_Class_1.var_26;
}
public String toString()
{
String result = "[\n";
result += "Test_Class_4.var_50 = "; result += Test.Printer.print(var_50);
result += "\n";
result += "Test_Class_4.var_52 = "; result += Test.Printer.print(var_52);
result += "\n";
result += "Test_Class_4.var_53 = "; result += Test.Printer.print(var_53);
result += "\n";
result += "Test_Class_4.var_47 = "; result += Test.Printer.print(var_47);
result += "\n";
result += "Test_Class_4.var_49 = "; result += Test.Printer.print(var_49);
result += "\n";
result += "Test_Class_4.var_48 = "; result += Test.Printer.print(var_48);
result += "\n";
result += "Test_Class_4.var_51 = "; result += Test.Printer.print(var_51);
result += "\n";
result += "Test_Class_4.var_54 = "; result += Test.Printer.print(var_54);
result += "";
result += "\n]";
return result;
}
}
class Test_Class_5 extends Test_Class_4 {
char var_60 = '_';
final byte var_61 = 101;
public Test_Class_5()
{
Test_Class_0.var_3.indexOf(Test_Class_1.var_21, (Test_Class_3.var_40 |= Test_Class_3.var_40) ? new Test_Class_1().var_24 : 'i');
}
final char func_0(Test_Class_1 arg_0, final Test_Class_1 arg_1)
{
long var_62 = 0L;
"aoal".toLowerCase();
for (byte var_63 = arg_0.var_25; var_62 < 1 && "ji".startsWith("dikrs".endsWith("va") ? (Test_Class_1.var_29 = "mvp") : Test_Class_0.var_3, Test_Class_1.var_23); ((Test_Class_2)(new Object[arg_0.var_25])[var_63]).var_34 -= new Test_Class_2().var_36)
{
((Test_Class_3.var_40 ? false : Test_Class_3.var_40) ? (Test_Class_0)(new Object[arg_1.var_25][arg_1.var_25])[arg_1.var_25][var_63] : (Test_Class_0)(new Object[var_48][var_48])[var_63][var_63]).var_2 += true ^ Test_Class_3.var_40 ^ (((new Test_Class_3[var_63][var_63])[var_63][var_61]).var_35 != 2.1423512E38F | ! !false) ? var_49 + ~var_48 : 3.1549515E38F;
var_62++;
(!false & ((Test_Class_3.var_40 |= (Test_Class_3.var_40 ^= true)) & true) ? (Test_Class_2)(new Object[var_63])[var_63] : (new Test_Class_2[var_63][var_61])[var_63][arg_0.var_25]).var_33 = (var_60 *= (var_60 *= ((new Test_Class_3[var_48][var_61])[var_61][var_63]).var_35));
float var_64;
}
Test_Class_1.var_29 = "xyenjknu";
Test_Class_3.var_40 ^= (Test_Class_3.var_40 = !false & true) ? Test_Class_3.var_40 : Test_Class_3.var_40;
((new Test_Class_2[var_48][arg_1.var_25])[arg_0.var_25][var_48]).var_33 = var_61;
Test_Class_1.var_21 |= --(((new Test_Class_3[Test_Class_3.var_31 = arg_0.var_25][var_61])[var_61])[(((new Test_Class_3[var_48][var_61])[var_48])[((Test_Class_3)(new Test_Class_2[var_48][arg_0.var_25])[var_61][var_48]).var_39]).var_39 >>>= var_60]).var_39;
var_51.compareToIgnoreCase("hgcaybk");
Test_Class_0 var_65 = (Test_Class_1.var_29 = "t").codePointBefore(1602805584) >= (float)((new Test_Class_3[var_48][var_61])[var_48][Test_Class_2.var_31 = arg_1.var_25]).var_39 - 7.256386549028811E307 ? new Test_Class_0() : ((new Test_Class_0[arg_0.var_25][var_48][var_48])[arg_0.var_25])[arg_0.var_25][Test_Class_2.var_31 = arg_1.var_25];
return 'U';
}
protected static Test_Class_1 func_1(final short arg_0, long arg_1)
{
--new Test_Class_0().var_2;
"xb".length();
if ((Test_Class_3.var_40 ^= (Test_Class_2.var_32 = Test_Class_0.var_1) == 1.2609472E38F) ? (Test_Class_3.var_40 = (Test_Class_3.var_40 = Test_Class_3.var_40)) : true)
{
--Test_Class_1.var_26;
}
else
{
"ybbe".substring(209378562, var_52 = (Test_Class_1.var_21 |= (Test_Class_2.var_31 = (byte)'a')));
}
Test_Class_3.var_40 &= (Test_Class_3.var_40 &= true) && (Test_Class_1.var_29 = (Test_Class_1.var_29 = Test_Class_0.var_3)).endsWith(Test_Class_0.var_3);
(false ? new Test_Class_0() : new Test_Class_0()).var_2 >>= new Test_Class_1().var_25;
return 9.430116214455637E307 <= (true ? (Test_Class_3)new Test_Class_2() : (Test_Class_3)new Test_Class_2()).var_34 ? new Test_Class_1() : new Test_Class_1();
}
public String toString()
{
String result = "[\n";
result += "Test_Class_5.var_50 = "; result += Test.Printer.print(var_50);
result += "\n";
result += "Test_Class_5.var_60 = "; result += Test.Printer.print(var_60);
result += "\n";
result += "Test_Class_5.var_52 = "; result += Test.Printer.print(var_52);
result += "\n";
result += "Test_Class_5.var_53 = "; result += Test.Printer.print(var_53);
result += "\n";
result += "Test_Class_5.var_47 = "; result += Test.Printer.print(var_47);
result += "\n";
result += "Test_Class_5.var_49 = "; result += Test.Printer.print(var_49);
result += "\n";
result += "Test_Class_5.var_48 = "; result += Test.Printer.print(var_48);
result += "\n";
result += "Test_Class_5.var_61 = "; result += Test.Printer.print(var_61);
result += "\n";
result += "Test_Class_5.var_51 = "; result += Test.Printer.print(var_51);
result += "\n";
result += "Test_Class_5.var_54 = "; result += Test.Printer.print(var_54);
result += "";
result += "\n]";
return result;
}
}
public class Test {
Test_Class_4 var_66;
Test_Class_3 var_67;
Test_Class_5 var_68;
Test_Class_2[] var_69;
long var_70 = ++Test_Class_1.var_26 & Test_Class_1.var_21++;
final static double var_71 = 3.566207721984698E307;
static boolean var_72;
final static String var_73 = "nmxx";
private final char func_0(Test_Class_3 arg_0, final boolean[] arg_1)
{
((Test_Class_5)(arg_1[arg_0.var_39++] ? new Test_Class_2[(var_67 = arg_0).var_39] : (new Object[arg_0.var_39])[arg_0.var_39])).var_54 = new Test_Class_1();
new Test_Class_0();
(((new Test[arg_0.var_39][arg_0.var_39][arg_0.var_39])[++arg_0.var_39])[arg_0.var_39][arg_0.var_39]).var_66 = (var_68 = (new Test_Class_5[arg_0.var_39][arg_0.var_39])[arg_0.var_39][arg_0.var_39]);
((new Test[arg_0.var_39])[(arg_0 = (var_67 = (arg_0 = arg_0))).var_39]).var_70 = ((new long[arg_0.var_39][arg_0.var_39])[arg_0.var_39])[arg_0.var_39 = ((var_67 = (arg_0 = arg_0)).var_39 -= new Test_Class_0().var_2)] << ']';
arg_0 = (new Test_Class_0().var_2 *= ((new Test_Class_2[arg_0.var_39])[arg_0.var_39]).var_34) >= arg_0.var_39 ? (var_67 = arg_0) : (arg_0 = arg_0);
Test_Class_1.var_26--;
Test_Class_4 var_74 = var_66 = (Test_Class_5)(new Test_Class_4[arg_0.var_39])[arg_0.var_39];
Test_Class_3.var_40 ^= ! (Test_Class_3.var_40 &= (Test_Class_3.var_40 ^= Test_Class_3.var_40) | (Test_Class_3.var_40 &= Test_Class_3.var_40));
var_72 = (arg_1[(var_67 = arg_0).var_39] | !Test_Class_3.var_40 & !Test_Class_3.var_40 ? (Test_Class_1.var_29 = var_73).endsWith((var_66 = var_74).var_51) && (Test_Class_3.var_40 ^= Test_Class_3.var_40) : (Test_Class_3.var_40 ^= Test_Class_3.var_40)) ^ !Test_Class_3.var_40;
Test_Class_3.var_40 &= (Test_Class_3.var_40 &= (Test_Class_3.var_40 = Test_Class_3.var_40) & Test_Class_3.var_40 ^ Test_Class_3.var_40);
arg_0.var_39 -= --var_70;
int var_75;
double var_76;
{
boolean var_77;
var_70 ^= new Test_Class_0().var_2++;
}
Test_Class_1.var_26 /= Test_Class_0.var_3.lastIndexOf(~new Test_Class_1().var_25, Test_Class_1.var_21);
Test_Class_1.var_26 |= Test_Class_1.var_21;
(((new Test_Class_3[arg_0.var_39][arg_0.var_39][var_74.var_48])[arg_0.var_39])[arg_0.var_39][arg_0.var_39]).var_34 %= (var_67 = arg_0).var_39;
Test_Class_1.var_21 &= arg_0.var_39;
var_68 = (var_68 = (Test_Class_5)var_74);
var_72 = false;
return new Test_Class_5().var_60 ^= 'v';
}
public static Test_Class_2 func_1(byte[][] arg_0, final int arg_1, Test_Class_1 arg_2, final Test_Class_1 arg_3)
{
((new Test[arg_3.var_25])[((Test_Class_3)new Test_Class_2()).var_39 *= --Test_Class_1.var_26]).var_67 = (((new Test[arg_2.var_25])[(((new Test[arg_2.var_25][arg_2.var_25])[arg_3.var_25][arg_3.var_25]).var_67 = (new Test_Class_3[arg_2.var_25][arg_2.var_25])[arg_2.var_25][arg_3.var_25]).var_39 %= Test_Class_1.var_26]).var_67 = (((new Test[arg_3.var_25][arg_2.var_25])[arg_3.var_25][arg_2.var_25]).var_67 = (((new Test[arg_3.var_25])[arg_2.var_25]).var_67 = (Test_Class_3)new Test_Class_2())));
{
--Test_Class_1.var_26;
}
if (!Test_Class_3.var_40)
{
"jfqj".replaceAll("ac", Test_Class_0.var_3);
}
else
{
arg_2 = (((new Test_Class_5[arg_3.var_25][arg_2.var_25])[((new Test_Class_3[arg_2.var_25])[arg_3.var_25]).var_39][((Test_Class_3)(new Test_Class_2[arg_2.var_25])[arg_3.var_25]).var_39]).var_54 = arg_3);
new Test_Class_1();
}
if (true)
{
Test_Class_0.func_0();
}
else
{
Test_Class_1.var_23 /= Test_Class_1.var_26;
}
Test_Class_1.var_26--;
Test_Class_1.var_23 ^= Test_Class_0.var_1;
return new Test_Class_2();
}
public static String execute()
{
try {
Test t = new Test();
try { t.test(); }
catch(Throwable e) { }
try { return t.toString(); }
catch (Throwable e) { return "Error during result conversion to String"; }
} catch (Throwable e) { return "Error during test execution"; }
}
public static void main(String[] args)
{
try {
Test t = new Test();
try { t.test(); }
catch(Throwable e) { }
try { System.out.println(t); }
catch(Throwable e) { }
} catch (Throwable e) { }
}
private void test()
{
double var_78 = 0;
--Test_Class_1.var_26;
long var_79;
for (var_70 /= 8.089457748637276E307; var_78 < 162 && !true & (true ? Test_Class_3.var_40 : (Test_Class_3.var_40 ^= Test_Class_3.var_40)); Test_Class_1.var_26 -= 1.2513521E38F)
{
short var_80 = 10682;
Test_Class_1.var_21--;
var_78++;
var_72 = (Test_Class_3.var_40 |= (Test_Class_3.var_40 ^= false));
++Test_Class_1.var_26;
}
Test_Class_2 var_81;
new Test_Class_4();
int var_82 = 0;
++Test_Class_1.var_23;
do
{
--Test_Class_1.var_26;
var_82++;
++Test_Class_1.var_21;
} while ((Test_Class_3.var_40 ^= false & false) && var_82 < 256);
Test_Class_1.var_23 |= (var_68 = (var_68 = (Test_Class_5)(var_66 = new Test_Class_4()))).var_48 + (Test_Class_1.var_26 >>> new Test_Class_0().var_2);
(true ? new Test_Class_5() : (var_68 = (var_68 = new Test_Class_5()))).var_60 *= Test_Class_0.var_1;
}
public String toString()
{
String result = "[\n";
result += "Test.var_69 = "; result += Printer.print(var_69);
result += "\n";
result += "Test.var_70 = "; result += Printer.print(var_70);
result += "\n";
result += "Test.var_71 = "; result += Printer.print(var_71);
result += "\n";
result += "Test.var_73 = "; result += Printer.print(var_73);
result += "\n";
result += "Test.var_68 = "; result += Printer.print(var_68);
result += "\n";
result += "Test.var_66 = "; result += Printer.print(var_66);
result += "\n";
result += "Test.var_72 = "; result += Printer.print(var_72);
result += "\n";
result += "Test.var_67 = "; result += Printer.print(var_67);
result += "";
result += "\n]";
return result;
}
static class Printer
{
public static String print(boolean arg) { return String.valueOf(arg); }
public static String print(byte arg) { return String.valueOf(arg); }
public static String print(short arg) { return String.valueOf(arg); }
public static String print(char arg) { return String.valueOf((int)arg); }
public static String print(int arg) { return String.valueOf(arg); }
public static String print(long arg) { return String.valueOf(arg); }
public static String print(float arg) { return String.valueOf(arg); }
public static String print(double arg) { return String.valueOf(arg); }
public static String print(Object arg)
{
return print_r(new java.util.Stack(), arg);
}
private static String print_r(java.util.Stack visitedObjects, Object arg)
{
String result = "";
if (arg == null)
result += "null";
else
if (arg.getClass().isArray())
{
for (int i = 0; i < visitedObjects.size(); i++)
if (visitedObjects.elementAt(i) == arg) return "<recursive>";
visitedObjects.push(arg);
final String delimiter = ", ";
result += "[";
if (arg instanceof Object[])
{
Object[] array = (Object[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print_r(visitedObjects, array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof boolean[])
{
boolean[] array = (boolean[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof byte[])
{
byte[] array = (byte[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof short[])
{
short[] array = (short[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof char[])
{
char[] array = (char[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof int[])
{
int[] array = (int[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof long[])
{
long[] array = (long[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof float[])
{
float[] array = (float[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof double[])
{
double[] array = (double[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
result += "]";
visitedObjects.pop();
} else
{
result += arg.toString();
}
return result;
}
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright 2009 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.
*
*/
/*
* @test
* @bug 6823453
* @summary DeoptimizeALot causes fastdebug server jvm to fail with assert(false,"unscheduable graph")
* @run main/othervm -Xcomp -XX:CompileOnly=Test -XX:+DeoptimizeALot Test
*/
public class Test {
static long vara_1 = 1L;
static void testa() {
short var_2 = (byte) 1.0E10;
for ( Object temp = new byte[(byte)1.0E10]; true ;
var_2 = "1".equals("0") ? ((byte) vara_1) : 1 ) {}
}
static void testb() {
long var_1 = -1L;
short var_2 = (byte) 1.0E10;
for ( Object temp = new byte[(byte)1.0E10]; true ;
var_2 = "1".equals("0") ? ((byte) var_1) : 1 ) {}
}
static void testc() {
long var_1 = -1L;
if (vara_1 > 0) var_1 = 1L;
int var_2 = (byte)var_1 - 128;
for ( Object temp = new byte[var_2]; true ;
var_2 = "1".equals("0") ? 2 : 1 ) {}
}
static void testd() {
long var_1 = 0L;
int var_2 = (byte)var_1 + 1;
for (int i=0; i<2 ; i++) var_2 = var_2 - 1;
for ( Object temp = new byte[var_2]; true ;
var_2 = "1".equals("0") ? 2 : 1 ) {}
}
public static void main(String[] args) throws Exception {
int nex = 0;
try {
testa();
}
catch (java.lang.NegativeArraySizeException ex) { nex++; }
try {
testb();
}
catch (java.lang.NegativeArraySizeException ex) { nex++; }
try {
testc();
}
catch (java.lang.NegativeArraySizeException ex) { nex++; }
try {
testd();
}
catch (java.lang.NegativeArraySizeException ex) { nex++; }
if (nex != 4)
System.exit(97);
}
}