📄 code-analyse.c
字号:
/* code-analyse.c * Analyse a method's bytecodes. * * Copyright (c) 1996, 1997 * Transvirtual Technologies, Inc. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. */#define IDBG(s)#define VDBG(s)#include "config.h"#include "debug.h"#include "config-std.h"#include "gtypes.h"#include "bytecode.h"#include "object.h"#include "constants.h"#include "access.h"#include "classMethod.h"#include "code-analyse.h"#include "lookup.h"#include "exception.h"#include "icode.h"#include "itypes.h"#include "locks.h"#include "thread.h"#include "jthread.h"#include "baseClasses.h"#include "soft.h"#include "md.h"#include "gc.h"const uint8 insnLen[256] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 5, 1, 3, 2, 3, 1, 1, 3, 3, 1, 1, 1, 4, 3, 3, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };static void mergeFrame(codeinfo*, int, int, frameElement*, Method*);static bool analyzeBasicBlock(codeinfo*, Method*, int32, errorInfo*);static void updateLocals(codeinfo*, int32, frameElement*);static bool analyzeCatchClause(jexceptionEntry*, Hjava_lang_Class*, errorInfo*);boolanalyzeMethod(Method* meth, codeinfo **pcodeinfo, errorInfo *einfo){ int32 pc; int32 tabpc; int32 idx; int32 sp; int32 lcl; int count; perPCInfo* bhead; perPCInfo* btail; perPCInfo* bcurr; bool rerun; bool failed; bool wide; codeinfo *codeInfo; localUse* localuse;DBG(CODEANALYSE, dprintf("%s %p: %s.%s\n", __FUNCTION__, THREAD_NATIVE(), meth->class->name->data, meth->name->data); ) if( meth->c.bcode.code == 0 ) { postExceptionMessage(einfo, JAVA_LANG(VerifyError), "No code attribute for %s.%s.", meth->class->name->data, meth->name->data); return false; } codeInfo = gc_malloc(sizeof(codeinfo) + meth->c.bcode.codelen*sizeof(perPCInfo), GC_ALLOC_CODEANALYSE); *pcodeinfo = codeInfo; if (!codeInfo) { postOutOfMemory(einfo); return false; } /* Allocate space for local register info - we add in an extra one * to avoid mallocing 0 bytes. */ localuse = gc_malloc(sizeof(localUse) * (meth->localsz+1), GC_ALLOC_CODEANALYSE); if (!localuse) { KFREE(codeInfo); postOutOfMemory(einfo); return false; } codeInfo->localuse = localuse; /* We don't need to do this twice */ meth->accflags |= ACC_VERIFIED; for (lcl = 0; lcl < meth->localsz; lcl++) { localuse = codeInfo->localuse; localuse[lcl].use = 0; localuse[lcl].first = 0x7FFFFFFF; localuse[lcl].last = -1; localuse[lcl].write = -1; localuse[lcl].type = 0; }DBG(CODEANALYSE, dprintf("%s %p: codeInfo = %p\n", __FUNCTION__, THREAD_NATIVE(), codeInfo); ) /* Allocate code info. block */ codeInfo->localsz = meth->localsz; codeInfo->stacksz = meth->stacksz; codeInfo->codelen = meth->c.bcode.codelen; /* First basic block becomes head of block chain */ SET_NEEDVERIFY(0); bhead = &codeInfo->perPC[0]; btail = bhead; /* Scan the code and mark the beginning of basic blocks */ wide = false; for (pc = 0; pc < codeInfo->codelen;) { SET_STARTOFINSTRUCTION(pc); /* set native pc to -1 so that we can recognize whether * a corresponding native PC will be generated. */ SET_INSNPC(pc, -1); switch (INSN(pc)) { case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE: case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLE: case IF_ACMPEQ: case IF_ACMPNE: case IFNULL: case IFNONNULL: tabpc = pc + WORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); SET_STARTOFBASICBLOCK(pc); SET_NORMALFLOW(pc); break; case GOTO: tabpc = pc + WORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case GOTO_W: tabpc = pc + DWORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case JSR: tabpc = pc + WORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); SET_STARTOFBASICBLOCK(pc); SET_NORMALFLOW(pc); break; case JSR_W: tabpc = pc + DWORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); SET_STARTOFBASICBLOCK(pc); SET_NORMALFLOW(pc); break; case TABLESWITCH: tabpc = (pc + 4) & -4; idx = DWORD(tabpc+8)-DWORD(tabpc+4)+1; for (; idx > 0; idx--) { SET_STARTOFBASICBLOCK(pc+DWORD(tabpc+idx*4+8)); SET_JUMPFLOW(pc, pc+DWORD(tabpc+idx*4+8)); } SET_STARTOFBASICBLOCK(pc+DWORD(tabpc)); SET_JUMPFLOW(pc, pc+DWORD(tabpc)); pc = tabpc + (DWORD(tabpc+8)-DWORD(tabpc+4)+1+3) * 4; if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case LOOKUPSWITCH: tabpc = (pc + 4) & -4; idx = DWORD(tabpc+4); for (; idx > 0; idx--) { SET_STARTOFBASICBLOCK(pc+DWORD(tabpc+idx*8+4)); SET_JUMPFLOW(pc, pc+DWORD(tabpc+idx*8+4)); } SET_STARTOFBASICBLOCK(pc+DWORD(tabpc)); SET_JUMPFLOW(pc, pc+DWORD(tabpc)); pc = tabpc + (DWORD(tabpc+4)+1) * 8; if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case IRETURN: case LRETURN: case ARETURN: case FRETURN: case DRETURN: case RETURN: case ATHROW: case RET: pc = pc + INSNLEN(pc); if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case WIDE: wide = true; pc = pc + INSNLEN(pc); SET_NORMALFLOW(pc); break; case ILOAD: case LLOAD: case FLOAD: case DLOAD: case ALOAD: case ISTORE: case LSTORE: case FSTORE: case DSTORE: case ASTORE: pc = pc + INSNLEN(pc); if (wide == true) { wide = false; pc += 1; } SET_NORMALFLOW(pc); break; case IINC: pc = pc + INSNLEN(pc); if (wide == true) { wide = false; pc += 2; } SET_NORMALFLOW(pc); break; default: /* The default */ pc = pc + INSNLEN(pc); SET_NORMALFLOW(pc); break; } } /* Setup exception info. */ sp = meth->localsz + meth->stacksz - 1; if (meth->exception_table != 0) { for (lcl = 0; lcl < meth->exception_table->length; lcl++) { bool succ; jexceptionEntry *entry; entry = &(meth->exception_table->entry[lcl]); /* Verify catch clause exception has valid type. */ succ = analyzeCatchClause(entry, meth->class, einfo); if (succ == false) { return false; } pc = entry->handler_pc; ATTACH_NEW_BASICBLOCK(pc); SET_STARTOFEXCEPTION(pc); SET_STACKPOINTER(pc, sp); SET_NEWFRAME(pc); STACKINIT(0, TOBJ); } } /* Mark the various starting states. These include the main * entry point plus all the exception entry points, their arguments * and stack values. */ pc = 0; SET_STACKPOINTER(pc, meth->localsz + meth->stacksz); SET_NEWFRAME(pc); /* Parse the method signature to setup the inital locals */ idx = 0; if ((meth->accflags & ACC_STATIC) == 0) { LOCALINIT(0, TOBJ); idx++; } for (count = 0; count < METHOD_NARGS(meth); ++count) { switch (*METHOD_ARG_TYPE(meth, count)) { case 'L': case '[': LOCALINIT(idx, TOBJ); idx += 1; break; case 'I': case 'Z': case 'S': case 'B': case 'C': LOCALINIT(idx, TINT); idx += 1; break; case 'J': LOCALINIT(idx, TLONG); LOCALINIT(idx+1, TVOID); idx += 2; break; case 'F': LOCALINIT(idx, TFLOAT); idx += 1; break; case 'D': LOCALINIT(idx, TDOUBLE); LOCALINIT(idx+1, TVOID); idx += 2; break; default: assert("Signature character unknown" == 0); } } /* Scan out list of basic blocks. Unfortunately they're not in * precise order so we have to do this until they're all done. */ do { rerun = false; for (bcurr = bhead; bcurr != NULL; bcurr = bcurr->nextBB) { pc = bcurr - codeInfo->perPC; if (IS_NEEDVERIFY(pc)) { failed = analyzeBasicBlock(codeInfo, meth, pc, einfo); if (failed) { tidyAnalyzeMethod(pcodeinfo); return (false); } rerun = true; } } } while (rerun == true); /* Check we've processed each block at least once */ /* Note that it is perfectly legal for code to contain unreachable * basic blocks; There's no need to complain. */#if VDBG(1) - 1 == 0 for (bcurr = bhead; bcurr != NULL; bcurr = bcurr->nextBB) { if ((bcurr->flags & FLAG_DONEVERIFY) == 0) { VDBG(dprintf("%s.%s%s pc %d bcurr->flags 0x%04x\n", meth->class->name->data, meth->name->data, METHOD_SIGD(meth), bcurr - codeInfo->perPC, bcurr->flags);) } }#endif return (true);}staticboolanalyzeBasicBlock(codeinfo* codeInfo, Method* meth, int32 pc, errorInfo *einfo){ int32 tabpc; int32 idx; int32 sp; int32 opc; callInfo call; fieldInfo finfo; Hjava_lang_Class* type; const char* sig; frameElement* activeFrame; bool wide; bool failed; bool firsttime; opc = pc; assert(pc == 0 || IS_STARTOFBASICBLOCK(pc) || IS_STARTOFEXCEPTION(pc)); assert(IS_STACKPOINTERSET(pc)); /* If this block hasn't been verified before then note this */ if (!IS_DONEVERIFY(pc)) { firsttime = true; } else { firsttime = false; } /* Get stack pointer */ sp = STACKPOINTER(pc); /* Allocate frame to hold type data */ activeFrame = ALLOCFRAME(); if (activeFrame == 0) { postOutOfMemory(einfo); return true; } SET_DONEVERIFY(pc); FRAMELOAD(pc); /* Process basic block until we get to the beginning of a new one */ wide = false; failed = false; do { if (sp < meth->localsz || sp > meth->localsz + meth->stacksz) { failed = true; postExceptionMessage(einfo, JAVA_LANG(VerifyError), "In class %s in method %s with signature %s at pc %d: sp %d not in range [%d, %d]", meth->class->name->data, meth->name->data, METHOD_SIGD(meth), pc, sp, meth->localsz, meth->localsz + meth->stacksz); break; } /* If we're in an exception block, merge locals into * the handler. */ if (meth->exception_table != 0) { for (idx = 0; idx < meth->exception_table->length; idx++) { if (pc >= meth->exception_table->entry[idx].start_pc && pc < meth->exception_table->entry[idx].end_pc) { FRAMEMERGE_LOCALS(meth->exception_table->entry[idx].handler_pc); } } }IDBG( dprintf("%d: %d\n", pc, INSN(pc)); ) switch (INSN(pc)) { int32 lcl; case NOP: INCPC(1); break; case ACONST_NULL: STKPUSH(1); STACKOUT(0, TOBJ); INCPC(1); break; case ICONST_M1: case ICONST_0: case ICONST_1: case ICONST_2: case ICONST_3: case ICONST_4: case ICONST_5: STKPUSH(1); STACKOUT_CONST(0, TINT, INSN(pc) - ICONST_0); INCPC(1); break; case BIPUSH: STKPUSH(1); STACKOUT_CONST(0, TINT, BYTE(pc+1)); INCPC(2); break; case SIPUSH: STKPUSH(1); STACKOUT_CONST(0, TINT, WORD(pc+1)); INCPC(3); break; case LCONST_0: case LCONST_1: STKPUSH(2); STACKOUT(0, TLONG); STACKOUT(1, TVOID); INCPC(1); break; case FCONST_0: case FCONST_1: case FCONST_2: STKPUSH(1); STACKOUT(0, TFLOAT); INCPC(1); break; case DCONST_0: case DCONST_1: STKPUSH(2); STACKOUT(0, TDOUBLE); STACKOUT(1, TVOID); INCPC(1); break; case LDC1: STKPUSH(1); lcl = (uint8)BYTE(pc + 1); CONSTANTTYPE(type, lcl); STACKOUT(0, type); INCPC(2); break; case LDC2: STKPUSH(1); CONSTANTTYPE(type, (uint16)WORD(pc+1)); STACKOUT(0, type); INCPC(3); break; case LDC2W: STKPUSH(2); CONSTANTTYPE(type, (uint16)WORD(pc+1)); STACKOUT(0, type); STACKOUT(1, TVOID); INCPC(3); break; case ILOAD_0: case ILOAD_1: case ILOAD_2: case ILOAD_3: lcl = INSN(pc) - ILOAD_0; STKPUSH(1); STACKOUT_LOCAL(0, TINT, lcl); INCPC(1); break; case ILOAD: if (wide) { wide = false; STKPUSH(1); STACKOUT_LOCAL(0, TINT, WORD(pc+1)); INCPC(3); } else { STKPUSH(1); STACKOUT_LOCAL(0, TINT, BYTE(pc+1)); INCPC(2); } break; case LLOAD_0: case LLOAD_1: case LLOAD_2: case LLOAD_3: lcl = INSN(pc) - LLOAD_0; STKPUSH(2); STACKOUT_LOCAL(0, TLONG, lcl); STACKOUT_LOCAL(1, TVOID, lcl+1); INCPC(1); break; case LLOAD: if (wide) { wide = false; STKPUSH(2); STACKOUT_LOCAL(0, TLONG, WORD(pc+1)); STACKOUT_LOCAL(1, TVOID, WORD(pc+1)+1); INCPC(3); } else { STKPUSH(2); STACKOUT_LOCAL(0, TLONG, BYTE(pc+1)); STACKOUT_LOCAL(1, TVOID, BYTE(pc+1)+1); INCPC(2); } break; case FLOAD_0: case FLOAD_1: case FLOAD_2: case FLOAD_3: lcl = INSN(pc) - FLOAD_0; STKPUSH(1); STACKOUT_LOCAL(0, TFLOAT, lcl); INCPC(1); break; case FLOAD: if (wide) { wide = false; STKPUSH(1); STACKOUT_LOCAL(0, TFLOAT, WORD(pc+1)); INCPC(3); } else { STKPUSH(1); STACKOUT_LOCAL(0, TFLOAT, BYTE(pc+1)); INCPC(2); } break; case DLOAD_0: case DLOAD_1: case DLOAD_2: case DLOAD_3: lcl = INSN(pc) - DLOAD_0; STKPUSH(2); STACKOUT_LOCAL(0, TDOUBLE, lcl); STACKOUT_LOCAL(1, TVOID, lcl+1); INCPC(1); break; case DLOAD: if (wide) { lcl = WORD(pc+1); wide = false; STKPUSH(2); STACKOUT_LOCAL(0, TDOUBLE, lcl); STACKOUT_LOCAL(1, TVOID, lcl+1); INCPC(3); } else { lcl = BYTE(pc+1); STKPUSH(2); STACKOUT_LOCAL(0, TDOUBLE, lcl); STACKOUT_LOCAL(1, TVOID, lcl+1); INCPC(2); } break; case ALOAD_0: case ALOAD_1: case ALOAD_2: case ALOAD_3: lcl = INSN(pc) - ALOAD_0; STKPUSH(1); STACKOUT_LOCAL(0, TOBJ, lcl); INCPC(1); break; case ALOAD: if (wide) { wide = false; STKPUSH(1); STACKOUT_LOCAL(0, TOBJ, WORD(pc+1)); INCPC(3); } else { STKPUSH(1); STACKOUT_LOCAL(0, TOBJ, BYTE(pc+1)); INCPC(2); } break; case IALOAD: case BALOAD: case CALOAD: case SALOAD: STACKIN(1, TOBJ); STACKIN(0, TINT); STKPOP(1); STACKOUT(0, TINT); INCPC(1); break; case LALOAD: STACKIN(1, TOBJ); STACKIN(0, TINT); STACKOUT(0, TLONG); STACKOUT(1, TVOID); INCPC(1); break; case FALOAD: STACKIN(1, TOBJ); STACKIN(0, TINT); STKPOP(1); STACKOUT(0, TFLOAT); INCPC(1); break; case DALOAD: STACKIN(1, TOBJ); STACKIN(0, TINT); STACKOUT(0, TDOUBLE); STACKOUT(1, TVOID); INCPC(1); break; case AALOAD: STACKIN(1, TOBJ); STACKIN(0, TINT); STKPOP(1); STACKOUT(0, TOBJ); INCPC(1); break; case ISTORE_0: case ISTORE_1: case ISTORE_2: case ISTORE_3: lcl = INSN(pc) - ISTORE_0; LOCALOUT_STACK(lcl, TINT, 0); STKPOP(1); INCPC(1); break; case ISTORE: if (wide) { LOCALOUT_STACK(WORD(pc+1), TINT, 0); INCPC(1); wide = false; } else { LOCALOUT_STACK(BYTE(pc+1), TINT, 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -