quicken.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 748 行 · 第 1/2 页
C
748 行
/* * @(#)quicken.c 1.57 06/10/25 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program 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 program 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 at /legal/license.txt). * * 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 or visit www.sun.com if you need additional * information or have any questions. * */#ifdef CVM_CLASSLOADING#include "javavm/include/interpreter.h"#include "javavm/include/classes.h"#include "javavm/include/utils.h"#include "javavm/include/preloader.h"#include "javavm/include/common_exceptions.h"#include "javavm/include/porting/int.h"#include "javavm/include/opcodes.h"#include "javavm/include/globals.h"#include "javavm/include/bcattr.h"#include "javavm/include/indirectmem.h"#ifdef CVM_JVMTI#include "javavm/include/jvmtiExport.h"#endif#ifdef CVM_HW#include "include/hw.h"#endif/* * GET_INDEX - Macro used for getting an unaligned unsigned short from * the byte codes. */#undef GET_INDEX#define GET_INDEX(ptr) (CVMgetUint16(ptr))/* Used to be that we defined CVM_NO_LOSSY_OPCODES in the makefile. * Now we do a runtime check to determine if we will quicken to * a lossy opcode. This is so we can build with JVMTI code compiled * in but run with the non-jvmti interpreter loop and with lossy * romized opcodes. JVMPI instruction tracing needs lossless opcodes * as well, hence this bool. */#ifdef CVM_JVMPI_TRACE_INSTRUCTIONstatic CVMBool isLossy = CVM_FALSE;#elsestatic CVMBool isLossy = CVM_TRUE;#endif/* * Macro to make sure that no register caching is done when we * write a new byte code. */#undef CVM_WRITE_CODE_BYTE#define CVM_WRITE_CODE_BYTE(ptr, offset, newvalue) \ ((volatile CVMUint8*) (ptr))[(offset)] = (newvalue);static CVMQuickenReturnCodeCVMquickenOpcodeHelper(CVMExecEnv* ee, CVMUint8* quickening, CVMUint8* pc, CVMConstantPool* cp, CVMClassBlock** p_cb, CVMBool clobbersCpIndex);/* * CVMopcodeWasQuickened - check to see if the opcode was already quickened. * Note: If breakpoints are enabled and we have to deal with * two threads trying to quicken at the same time. * * WARNING: Must be executed within the code lock. * * p_opcode: Pointer to the opcode we are quickening. The current opcode * at *pc is also returned here. Once this is updated, the code * lock is not released, so the opcode remains valid. * pc: Pointer to the instruction we are quickening */static CVMBoolCVMopcodeWasQuickened(CVMExecEnv* ee, CVMUint8* p_opcode, CVMUint8* pc){ /* * IMPORTANT NOTE: This is not allowed to block, since it is executed * under the global CODE_LOCK microlock. */#ifdef CVM_JVMTI if (*pc == opc_breakpoint) { /* If the original opcode is an opc_breakpoint, then we need call * the debugger to get the real opcode and make sure that it * hasn't been quickened already. */ CVMUint8 breakpointOpcode = CVMjvmtiGetBreakpointOpcode(ee, pc, CVM_FALSE); *p_opcode = breakpointOpcode; /* alway return updated opcode */ } else { *p_opcode = *pc; /* alway return updated opcode */ }#else *p_opcode = *pc; /* alway return updated opcode */#endif return CVMbcAttr(*p_opcode, QUICK);}/* * CVMquickenOpcodeHelper - quickens all opcodes. * * quickening: * A pointer to a three-byte location. On entry, the first byte * contains the instruction to be quickened. On exit, quickening[] * contains the new instruction (and/or the operands) to be written * into the instruction stream. * pc: A pointer to the current instruction. * cp: A pointer to the constant pool. * p_cb: A place to store the CVMClassBlock* in case static initializers * still need to be run. The interpreter needs this. Otherwise * it would need to enter the code lock and repeat what * CVMopcodeWasQuickened() has already done in order to get * the cb from the constant pool. * clobbersCpIndex: true if quickening the opcode will cause the constant * pool index in the instruction to be overwritten. * * Possible return values are: * * CVM_QUICKEN_SUCCESS_OPCODE_ONLY: * quickening succeeded, only opcode changed. * CVM_QUICKEN_SUCCESS_OPCODE_AND_OPERANDS * quickening succeeded, opcode and operands changed. * CVM_QUICKEN_NEED_TO_RUN_STATIC_INITIALIZERS * need to run static initializers, *p_cb updated. The interpreter * needs to run static initializers first and then call * CVMquickenOpcode() again. * CVM_QUICKEN_ALREADY_QUICKENED * someone else already raced us to it * OR * in the JVMTI case, the instruction stream is already * updated in CVMquickenOpcode(). * CVM_QUICKEN_ERROR * an error occurred, exception pending * * On exit quickening[0] contains the new opcode. * quickening[1,2] contain the new operands if they have changed. * */static CVMQuickenReturnCodeCVMquickenOpcodeHelper(CVMExecEnv* ee, CVMUint8* quickening, CVMUint8* pc, CVMConstantPool* cp, CVMClassBlock** p_cb, CVMBool clobbersCpIndex){ CVMUint8 opcode; CVMUint16 cpIndex; CVMBool isStaticOpcode = CVM_FALSE; /* default to false */ CVMBool isPutOpcode = CVM_FALSE; /* default to false */ CVMClassBlock* cb = NULL; CVMMethodBlock* mb = NULL; /* only setup for some invoke opcodes */ CVMFieldBlock* fb = NULL; /* only setup for field opcodes */ CVMBool wasQuickened; /* grab the CVM_CODE_LOCK if necessary */ if (clobbersCpIndex) { /* * We can't trust the cpIndex that we will fetch from the instruction * stream unless we also verify that the opcode hasn't been quickened. * If the opcode was already quickened then there is nothing for * us to do. * * Grabbing the code lock ensures that no one is in the middle * of quickening when we check to see if the opcode has been * quickened yet. We want to avoid the race condition where the * index has been overwritten, but the opcode has not been * written yet. By calling CVMopcodeWasQuickened * from within the code lock, we guarantee that if the opcode * wasn't quickened then the cpIndex is good. If the opcode * has been quickened, then we don't care about cpIndex. */#ifdef CVM_JVMTI CVM_JVMTI_LOCK(ee);#else CVM_CODE_LOCK(ee);#endif } wasQuickened = CVMopcodeWasQuickened(ee, quickening, pc); opcode = quickening[0]; /* * If quickening clobbers the cpIndex, then we must fetch it within * the CVM_CODE_LOCK. */ if (opcode == opc_ldc) { cpIndex = pc[1]; } else { cpIndex = GET_INDEX(pc + 1); } /* release the CVM_CODE_LOCK if necessary */ if (clobbersCpIndex) {#ifdef CVM_JVMTI CVM_JVMTI_UNLOCK(ee);#else CVM_CODE_UNLOCK(ee);#endif } if (wasQuickened) { /* opcode has already been quickened */ return CVM_QUICKEN_ALREADY_QUICKENED; } if (!CVMcpResolveEntry(ee, cp, cpIndex)) { return CVM_QUICKEN_ERROR; } /* * Do any required error checking an handling. */ switch (opcode) { case opc_new: { cb = CVMcpGetCb(cp, cpIndex);#ifndef CVM_TRUSTED_CLASSLOADERS /* * Make sure we are not trying to instantiate an iterface or an * abstract class. */ if (!CVMclassIsOKToInstantiate(ee, cb)) { return CVM_QUICKEN_ERROR; }#endif /* * If static intializers still need to be run for this class, then * leave it up to the interpreter to do this for us first. */ if (CVMcbInitializationNeeded(cb, ee)) { *p_cb = cb; /* return cb to the interpreter. */ return CVM_QUICKEN_NEED_TO_RUN_STATIC_INITIALIZERS; } break; } case opc_putstatic: isStaticOpcode = CVM_TRUE; /* fall through */ case opc_putfield: isPutOpcode = CVM_TRUE; goto check_field; case opc_getstatic: isStaticOpcode = CVM_TRUE; /* fall through */ case opc_getfield: check_field: { fb = CVMcpGetFb(cp, cpIndex); cb = CVMfbClassBlock(fb);#ifndef CVM_TRUSTED_CLASSLOADERS /* * Make sure that both the opcode and the fb agree on whether or * not the field is static. */ if (!CVMfieldHasNotChangeStaticState(ee, fb, isStaticOpcode)) { return CVM_QUICKEN_ERROR; } /* * Make sure we aren't trying to store into a final field. * The VM spec says that you can only store into a final field * when initializing it. The JDK seems to interpret this as * meaning that a class has write access to its final fields, * so we do the same here (see how isFinalField gets setup above). */ if (isPutOpcode) { if (!CVMfieldIsOKToWriteTo(ee, fb, CVMeeGetCurrentFrameCb(ee), CVM_TRUE)) { return CVM_QUICKEN_ERROR; } } #endif /* CVM_TRUSTED_CLASSLOADERS */ /* * If static intializers still need to be run for this class, * then leave it up to the interpreter to do this for us * first. */ if (CVMcbInitializationNeeded(cb, ee)) { *p_cb = cb; /* return cb to the interpreter. */ return CVM_QUICKEN_NEED_TO_RUN_STATIC_INITIALIZERS; } break; } case opc_invokestatic: isStaticOpcode = CVM_TRUE; goto check_method; case opc_invokevirtual: case opc_invokespecial: check_method: { mb = CVMcpGetMb(cp, cpIndex); cb = CVMmbClassBlock(mb);#ifndef CVM_TRUSTED_CLASSLOADERS /* * Make sure that both the opcode and the mb agree on whether or * not the method is static. */ if (!CVMmethodHasNotChangeStaticState(ee, mb, isStaticOpcode)) { return CVM_QUICKEN_ERROR; } #endif /* * If static intializers still need to be run for this class, then * leave it up to the interpreter to do this for us first. */ if ((opcode == opc_invokestatic) && CVMcbInitializationNeeded(cb, ee)) { *p_cb = cb; /* return cb to the interpreter. */ return CVM_QUICKEN_NEED_TO_RUN_STATIC_INITIALIZERS; } break; } case opc_invokeinterface: case opc_anewarray: case opc_multianewarray: case opc_checkcast: case opc_instanceof: case opc_ldc: case opc_ldc_w: case opc_ldc2_w: /* nothing to do for these opcodes */ break; default: CVMassert(CVM_FALSE); } /* * Get the new instruction bytes for the quickened opcode. */ { CVMUint8 newOpcode = opc_xxxunusedxxx;/* opcode we will quicken to. */ CVMUint8 operand1 = 0; /* 1st instruction operand if needed. */ CVMUint8 operand2 = 0; /* 2nd instruction operand if needed. */ CVMBool changesOperands = CVM_FALSE; /* true if quickening changes * the operands */ /* * Assign newOpcode to the opcode we are going to quicken to. * If the 1st or 2nd operand bytes are also modified, set operand1 * and operand2 to the proper values and set the changesOperands flag. */ switch (opcode) { case opc_new: if (CVMcbCheckInitNeeded(cb, ee)) { newOpcode = opc_new_checkinit_quick; } else { newOpcode = opc_new_quick; } break; case opc_anewarray: newOpcode = opc_anewarray_quick; break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?