Merge
This commit is contained in:
commit
62717f091a
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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 */ +
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
70
hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp
Normal file
70
hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp
Normal 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
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
1133
hotspot/src/cpu/x86/vm/methodHandles_x86.cpp
Normal file
1133
hotspot/src/cpu/x86/vm/methodHandles_x86.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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; }
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;") \
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 )
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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(); }
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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() {
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
@ -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" );
|
||||
|
2347
hotspot/src/share/vm/prims/methodHandles.cpp
Normal file
2347
hotspot/src/share/vm/prims/methodHandles.cpp
Normal file
File diff suppressed because it is too large
Load Diff
435
hotspot/src/share/vm/prims/methodHandles.hpp
Normal file
435
hotspot/src/share/vm/prims/methodHandles.hpp
Normal 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(); }
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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")\
|
||||
\
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 ) {
|
||||
|
44
hotspot/test/compiler/6539464/Test.java
Normal file
44
hotspot/test/compiler/6539464/Test.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
849
hotspot/test/compiler/6711117/Test.java
Normal file
849
hotspot/test/compiler/6711117/Test.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
96
hotspot/test/compiler/6823453/Test.java
Normal file
96
hotspot/test/compiler/6823453/Test.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user