📄 codehacker.java
字号:
/* * CodeHacker.java 1.17 01/04/27 SMI * * Copyright (c) 1997,1999 Sun Microsystems, Inc. All Rights Reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. * Use is subject to license terms. */package vm;import components.*;import java.io.PrintStream;import vm.Const;import vm.EVMConst;import util.DataFormatException;import util.SignatureIterator;/* * This class "quickens" Java bytecodes. * That is, it looks at the instructions having symbolic references, * such as get/putfield and methodcalls, attempts to resolve the references * and re-writes the instructions in their JVM-specific, quick form. * * Resolution failures are not (any longer) considered fatal errors, they * just result in code that cannot be considered as read-only, as more * resolution will be required at runtime, as we refuse to re-write any * instructions having unresolved references. * * The following is an exception to the above rule (and an unfortunate hack): * References to array classes (having names starting in "[") are * quickened anyway, as we have confidence that these classes, though not * instantiated when this code is run, will be instantiated in time. * (Perhaps this should be under control of a flag?) * */publicclass CodeHacker { ConstantPool pool; boolean warn; boolean verbose; PrintStream log; boolean useLosslessOpcodes = false; ClassInfo java_lang_Object; private boolean success; private byte newopcode; public CodeHacker( ConstantPool p, boolean lossless, boolean w, boolean v ){ pool = p; warn = w; verbose = v; log = System.out; java_lang_Object = ClassInfo.lookupClass("java/lang/Object"); if ( java_lang_Object == null ){ log.println("CodeHacker: could not find java/lang/Object"); } useLosslessOpcodes = lossless; } private void lookupFailed( ClassConstant me, FMIrefConstant target ){ log.println("Quickening "+me.name.string+": lookup failed for "+target); success = false; } private static int getInt( byte code[], int w ){ return ( (int)code[w] << 24 ) | (( (int)code[w+1] &0xff ) << 16 ) | (( (int)code[w+2] &0xff ) << 8 ) | ( (int)code[w+3] &0xff ); } private static int getUnsignedShort( byte code[], int w ){ return (( (int)code[w] &0xff ) << 8 ) | ( (int)code[w+1] &0xff ); } private static void putShort( byte code[], int w, short v ){ code[w] = (byte)(v>>>8); code[w+1] = (byte)v; } private FMIrefConstant dup( FMIrefConstant c ){ return (FMIrefConstant) pool.dup( c ); } /* * Returns true if the reference was fully quickened. * Returns false if the reference could not be deleted, either because * the lookup failed, or because we had to use the wide variant. * Sets this.success to false if the lookup failed or there was no * usable variant. */ private boolean quickenFieldAccess( ClassConstant me, byte code[], int loc, boolean isStatic, ConstantObject c[], int oneWord, int twoWords, int refReference) { FieldConstant fc = (FieldConstant)c[ getUnsignedShort( code, loc+1 ) ]; FieldInfo fi = fc.find(); if ( fi == null ){ // never even try to quicken anything we cannot resolve. lookupFailed( me, fc ); return false; } byte newCode; switch (fc.sig.type.string.charAt(0) ){ case '[': case 'L': newCode = (byte)refReference; break; case 'D': case 'J': newCode = (byte)twoWords; break; default: newCode = (byte)oneWord; break; } if ( isStatic ) { code[loc] = newCode; return false; // still references constant pool! } else { int fieldOffset = fi.instanceOffset; code[loc+1] = (byte)((fieldOffset >> 8) & 0xFF); code[loc+2] = (byte) (fieldOffset & 0xFF); code[loc] = newCode; return true; } } /* * Should a call to the specified methodblock be turned into * an invokesuper_fast instead of a invokenonvirtual_fast? * * The fourTHREE conditions that have to be satisfied: * The method isn't private * The method isn't an <init> method * XXXXThe ACC_SUPER flag is set in the current class * The method's class is a superclass (and not equal) to * the current class. */ private boolean isSpecialSuperCall( MethodInfo me, MethodInfo callee ){ String name = callee.name.string; if ( (callee.access&Const.ACC_PRIVATE) != 0 ) return false; if ( name.equals("<init>") ) return false; ClassInfo myclass = me.parent; ClassInfo hisclass = callee.parent; if ( myclass == hisclass ) return false; // walk up my chain, looking for other's class while ( myclass != null ){ myclass = myclass.superClassInfo; if ( myclass == hisclass ) return true; } return false; } private boolean quickenCode( MethodInfo m, ConstantObject c[] ) throws DataFormatException { byte code[] = m.code; int list[] = m.ldcInstructions; ConstantObject co; FieldConstant fc; MethodConstant mc; NameAndTypeConstant nt; ClassConstant cc; String t; ClassConstant me = m.parent.thisClass; MethodInfo mi; ClassInfo ci; success = true; if (verbose){ log.println("Q>>METHOD "+m.name.string ); } if ( list != null ){ for ( int i = 0; i < list.length; i++ ){ int loc = list[i]; if ( loc < 0 ) continue; switch( (int)code[loc]&0xff ){ case Const.opc_ldc: // // no danger of lookup failure here, // so don't even examine the referenced object. // co = c[(int)code[loc+1]&0xff]; break; default: throw new DataFormatException( "unexpected opcode in ldc="+ ((int)code[loc]&0xff)+" at loc="+loc+ " in "+m.qualifiedName() ); } } } list = m.wideConstantRefInstructions; if ( list != null ){ MethodInfo[] tList = null; int tli = 0; // index into tList if (VMMethodInfo.SAVE_TARGET_METHODS) { tList = new MethodInfo[list.length]; } for ( int i = 0; i < list.length; i++ ){ int loc = list[i]; if ( loc < 0 ) continue; co = c[ getUnsignedShort(code, loc+1) ]; if ( ! co.isResolved() ){ // // don't try to quicken unresolved references. // this is not fatal! // // Do quicken if its a reference to an array!! // What a hack! if ( (co instanceof ClassConstant ) && ((ClassConstant)co).name.string.charAt(0) == Const.SIGC_ARRAY ){ ((ClassConstant)co).forget(); // never mind, we'll fix later... } else { if ( warn ){ log.println("Warning: could not quicken reference from " + m.qualifiedName() + " to "+co ); } continue; } } switch( (int)code[loc]&0xff ){ case Const.opc_ldc_w: co.incldcReference(); break; case Const.opc_ldc2_w: break; case Const.opc_getstatic: quickenFieldAccess( me, code, loc, true, c, Const.opc_getstatic_fast, Const.opc_getstatic2_fast, Const.opc_getstaticp_fast); break; case Const.opc_putstatic: quickenFieldAccess( me, code, loc, true, c, Const.opc_putstatic_fast, Const.opc_putstatic2_fast, Const.opc_putstatic_fast); break; case Const.opc_getfield: if (quickenFieldAccess( me, code, loc, false, c, Const.opc_getfield_fast, Const.opc_getfield2_fast, Const.opc_getfieldp_fast )) { // doesn't reference constant pool any more list[i] = -1; } break; case Const.opc_putfield: if (quickenFieldAccess( me, code, loc, false, c, Const.opc_putfield_fast, Const.opc_putfield2_fast, Const.opc_putfield_fast)) { // doesn't reference constant pool any more list[i] = -1; } break; case Const.opc_invokevirtual: mc = (MethodConstant)c[ getUnsignedShort( code, loc+1 ) ]; mi = mc.find(); if (mi != null){ if (mi.isPrivateMember() || ((mi.access & Const.ACC_FINAL) != 0) || ((mi.parent.access & Const.ACC_FINAL) != 0)) { code[loc] = (byte)Const.opc_invokespecial_fast; } } break; case Const.opc_invokeinterface: break; case Const.opc_invokestatic: code[loc] = (byte)Const.opc_invokestatic_fast; break; case Const.opc_new: code[loc] = (byte)Const.opc_new_fast; break; case Const.opc_anewarray: // code[loc] = (byte)Const.opc_anewarray_fast; break; case Const.opc_checkcast: code[loc] = (byte)Const.opc_checkcast_fast; break; case Const.opc_instanceof: code[loc] = (byte)Const.opc_instanceof_fast; break; case Const.opc_multianewarray: code[loc] = (byte)Const.opc_multianewarray_fast; break; case Const.opc_invokespecial: code[loc] = (byte)Const.opc_invokespecial_fast; break; default: throw new DataFormatException( "unexpected opcode in wideConstantRef="+ ((int)code[loc]&0xff)+" at loc="+loc+ " in "+m.qualifiedName() ); } } // Alloc and copy to new targetMethods array if (VMMethodInfo.SAVE_TARGET_METHODS) { m.targetMethods = new MethodInfo[tli]; System.arraycopy(tList, 0, m.targetMethods, 0, tli); } } return success; } public boolean quickenCode( ClassInfo c ){ ConstantObject constants[] = c.constants; MethodInfo method[]= c.methods; int n = method.length; int i = 0; boolean result = true; try { for ( i = 0; i < n; i++ ){ if ( ! quickenCode( method[i], constants ) ) result = false; } } catch( DataFormatException e ){ System.err.println("Quickening "+method[i].qualifiedName()+" got exception:"); e.printStackTrace(); return false; } return result; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -