Path: blob/master/src/java.base/share/native/libverify/check_code.c
41149 views
/*1* Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*-26* Verify that the code within a method block doesn't exploit any27* security holes.28*/29/*30Exported function:3132jboolean33VerifyClassForMajorVersion(JNIEnv *env, jclass cb, char *message_buffer,34jint buffer_length, jint major_version)3536This file now only uses the standard JNI and the following VM functions37exported in jvm.h:3839JVM_FindClassFromClass40JVM_IsInterface41JVM_GetClassNameUTF42JVM_GetClassCPEntriesCount43JVM_GetClassCPTypes44JVM_GetClassFieldsCount45JVM_GetClassMethodsCount4647JVM_GetFieldIxModifiers4849JVM_GetMethodIxModifiers50JVM_GetMethodIxExceptionTableLength51JVM_GetMethodIxLocalsCount52JVM_GetMethodIxArgsSize53JVM_GetMethodIxMaxStack54JVM_GetMethodIxNameUTF55JVM_GetMethodIxSignatureUTF56JVM_GetMethodIxExceptionsCount57JVM_GetMethodIxExceptionIndexes58JVM_GetMethodIxByteCodeLength59JVM_GetMethodIxByteCode60JVM_GetMethodIxExceptionTableEntry61JVM_IsConstructorIx6263JVM_GetCPClassNameUTF64JVM_GetCPFieldNameUTF65JVM_GetCPMethodNameUTF66JVM_GetCPFieldSignatureUTF67JVM_GetCPMethodSignatureUTF68JVM_GetCPFieldClassNameUTF69JVM_GetCPMethodClassNameUTF70JVM_GetCPFieldModifiers71JVM_GetCPMethodModifiers7273JVM_ReleaseUTF74JVM_IsSameClassPackage7576*/7778#include <string.h>79#include <setjmp.h>80#include <assert.h>81#include <limits.h>82#include <stdlib.h>8384#include "jni.h"85#include "jni_util.h"86#include "jvm.h"87#include "classfile_constants.h"88#include "opcodes.in_out"8990/* On AIX malloc(0) and calloc(0, ...) return a NULL pointer, which is legal,91* but the code here does not handles it. So we wrap the methods and return non-NULL92* pointers even if we allocate 0 bytes.93*/94#ifdef _AIX95static int aix_dummy;96static void* aix_malloc(size_t len) {97if (len == 0) {98return &aix_dummy;99}100return malloc(len);101}102103static void* aix_calloc(size_t n, size_t size) {104if (n == 0) {105return &aix_dummy;106}107return calloc(n, size);108}109110static void aix_free(void* p) {111if (p == &aix_dummy) {112return;113}114free(p);115}116117#undef malloc118#undef calloc119#undef free120#define malloc aix_malloc121#define calloc aix_calloc122#define free aix_free123#endif124125#ifdef __APPLE__126/* use setjmp/longjmp versions that do not save/restore the signal mask */127#define setjmp _setjmp128#define longjmp _longjmp129#endif130131#define MAX_ARRAY_DIMENSIONS 255132/* align byte code */133#ifndef ALIGN_UP134#define ALIGN_UP(n,align_grain) (((n) + ((align_grain) - 1)) & ~((align_grain)-1))135#endif /* ALIGN_UP */136#define UCALIGN(n) ((unsigned char *)ALIGN_UP((uintptr_t)(n),sizeof(int)))137138#ifdef DEBUG139140int verify_verbose = 0;141static struct context_type *GlobalContext;142#endif143144enum {145ITEM_Bogus,146ITEM_Void, /* only as a function return value */147ITEM_Integer,148ITEM_Float,149ITEM_Double,150ITEM_Double_2, /* 2nd word of double in register */151ITEM_Long,152ITEM_Long_2, /* 2nd word of long in register */153ITEM_Array,154ITEM_Object, /* Extra info field gives name. */155ITEM_NewObject, /* Like object, but uninitialized. */156ITEM_InitObject, /* "this" is init method, before call157to super() */158ITEM_ReturnAddress, /* Extra info gives instr # of start pc */159/* The following four are only used within array types.160* Normally, we use ITEM_Integer, instead. */161ITEM_Byte,162ITEM_Short,163ITEM_Char,164ITEM_Boolean165};166167168#define UNKNOWN_STACK_SIZE -1169#define UNKNOWN_REGISTER_COUNT -1170#define UNKNOWN_RET_INSTRUCTION -1171172#undef MAX173#undef MIN174#define MAX(a, b) ((a) > (b) ? (a) : (b))175#define MIN(a, b) ((a) < (b) ? (a) : (b))176177#define BITS_PER_INT (CHAR_BIT * sizeof(int)/sizeof(char))178#define SET_BIT(flags, i) (flags[(i)/BITS_PER_INT] |= \179((unsigned)1 << ((i) % BITS_PER_INT)))180#define IS_BIT_SET(flags, i) (flags[(i)/BITS_PER_INT] & \181((unsigned)1 << ((i) % BITS_PER_INT)))182183typedef unsigned int fullinfo_type;184typedef unsigned int *bitvector;185186#define GET_ITEM_TYPE(thing) ((thing) & 0x1F)187#define GET_INDIRECTION(thing) (((thing) & 0xFFFF) >> 5)188#define GET_EXTRA_INFO(thing) ((thing) >> 16)189#define WITH_ZERO_INDIRECTION(thing) ((thing) & ~(0xFFE0))190#define WITH_ZERO_EXTRA_INFO(thing) ((thing) & 0xFFFF)191192#define MAKE_FULLINFO(type, indirect, extra) \193((type) + ((indirect) << 5) + ((extra) << 16))194195#define MAKE_Object_ARRAY(indirect) \196(context->object_info + ((indirect) << 5))197198#define NULL_FULLINFO MAKE_FULLINFO(ITEM_Object, 0, 0)199200/* JVM_OPC_invokespecial calls to <init> need to be treated special */201#define JVM_OPC_invokeinit 0x100202203/* A hash mechanism used by the verifier.204* Maps class names to unique 16 bit integers.205*/206207#define HASH_TABLE_SIZE 503208209/* The buckets are managed as a 256 by 256 matrix. We allocate an entire210* row (256 buckets) at a time to minimize fragmentation. Rows are211* allocated on demand so that we don't waste too much space.212*/213214#define MAX_HASH_ENTRIES 65536215#define HASH_ROW_SIZE 256216217typedef struct hash_bucket_type {218char *name;219unsigned int hash;220jclass class;221unsigned short ID;222unsigned short next;223unsigned loadable:1; /* from context->class loader */224} hash_bucket_type;225226typedef struct {227hash_bucket_type **buckets;228unsigned short *table;229int entries_used;230} hash_table_type;231232#define GET_BUCKET(class_hash, ID)\233(class_hash->buckets[ID / HASH_ROW_SIZE] + ID % HASH_ROW_SIZE)234235/*236* There are currently two types of resources that we need to keep237* track of (in addition to the CCalloc pool).238*/239enum {240VM_STRING_UTF, /* VM-allocated UTF strings */241VM_MALLOC_BLK /* malloc'ed blocks */242};243244#define LDC_CLASS_MAJOR_VERSION 49245246#define LDC_METHOD_HANDLE_MAJOR_VERSION 51247248#define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION 51249250#define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION 52251252#define ALLOC_STACK_SIZE 16 /* big enough */253254typedef struct alloc_stack_type {255void *ptr;256int kind;257struct alloc_stack_type *next;258} alloc_stack_type;259260/* The context type encapsulates the current invocation of the byte261* code verifier.262*/263struct context_type {264265JNIEnv *env; /* current JNIEnv */266267/* buffers etc. */268char *message;269jint message_buf_len;270jboolean err_code;271272alloc_stack_type *allocated_memory; /* all memory blocks that we have not273had a chance to free */274/* Store up to ALLOC_STACK_SIZE number of handles to allocated memory275blocks here, to save mallocs. */276alloc_stack_type alloc_stack[ALLOC_STACK_SIZE];277int alloc_stack_top;278279/* these fields are per class */280jclass class; /* current class */281jint major_version;282jint nconstants;283unsigned char *constant_types;284hash_table_type class_hash;285286fullinfo_type object_info; /* fullinfo for java/lang/Object */287fullinfo_type string_info; /* fullinfo for java/lang/String */288fullinfo_type throwable_info; /* fullinfo for java/lang/Throwable */289fullinfo_type cloneable_info; /* fullinfo for java/lang/Cloneable */290fullinfo_type serializable_info; /* fullinfo for java/io/Serializable */291292fullinfo_type currentclass_info; /* fullinfo for context->class */293fullinfo_type superclass_info; /* fullinfo for superclass */294295/* these fields are per method */296int method_index; /* current method */297unsigned short *exceptions; /* exceptions */298unsigned char *code; /* current code object */299jint code_length;300int *code_data; /* offset to instruction number */301struct instruction_data_type *instruction_data; /* info about each */302struct handler_info_type *handler_info;303fullinfo_type *superclasses; /* null terminated superclasses */304int instruction_count; /* number of instructions */305fullinfo_type return_type; /* function return type */306fullinfo_type swap_table[4]; /* used for passing information */307int bitmask_size; /* words needed to hold bitmap of arguments */308309/* these fields are per field */310int field_index;311312/* Used by the space allocator */313struct CCpool *CCroot, *CCcurrent;314char *CCfree_ptr;315int CCfree_size;316317/* Jump here on any error. */318jmp_buf jump_buffer;319320#ifdef DEBUG321/* keep track of how many global refs are allocated. */322int n_globalrefs;323#endif324};325326struct stack_info_type {327struct stack_item_type *stack;328int stack_size;329};330331struct register_info_type {332int register_count; /* number of registers used */333fullinfo_type *registers;334int mask_count; /* number of masks in the following */335struct mask_type *masks;336};337338struct mask_type {339int entry;340int *modifies;341};342343typedef unsigned short flag_type;344345struct instruction_data_type {346int opcode; /* may turn into "canonical" opcode */347unsigned changed:1; /* has it changed */348unsigned protected:1; /* must accessor be a subclass of "this" */349union {350int i; /* operand to the opcode */351int *ip;352fullinfo_type fi;353} operand, operand2;354fullinfo_type p;355struct stack_info_type stack_info;356struct register_info_type register_info;357#define FLAG_REACHED 0x01 /* instruction reached */358#define FLAG_NEED_CONSTRUCTOR 0x02 /* must call this.<init> or super.<init> */359#define FLAG_NO_RETURN 0x04 /* must throw out of method */360flag_type or_flags; /* true for at least one path to this inst */361#define FLAG_CONSTRUCTED 0x01 /* this.<init> or super.<init> called */362flag_type and_flags; /* true for all paths to this instruction */363};364365struct handler_info_type {366int start, end, handler;367struct stack_info_type stack_info;368};369370struct stack_item_type {371fullinfo_type item;372struct stack_item_type *next;373};374375typedef struct context_type context_type;376typedef struct instruction_data_type instruction_data_type;377typedef struct stack_item_type stack_item_type;378typedef struct register_info_type register_info_type;379typedef struct stack_info_type stack_info_type;380typedef struct mask_type mask_type;381382static void read_all_code(context_type *context, jclass cb, int num_methods,383int** code_lengths, unsigned char*** code);384static void verify_method(context_type *context, jclass cb, int index,385int code_length, unsigned char* code);386static void free_all_code(context_type* context, int num_methods,387unsigned char** code);388static void verify_field(context_type *context, jclass cb, int index);389390static void verify_opcode_operands (context_type *, unsigned int inumber, int offset);391static void set_protected(context_type *, unsigned int inumber, int key, int);392static jboolean is_superclass(context_type *, fullinfo_type);393394static void initialize_exception_table(context_type *);395static int instruction_length(unsigned char *iptr, unsigned char *end);396static jboolean isLegalTarget(context_type *, int offset);397static void verify_constant_pool_type(context_type *, int, unsigned);398399static void initialize_dataflow(context_type *);400static void run_dataflow(context_type *context);401static void check_register_values(context_type *context, unsigned int inumber);402static void check_flags(context_type *context, unsigned int inumber);403static void pop_stack(context_type *, unsigned int inumber, stack_info_type *);404static void update_registers(context_type *, unsigned int inumber, register_info_type *);405static void update_flags(context_type *, unsigned int inumber,406flag_type *new_and_flags, flag_type *new_or_flags);407static void push_stack(context_type *, unsigned int inumber, stack_info_type *stack);408409static void merge_into_successors(context_type *, unsigned int inumber,410register_info_type *register_info,411stack_info_type *stack_info,412flag_type and_flags, flag_type or_flags);413static void merge_into_one_successor(context_type *context,414unsigned int from_inumber,415unsigned int inumber,416register_info_type *register_info,417stack_info_type *stack_info,418flag_type and_flags, flag_type or_flags,419jboolean isException);420static void merge_stack(context_type *, unsigned int inumber,421unsigned int to_inumber, stack_info_type *);422static void merge_registers(context_type *, unsigned int inumber,423unsigned int to_inumber,424register_info_type *);425static void merge_flags(context_type *context, unsigned int from_inumber,426unsigned int to_inumber,427flag_type new_and_flags, flag_type new_or_flags);428429static stack_item_type *copy_stack(context_type *, stack_item_type *);430static mask_type *copy_masks(context_type *, mask_type *masks, int mask_count);431static mask_type *add_to_masks(context_type *, mask_type *, int , int);432433static fullinfo_type decrement_indirection(fullinfo_type);434435static fullinfo_type merge_fullinfo_types(context_type *context,436fullinfo_type a,437fullinfo_type b,438jboolean assignment);439static jboolean isAssignableTo(context_type *,440fullinfo_type a,441fullinfo_type b);442443static jclass object_fullinfo_to_classclass(context_type *, fullinfo_type);444445446#define NEW(type, count) \447((type *)CCalloc(context, (count)*(sizeof(type)), JNI_FALSE))448#define ZNEW(type, count) \449((type *)CCalloc(context, (count)*(sizeof(type)), JNI_TRUE))450451static void CCinit(context_type *context);452static void CCreinit(context_type *context);453static void CCdestroy(context_type *context);454static void *CCalloc(context_type *context, int size, jboolean zero);455456static fullinfo_type cp_index_to_class_fullinfo(context_type *, int, int);457458static const char* get_result_signature(const char* signature);459460static char signature_to_fieldtype(context_type *context,461const char **signature_p, fullinfo_type *info);462463static void CCerror (context_type *, char *format, ...);464static void CFerror (context_type *, char *format, ...);465static void CCout_of_memory (context_type *);466467/* Because we can longjmp any time, we need to be very careful about468* remembering what needs to be freed. */469470static void check_and_push(context_type *context, const void *ptr, int kind);471static void pop_and_free(context_type *context);472473static int signature_to_args_size(const char *method_signature);474475#ifdef DEBUG476static void print_stack (context_type *, stack_info_type *stack_info);477static void print_registers(context_type *, register_info_type *register_info);478static void print_flags(context_type *, flag_type, flag_type);479static void print_formatted_fieldname(context_type *context, int index);480static void print_formatted_methodname(context_type *context, int index);481#endif482483/*484* Declare library specific JNI_Onload entry if static build485*/486DEF_STATIC_JNI_OnLoad487488void initialize_class_hash(context_type *context)489{490hash_table_type *class_hash = &(context->class_hash);491class_hash->buckets = (hash_bucket_type **)492calloc(MAX_HASH_ENTRIES / HASH_ROW_SIZE, sizeof(hash_bucket_type *));493class_hash->table = (unsigned short *)494calloc(HASH_TABLE_SIZE, sizeof(unsigned short));495if (class_hash->buckets == 0 ||496class_hash->table == 0)497CCout_of_memory(context);498class_hash->entries_used = 0;499}500501static void finalize_class_hash(context_type *context)502{503hash_table_type *class_hash = &(context->class_hash);504JNIEnv *env = context->env;505int i;506/* 4296677: bucket index starts from 1. */507for (i=1;i<=class_hash->entries_used;i++) {508hash_bucket_type *bucket = GET_BUCKET(class_hash, i);509assert(bucket != NULL);510free(bucket->name);511if (bucket->class) {512(*env)->DeleteGlobalRef(env, bucket->class);513#ifdef DEBUG514context->n_globalrefs--;515#endif516}517}518if (class_hash->buckets) {519for (i=0;i<MAX_HASH_ENTRIES / HASH_ROW_SIZE; i++) {520if (class_hash->buckets[i] == 0)521break;522free(class_hash->buckets[i]);523}524}525free(class_hash->buckets);526free(class_hash->table);527}528529static hash_bucket_type *530new_bucket(context_type *context, unsigned short *pID)531{532hash_table_type *class_hash = &(context->class_hash);533int i = *pID = class_hash->entries_used + 1;534int row = i / HASH_ROW_SIZE;535if (i >= MAX_HASH_ENTRIES)536CCerror(context, "Exceeded verifier's limit of 65535 referred classes");537if (class_hash->buckets[row] == 0) {538class_hash->buckets[row] = (hash_bucket_type*)539calloc(HASH_ROW_SIZE, sizeof(hash_bucket_type));540if (class_hash->buckets[row] == 0)541CCout_of_memory(context);542}543class_hash->entries_used++; /* only increment when we are sure there544is no overflow. */545return GET_BUCKET(class_hash, i);546}547548static unsigned int549class_hash_fun(const char *s)550{551int i;552unsigned raw_hash;553for (raw_hash = 0; (i = *s) != '\0'; ++s)554raw_hash = raw_hash * 37 + i;555return raw_hash;556}557558/*559* Find a class using the defining loader of the current class560* and return a local reference to it.561*/562static jclass load_class_local(context_type *context,const char *classname)563{564jclass cb = JVM_FindClassFromClass(context->env, classname,565JNI_FALSE, context->class);566if (cb == 0)567CCerror(context, "Cannot find class %s", classname);568return cb;569}570571/*572* Find a class using the defining loader of the current class573* and return a global reference to it.574*/575static jclass load_class_global(context_type *context, const char *classname)576{577JNIEnv *env = context->env;578jclass local, global;579580local = load_class_local(context, classname);581global = (*env)->NewGlobalRef(env, local);582if (global == 0)583CCout_of_memory(context);584#ifdef DEBUG585context->n_globalrefs++;586#endif587(*env)->DeleteLocalRef(env, local);588return global;589}590591/*592* Return a unique ID given a local class reference. The loadable593* flag is true if the defining class loader of context->class594* is known to be capable of loading the class.595*/596static unsigned short597class_to_ID(context_type *context, jclass cb, jboolean loadable)598{599JNIEnv *env = context->env;600hash_table_type *class_hash = &(context->class_hash);601unsigned int hash;602hash_bucket_type *bucket;603unsigned short *pID;604const char *name = JVM_GetClassNameUTF(env, cb);605606check_and_push(context, name, VM_STRING_UTF);607hash = class_hash_fun(name);608pID = &(class_hash->table[hash % HASH_TABLE_SIZE]);609while (*pID) {610bucket = GET_BUCKET(class_hash, *pID);611if (bucket->hash == hash && strcmp(name, bucket->name) == 0) {612/*613* There is an unresolved entry with our name614* so we're forced to load it in case it matches us.615*/616if (bucket->class == 0) {617assert(bucket->loadable == JNI_TRUE);618bucket->class = load_class_global(context, name);619}620621/*622* It's already in the table. Update the loadable623* state if it's known and then we're done.624*/625if ((*env)->IsSameObject(env, cb, bucket->class)) {626if (loadable && !bucket->loadable)627bucket->loadable = JNI_TRUE;628goto done;629}630}631pID = &bucket->next;632}633bucket = new_bucket(context, pID);634bucket->next = 0;635bucket->hash = hash;636bucket->name = malloc(strlen(name) + 1);637if (bucket->name == 0)638CCout_of_memory(context);639strcpy(bucket->name, name);640bucket->loadable = loadable;641bucket->class = (*env)->NewGlobalRef(env, cb);642if (bucket->class == 0)643CCout_of_memory(context);644#ifdef DEBUG645context->n_globalrefs++;646#endif647648done:649pop_and_free(context);650return *pID;651}652653/*654* Return a unique ID given a class name from the constant pool.655* All classes are lazily loaded from the defining loader of656* context->class.657*/658static unsigned short659class_name_to_ID(context_type *context, const char *name)660{661hash_table_type *class_hash = &(context->class_hash);662unsigned int hash = class_hash_fun(name);663hash_bucket_type *bucket;664unsigned short *pID;665jboolean force_load = JNI_FALSE;666667pID = &(class_hash->table[hash % HASH_TABLE_SIZE]);668while (*pID) {669bucket = GET_BUCKET(class_hash, *pID);670if (bucket->hash == hash && strcmp(name, bucket->name) == 0) {671if (bucket->loadable)672goto done;673force_load = JNI_TRUE;674}675pID = &bucket->next;676}677678if (force_load) {679/*680* We found at least one matching named entry for a class that681* was not known to be loadable through the defining class loader682* of context->class. We must load our named class and update683* the hash table in case one these entries matches our class.684*/685JNIEnv *env = context->env;686jclass cb = load_class_local(context, name);687unsigned short id = class_to_ID(context, cb, JNI_TRUE);688(*env)->DeleteLocalRef(env, cb);689return id;690}691692bucket = new_bucket(context, pID);693bucket->next = 0;694bucket->class = 0;695bucket->loadable = JNI_TRUE; /* name-only IDs are implicitly loadable */696bucket->hash = hash;697bucket->name = malloc(strlen(name) + 1);698if (bucket->name == 0)699CCout_of_memory(context);700strcpy(bucket->name, name);701702done:703return *pID;704}705706#ifdef DEBUG707static const char *708ID_to_class_name(context_type *context, unsigned short ID)709{710hash_table_type *class_hash = &(context->class_hash);711hash_bucket_type *bucket = GET_BUCKET(class_hash, ID);712return bucket->name;713}714#endif715716static jclass717ID_to_class(context_type *context, unsigned short ID)718{719hash_table_type *class_hash = &(context->class_hash);720hash_bucket_type *bucket = GET_BUCKET(class_hash, ID);721if (bucket->class == 0) {722assert(bucket->loadable == JNI_TRUE);723bucket->class = load_class_global(context, bucket->name);724}725return bucket->class;726}727728static fullinfo_type729make_loadable_class_info(context_type *context, jclass cb)730{731return MAKE_FULLINFO(ITEM_Object, 0,732class_to_ID(context, cb, JNI_TRUE));733}734735static fullinfo_type736make_class_info(context_type *context, jclass cb)737{738return MAKE_FULLINFO(ITEM_Object, 0,739class_to_ID(context, cb, JNI_FALSE));740}741742static fullinfo_type743make_class_info_from_name(context_type *context, const char *name)744{745return MAKE_FULLINFO(ITEM_Object, 0,746class_name_to_ID(context, name));747}748749/* RETURNS750* 1: on success chosen to be consistent with previous VerifyClass751* 0: verify error752* 2: out of memory753* 3: class format error754*755* Called by verify_class. Verify the code of each of the methods756* in a class. Note that this function apparently can't be JNICALL,757* because if it is the dynamic linker doesn't appear to be able to758* find it on Win32.759*/760761#define CC_OK 1762#define CC_VerifyError 0763#define CC_OutOfMemory 2764#define CC_ClassFormatError 3765766JNIEXPORT jboolean767VerifyClassForMajorVersion(JNIEnv *env, jclass cb, char *buffer, jint len,768jint major_version)769{770context_type context_structure;771context_type *context = &context_structure;772jboolean result = CC_OK;773int i;774int num_methods;775int* code_lengths;776unsigned char** code;777778#ifdef DEBUG779GlobalContext = context;780#endif781782memset(context, 0, sizeof(context_type));783context->message = buffer;784context->message_buf_len = len;785786context->env = env;787context->class = cb;788789/* Set invalid method/field index of the context, in case anyone790calls CCerror */791context->method_index = -1;792context->field_index = -1;793794/* Don't call CCerror or anything that can call it above the setjmp! */795if (!setjmp(context->jump_buffer)) {796jclass super;797798CCinit(context); /* initialize heap; may throw */799800initialize_class_hash(context);801802context->major_version = major_version;803context->nconstants = JVM_GetClassCPEntriesCount(env, cb);804context->constant_types = (unsigned char *)805malloc(sizeof(unsigned char) * context->nconstants + 1);806807if (context->constant_types == 0)808CCout_of_memory(context);809810JVM_GetClassCPTypes(env, cb, context->constant_types);811812if (context->constant_types == 0)813CCout_of_memory(context);814815context->object_info =816make_class_info_from_name(context, "java/lang/Object");817context->string_info =818make_class_info_from_name(context, "java/lang/String");819context->throwable_info =820make_class_info_from_name(context, "java/lang/Throwable");821context->cloneable_info =822make_class_info_from_name(context, "java/lang/Cloneable");823context->serializable_info =824make_class_info_from_name(context, "java/io/Serializable");825826context->currentclass_info = make_loadable_class_info(context, cb);827828super = (*env)->GetSuperclass(env, cb);829830if (super != 0) {831fullinfo_type *gptr;832int i = 0;833834context->superclass_info = make_loadable_class_info(context, super);835836while(super != 0) {837jclass tmp_cb = (*env)->GetSuperclass(env, super);838(*env)->DeleteLocalRef(env, super);839super = tmp_cb;840i++;841}842(*env)->DeleteLocalRef(env, super);843super = 0;844845/* Can't go on context heap since it survives more than846one method */847context->superclasses = gptr =848malloc(sizeof(fullinfo_type)*(i + 1));849if (gptr == 0) {850CCout_of_memory(context);851}852853super = (*env)->GetSuperclass(env, context->class);854while(super != 0) {855jclass tmp_cb;856*gptr++ = make_class_info(context, super);857tmp_cb = (*env)->GetSuperclass(env, super);858(*env)->DeleteLocalRef(env, super);859super = tmp_cb;860}861*gptr = 0;862} else {863context->superclass_info = 0;864}865866(*env)->DeleteLocalRef(env, super);867868/* Look at each method */869for (i = JVM_GetClassFieldsCount(env, cb); --i >= 0;)870verify_field(context, cb, i);871num_methods = JVM_GetClassMethodsCount(env, cb);872read_all_code(context, cb, num_methods, &code_lengths, &code);873for (i = num_methods - 1; i >= 0; --i)874verify_method(context, cb, i, code_lengths[i], code[i]);875free_all_code(context, num_methods, code);876result = CC_OK;877} else {878result = context->err_code;879}880881/* Cleanup */882finalize_class_hash(context);883884while(context->allocated_memory)885pop_and_free(context);886887#ifdef DEBUG888GlobalContext = 0;889#endif890891if (context->exceptions)892free(context->exceptions);893894if (context->constant_types)895free(context->constant_types);896897if (context->superclasses)898free(context->superclasses);899900#ifdef DEBUG901/* Make sure all global refs created in the verifier are freed */902assert(context->n_globalrefs == 0);903#endif904905CCdestroy(context); /* destroy heap */906return result;907}908909static void910verify_field(context_type *context, jclass cb, int field_index)911{912JNIEnv *env = context->env;913int access_bits = JVM_GetFieldIxModifiers(env, cb, field_index);914context->field_index = field_index;915916if ( ((access_bits & JVM_ACC_PUBLIC) != 0) &&917((access_bits & (JVM_ACC_PRIVATE | JVM_ACC_PROTECTED)) != 0)) {918CCerror(context, "Inconsistent access bits.");919}920context->field_index = -1;921}922923924/**925* We read all of the class's methods' code because it is possible that926* the verification of one method could resulting in linking further927* down the stack (due to class loading), which could end up rewriting928* some of the bytecode of methods we haven't verified yet. Since we929* don't want to see the rewritten bytecode, cache all the code and930* operate only on that.931*/932static void933read_all_code(context_type* context, jclass cb, int num_methods,934int** lengths_addr, unsigned char*** code_addr)935{936int* lengths;937unsigned char** code;938int i;939940lengths = malloc(sizeof(int) * num_methods);941check_and_push(context, lengths, VM_MALLOC_BLK);942943code = malloc(sizeof(unsigned char*) * num_methods);944check_and_push(context, code, VM_MALLOC_BLK);945946*(lengths_addr) = lengths;947*(code_addr) = code;948949for (i = 0; i < num_methods; ++i) {950lengths[i] = JVM_GetMethodIxByteCodeLength(context->env, cb, i);951if (lengths[i] > 0) {952code[i] = malloc(sizeof(unsigned char) * (lengths[i] + 1));953check_and_push(context, code[i], VM_MALLOC_BLK);954JVM_GetMethodIxByteCode(context->env, cb, i, code[i]);955} else {956code[i] = NULL;957}958}959}960961static void962free_all_code(context_type* context, int num_methods, unsigned char** code)963{964int i;965for (i = 0; i < num_methods; ++i) {966if (code[i] != NULL) {967pop_and_free(context);968}969}970pop_and_free(context); /* code */971pop_and_free(context); /* lengths */972}973974/* Verify the code of one method */975static void976verify_method(context_type *context, jclass cb, int method_index,977int code_length, unsigned char* code)978{979JNIEnv *env = context->env;980int access_bits = JVM_GetMethodIxModifiers(env, cb, method_index);981int *code_data;982instruction_data_type *idata = 0;983int instruction_count;984int i, offset;985unsigned int inumber;986jint nexceptions;987988if ((access_bits & (JVM_ACC_NATIVE | JVM_ACC_ABSTRACT)) != 0) {989/* not much to do for abstract and native methods */990return;991}992993context->code_length = code_length;994context->code = code;995996/* CCerror can give method-specific info once this is set */997context->method_index = method_index;998999CCreinit(context); /* initial heap */1000code_data = NEW(int, code_length);10011002#ifdef DEBUG1003if (verify_verbose) {1004const char *classname = JVM_GetClassNameUTF(env, cb);1005const char *methodname =1006JVM_GetMethodIxNameUTF(env, cb, method_index);1007const char *signature =1008JVM_GetMethodIxSignatureUTF(env, cb, method_index);1009jio_fprintf(stdout, "Looking at %s.%s%s\n",1010(classname ? classname : ""),1011(methodname ? methodname : ""),1012(signature ? signature : ""));1013JVM_ReleaseUTF(classname);1014JVM_ReleaseUTF(methodname);1015JVM_ReleaseUTF(signature);1016}1017#endif10181019if (((access_bits & JVM_ACC_PUBLIC) != 0) &&1020((access_bits & (JVM_ACC_PRIVATE | JVM_ACC_PROTECTED)) != 0)) {1021CCerror(context, "Inconsistent access bits.");1022}10231024// If this method is an overpass method, which is generated by the VM,1025// we trust the code and no check needs to be done.1026if (JVM_IsVMGeneratedMethodIx(env, cb, method_index)) {1027return;1028}10291030/* Run through the code. Mark the start of each instruction, and give1031* the instruction a number */1032for (i = 0, offset = 0; offset < code_length; i++) {1033int length = instruction_length(&code[offset], code + code_length);1034int next_offset = offset + length;1035if (length <= 0)1036CCerror(context, "Illegal instruction found at offset %d", offset);1037if (next_offset > code_length)1038CCerror(context, "Code stops in the middle of instruction "1039" starting at offset %d", offset);1040code_data[offset] = i;1041while (++offset < next_offset)1042code_data[offset] = -1; /* illegal location */1043}1044instruction_count = i; /* number of instructions in code */10451046/* Allocate a structure to hold info about each instruction. */1047idata = NEW(instruction_data_type, instruction_count);10481049/* Initialize the heap, and other info in the context structure. */1050context->code = code;1051context->instruction_data = idata;1052context->code_data = code_data;1053context->instruction_count = instruction_count;1054context->handler_info =1055NEW(struct handler_info_type,1056JVM_GetMethodIxExceptionTableLength(env, cb, method_index));1057context->bitmask_size =1058(JVM_GetMethodIxLocalsCount(env, cb, method_index)1059+ (BITS_PER_INT - 1))/BITS_PER_INT;10601061if (instruction_count == 0)1062CCerror(context, "Empty code");10631064for (inumber = 0, offset = 0; offset < code_length; inumber++) {1065int length = instruction_length(&code[offset], code + code_length);1066instruction_data_type *this_idata = &idata[inumber];1067this_idata->opcode = code[offset];1068this_idata->stack_info.stack = NULL;1069this_idata->stack_info.stack_size = UNKNOWN_STACK_SIZE;1070this_idata->register_info.register_count = UNKNOWN_REGISTER_COUNT;1071this_idata->changed = JNI_FALSE; /* no need to look at it yet. */1072this_idata->protected = JNI_FALSE; /* no need to look at it yet. */1073this_idata->and_flags = (flag_type) -1; /* "bottom" and value */1074this_idata->or_flags = 0; /* "bottom" or value*/1075/* This also sets up this_data->operand. It also makes the1076* xload_x and xstore_x instructions look like the generic form. */1077verify_opcode_operands(context, inumber, offset);1078offset += length;1079}108010811082/* make sure exception table is reasonable. */1083initialize_exception_table(context);1084/* Set up first instruction, and start of exception handlers. */1085initialize_dataflow(context);1086/* Run data flow analysis on the instructions. */1087run_dataflow(context);10881089/* verify checked exceptions, if any */1090nexceptions = JVM_GetMethodIxExceptionsCount(env, cb, method_index);1091context->exceptions = (unsigned short *)1092malloc(sizeof(unsigned short) * nexceptions + 1);1093if (context->exceptions == 0)1094CCout_of_memory(context);1095JVM_GetMethodIxExceptionIndexes(env, cb, method_index,1096context->exceptions);1097for (i = 0; i < nexceptions; i++) {1098/* Make sure the constant pool item is JVM_CONSTANT_Class */1099verify_constant_pool_type(context, (int)context->exceptions[i],11001 << JVM_CONSTANT_Class);1101}1102free(context->exceptions);1103context->exceptions = 0;1104context->code = 0;1105context->method_index = -1;1106}110711081109/* Look at a single instruction, and verify its operands. Also, for1110* simplicity, move the operand into the ->operand field.1111* Make sure that branches don't go into the middle of nowhere.1112*/11131114static jint _ck_ntohl(jint n)1115{1116unsigned char *p = (unsigned char *)&n;1117return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];1118}11191120static void1121verify_opcode_operands(context_type *context, unsigned int inumber, int offset)1122{1123JNIEnv *env = context->env;1124instruction_data_type *idata = context->instruction_data;1125instruction_data_type *this_idata = &idata[inumber];1126int *code_data = context->code_data;1127int mi = context->method_index;1128unsigned char *code = context->code;1129int opcode = this_idata->opcode;1130int var;11311132/*1133* Set the ip fields to 0 not the i fields because the ip fields1134* are 64 bits on 64 bit architectures, the i field is only 321135*/1136this_idata->operand.ip = 0;1137this_idata->operand2.ip = 0;11381139switch (opcode) {11401141case JVM_OPC_jsr:1142/* instruction of ret statement */1143this_idata->operand2.i = UNKNOWN_RET_INSTRUCTION;1144/* FALLTHROUGH */1145case JVM_OPC_ifeq: case JVM_OPC_ifne: case JVM_OPC_iflt:1146case JVM_OPC_ifge: case JVM_OPC_ifgt: case JVM_OPC_ifle:1147case JVM_OPC_ifnull: case JVM_OPC_ifnonnull:1148case JVM_OPC_if_icmpeq: case JVM_OPC_if_icmpne: case JVM_OPC_if_icmplt:1149case JVM_OPC_if_icmpge: case JVM_OPC_if_icmpgt: case JVM_OPC_if_icmple:1150case JVM_OPC_if_acmpeq: case JVM_OPC_if_acmpne:1151case JVM_OPC_goto: {1152/* Set the ->operand to be the instruction number of the target. */1153int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2];1154int target = offset + jump;1155if (!isLegalTarget(context, target))1156CCerror(context, "Illegal target of jump or branch");1157this_idata->operand.i = code_data[target];1158break;1159}11601161case JVM_OPC_jsr_w:1162/* instruction of ret statement */1163this_idata->operand2.i = UNKNOWN_RET_INSTRUCTION;1164/* FALLTHROUGH */1165case JVM_OPC_goto_w: {1166/* Set the ->operand to be the instruction number of the target. */1167int jump = (((signed char)(code[offset+1])) << 24) +1168(code[offset+2] << 16) + (code[offset+3] << 8) +1169(code[offset + 4]);1170int target = offset + jump;1171if (!isLegalTarget(context, target))1172CCerror(context, "Illegal target of jump or branch");1173this_idata->operand.i = code_data[target];1174break;1175}11761177case JVM_OPC_tableswitch:1178case JVM_OPC_lookupswitch: {1179/* Set the ->operand to be a table of possible instruction targets. */1180int *lpc = (int *) UCALIGN(code + offset + 1);1181int *lptr;1182int *saved_operand;1183int keys;1184int k, delta;11851186if (context->major_version < NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION) {1187/* 4639449, 4647081: Padding bytes must be zero. */1188unsigned char* bptr = (unsigned char*) (code + offset + 1);1189for (; bptr < (unsigned char*)lpc; bptr++) {1190if (*bptr != 0) {1191CCerror(context, "Non zero padding bytes in switch");1192}1193}1194}1195if (opcode == JVM_OPC_tableswitch) {1196keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1;1197delta = 1;1198} else {1199keys = _ck_ntohl(lpc[1]); /* number of pairs */1200delta = 2;1201/* Make sure that the tableswitch items are sorted */1202for (k = keys - 1, lptr = &lpc[2]; --k >= 0; lptr += 2) {1203int this_key = _ck_ntohl(lptr[0]); /* NB: ntohl may be unsigned */1204int next_key = _ck_ntohl(lptr[2]);1205if (this_key >= next_key) {1206CCerror(context, "Unsorted lookup switch");1207}1208}1209}1210saved_operand = NEW(int, keys + 2);1211if (!isLegalTarget(context, offset + _ck_ntohl(lpc[0])))1212CCerror(context, "Illegal default target in switch");1213saved_operand[keys + 1] = code_data[offset + _ck_ntohl(lpc[0])];1214for (k = keys, lptr = &lpc[3]; --k >= 0; lptr += delta) {1215int target = offset + _ck_ntohl(lptr[0]);1216if (!isLegalTarget(context, target))1217CCerror(context, "Illegal branch in tableswitch");1218saved_operand[k + 1] = code_data[target];1219}1220saved_operand[0] = keys + 1; /* number of successors */1221this_idata->operand.ip = saved_operand;1222break;1223}12241225case JVM_OPC_ldc: {1226/* Make sure the constant pool item is the right type. */1227int key = code[offset + 1];1228int types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) |1229(1 << JVM_CONSTANT_String);1230if (context->major_version >= LDC_CLASS_MAJOR_VERSION) {1231types |= 1 << JVM_CONSTANT_Class;1232}1233if (context->major_version >= LDC_METHOD_HANDLE_MAJOR_VERSION) {1234types |= (1 << JVM_CONSTANT_MethodHandle) |1235(1 << JVM_CONSTANT_MethodType);1236}1237this_idata->operand.i = key;1238verify_constant_pool_type(context, key, types);1239break;1240}12411242case JVM_OPC_ldc_w: {1243/* Make sure the constant pool item is the right type. */1244int key = (code[offset + 1] << 8) + code[offset + 2];1245int types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) |1246(1 << JVM_CONSTANT_String);1247if (context->major_version >= LDC_CLASS_MAJOR_VERSION) {1248types |= 1 << JVM_CONSTANT_Class;1249}1250if (context->major_version >= LDC_METHOD_HANDLE_MAJOR_VERSION) {1251types |= (1 << JVM_CONSTANT_MethodHandle) |1252(1 << JVM_CONSTANT_MethodType);1253}1254this_idata->operand.i = key;1255verify_constant_pool_type(context, key, types);1256break;1257}12581259case JVM_OPC_ldc2_w: {1260/* Make sure the constant pool item is the right type. */1261int key = (code[offset + 1] << 8) + code[offset + 2];1262int types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long);1263this_idata->operand.i = key;1264verify_constant_pool_type(context, key, types);1265break;1266}12671268case JVM_OPC_getfield: case JVM_OPC_putfield:1269case JVM_OPC_getstatic: case JVM_OPC_putstatic: {1270/* Make sure the constant pool item is the right type. */1271int key = (code[offset + 1] << 8) + code[offset + 2];1272this_idata->operand.i = key;1273verify_constant_pool_type(context, key, 1 << JVM_CONSTANT_Fieldref);1274if (opcode == JVM_OPC_getfield || opcode == JVM_OPC_putfield)1275set_protected(context, inumber, key, opcode);1276break;1277}12781279case JVM_OPC_invokevirtual:1280case JVM_OPC_invokespecial:1281case JVM_OPC_invokestatic:1282case JVM_OPC_invokeinterface: {1283/* Make sure the constant pool item is the right type. */1284int key = (code[offset + 1] << 8) + code[offset + 2];1285const char *methodname;1286jclass cb = context->class;1287fullinfo_type clazz_info;1288int is_constructor, is_internal;1289int kind;12901291switch (opcode ) {1292case JVM_OPC_invokestatic:1293kind = ((context->major_version < STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION)1294? (1 << JVM_CONSTANT_Methodref)1295: ((1 << JVM_CONSTANT_InterfaceMethodref) | (1 << JVM_CONSTANT_Methodref)));1296break;1297case JVM_OPC_invokeinterface:1298kind = 1 << JVM_CONSTANT_InterfaceMethodref;1299break;1300default:1301kind = 1 << JVM_CONSTANT_Methodref;1302}13031304/* Make sure the constant pool item is the right type. */1305verify_constant_pool_type(context, key, kind);1306methodname = JVM_GetCPMethodNameUTF(env, cb, key);1307check_and_push(context, methodname, VM_STRING_UTF);1308is_constructor = !strcmp(methodname, "<init>");1309is_internal = methodname[0] == '<';1310pop_and_free(context);13111312clazz_info = cp_index_to_class_fullinfo(context, key,1313JVM_CONSTANT_Methodref);1314this_idata->operand.i = key;1315this_idata->operand2.fi = clazz_info;1316if (is_constructor) {1317if (opcode != JVM_OPC_invokespecial) {1318CCerror(context,1319"Must call initializers using invokespecial");1320}1321this_idata->opcode = JVM_OPC_invokeinit;1322} else {1323if (is_internal) {1324CCerror(context, "Illegal call to internal method");1325}1326if (opcode == JVM_OPC_invokespecial1327&& clazz_info != context->currentclass_info1328&& clazz_info != context->superclass_info) {1329int not_found = 1;13301331jclass super = (*env)->GetSuperclass(env, context->class);1332while(super != 0) {1333jclass tmp_cb;1334fullinfo_type new_info = make_class_info(context, super);1335if (clazz_info == new_info) {1336not_found = 0;1337break;1338}1339tmp_cb = (*env)->GetSuperclass(env, super);1340(*env)->DeleteLocalRef(env, super);1341super = tmp_cb;1342}1343(*env)->DeleteLocalRef(env, super);13441345/* The optimizer may cause this to happen on local code */1346if (not_found) {1347CCerror(context, "Illegal use of nonvirtual function call");1348}1349}1350}1351if (opcode == JVM_OPC_invokeinterface) {1352unsigned int args1;1353unsigned int args2;1354const char *signature =1355JVM_GetCPMethodSignatureUTF(env, context->class, key);1356check_and_push(context, signature, VM_STRING_UTF);1357args1 = signature_to_args_size(signature) + 1;1358args2 = code[offset + 3];1359if (args1 != args2) {1360CCerror(context,1361"Inconsistent args_size for invokeinterface");1362}1363if (code[offset + 4] != 0) {1364CCerror(context,1365"Fourth operand byte of invokeinterface must be zero");1366}1367pop_and_free(context);1368} else if (opcode == JVM_OPC_invokevirtual1369|| opcode == JVM_OPC_invokespecial)1370set_protected(context, inumber, key, opcode);1371break;1372}13731374case JVM_OPC_invokedynamic:1375CCerror(context,1376"invokedynamic bytecode is not supported in this class file version");1377break;1378case JVM_OPC_instanceof:1379case JVM_OPC_checkcast:1380case JVM_OPC_new:1381case JVM_OPC_anewarray:1382case JVM_OPC_multianewarray: {1383/* Make sure the constant pool item is a class */1384int key = (code[offset + 1] << 8) + code[offset + 2];1385fullinfo_type target;1386verify_constant_pool_type(context, key, 1 << JVM_CONSTANT_Class);1387target = cp_index_to_class_fullinfo(context, key, JVM_CONSTANT_Class);1388if (GET_ITEM_TYPE(target) == ITEM_Bogus)1389CCerror(context, "Illegal type");1390switch(opcode) {1391case JVM_OPC_anewarray:1392if ((GET_INDIRECTION(target)) >= MAX_ARRAY_DIMENSIONS)1393CCerror(context, "Array with too many dimensions");1394this_idata->operand.fi = MAKE_FULLINFO(GET_ITEM_TYPE(target),1395GET_INDIRECTION(target) + 1,1396GET_EXTRA_INFO(target));1397break;1398case JVM_OPC_new:1399if (WITH_ZERO_EXTRA_INFO(target) !=1400MAKE_FULLINFO(ITEM_Object, 0, 0))1401CCerror(context, "Illegal creation of multi-dimensional array");1402/* operand gets set to the "unitialized object". operand2 gets1403* set to what the value will be after it's initialized. */1404this_idata->operand.fi = MAKE_FULLINFO(ITEM_NewObject, 0, inumber);1405this_idata->operand2.fi = target;1406break;1407case JVM_OPC_multianewarray:1408this_idata->operand.fi = target;1409this_idata->operand2.i = code[offset + 3];1410if ( (this_idata->operand2.i > (int)GET_INDIRECTION(target))1411|| (this_idata->operand2.i == 0))1412CCerror(context, "Illegal dimension argument");1413break;1414default:1415this_idata->operand.fi = target;1416}1417break;1418}14191420case JVM_OPC_newarray: {1421/* Cache the result of the JVM_OPC_newarray into the operand slot */1422fullinfo_type full_info;1423switch (code[offset + 1]) {1424case JVM_T_INT:1425full_info = MAKE_FULLINFO(ITEM_Integer, 1, 0); break;1426case JVM_T_LONG:1427full_info = MAKE_FULLINFO(ITEM_Long, 1, 0); break;1428case JVM_T_FLOAT:1429full_info = MAKE_FULLINFO(ITEM_Float, 1, 0); break;1430case JVM_T_DOUBLE:1431full_info = MAKE_FULLINFO(ITEM_Double, 1, 0); break;1432case JVM_T_BOOLEAN:1433full_info = MAKE_FULLINFO(ITEM_Boolean, 1, 0); break;1434case JVM_T_BYTE:1435full_info = MAKE_FULLINFO(ITEM_Byte, 1, 0); break;1436case JVM_T_CHAR:1437full_info = MAKE_FULLINFO(ITEM_Char, 1, 0); break;1438case JVM_T_SHORT:1439full_info = MAKE_FULLINFO(ITEM_Short, 1, 0); break;1440default:1441full_info = 0; /* Keep lint happy */1442CCerror(context, "Bad type passed to newarray");1443}1444this_idata->operand.fi = full_info;1445break;1446}14471448/* Fudge iload_x, aload_x, etc to look like their generic cousin. */1449case JVM_OPC_iload_0: case JVM_OPC_iload_1: case JVM_OPC_iload_2: case JVM_OPC_iload_3:1450this_idata->opcode = JVM_OPC_iload;1451var = opcode - JVM_OPC_iload_0;1452goto check_local_variable;14531454case JVM_OPC_fload_0: case JVM_OPC_fload_1: case JVM_OPC_fload_2: case JVM_OPC_fload_3:1455this_idata->opcode = JVM_OPC_fload;1456var = opcode - JVM_OPC_fload_0;1457goto check_local_variable;14581459case JVM_OPC_aload_0: case JVM_OPC_aload_1: case JVM_OPC_aload_2: case JVM_OPC_aload_3:1460this_idata->opcode = JVM_OPC_aload;1461var = opcode - JVM_OPC_aload_0;1462goto check_local_variable;14631464case JVM_OPC_lload_0: case JVM_OPC_lload_1: case JVM_OPC_lload_2: case JVM_OPC_lload_3:1465this_idata->opcode = JVM_OPC_lload;1466var = opcode - JVM_OPC_lload_0;1467goto check_local_variable2;14681469case JVM_OPC_dload_0: case JVM_OPC_dload_1: case JVM_OPC_dload_2: case JVM_OPC_dload_3:1470this_idata->opcode = JVM_OPC_dload;1471var = opcode - JVM_OPC_dload_0;1472goto check_local_variable2;14731474case JVM_OPC_istore_0: case JVM_OPC_istore_1: case JVM_OPC_istore_2: case JVM_OPC_istore_3:1475this_idata->opcode = JVM_OPC_istore;1476var = opcode - JVM_OPC_istore_0;1477goto check_local_variable;14781479case JVM_OPC_fstore_0: case JVM_OPC_fstore_1: case JVM_OPC_fstore_2: case JVM_OPC_fstore_3:1480this_idata->opcode = JVM_OPC_fstore;1481var = opcode - JVM_OPC_fstore_0;1482goto check_local_variable;14831484case JVM_OPC_astore_0: case JVM_OPC_astore_1: case JVM_OPC_astore_2: case JVM_OPC_astore_3:1485this_idata->opcode = JVM_OPC_astore;1486var = opcode - JVM_OPC_astore_0;1487goto check_local_variable;14881489case JVM_OPC_lstore_0: case JVM_OPC_lstore_1: case JVM_OPC_lstore_2: case JVM_OPC_lstore_3:1490this_idata->opcode = JVM_OPC_lstore;1491var = opcode - JVM_OPC_lstore_0;1492goto check_local_variable2;14931494case JVM_OPC_dstore_0: case JVM_OPC_dstore_1: case JVM_OPC_dstore_2: case JVM_OPC_dstore_3:1495this_idata->opcode = JVM_OPC_dstore;1496var = opcode - JVM_OPC_dstore_0;1497goto check_local_variable2;14981499case JVM_OPC_wide:1500this_idata->opcode = code[offset + 1];1501var = (code[offset + 2] << 8) + code[offset + 3];1502switch(this_idata->opcode) {1503case JVM_OPC_lload: case JVM_OPC_dload:1504case JVM_OPC_lstore: case JVM_OPC_dstore:1505goto check_local_variable2;1506default:1507goto check_local_variable;1508}15091510case JVM_OPC_iinc: /* the increment amount doesn't matter */1511case JVM_OPC_ret:1512case JVM_OPC_aload: case JVM_OPC_iload: case JVM_OPC_fload:1513case JVM_OPC_astore: case JVM_OPC_istore: case JVM_OPC_fstore:1514var = code[offset + 1];1515check_local_variable:1516/* Make sure that the variable number isn't illegal. */1517this_idata->operand.i = var;1518if (var >= JVM_GetMethodIxLocalsCount(env, context->class, mi))1519CCerror(context, "Illegal local variable number");1520break;15211522case JVM_OPC_lload: case JVM_OPC_dload: case JVM_OPC_lstore: case JVM_OPC_dstore:1523var = code[offset + 1];1524check_local_variable2:1525/* Make sure that the variable number isn't illegal. */1526this_idata->operand.i = var;1527if ((var + 1) >= JVM_GetMethodIxLocalsCount(env, context->class, mi))1528CCerror(context, "Illegal local variable number");1529break;15301531default:1532if (opcode > JVM_OPC_MAX)1533CCerror(context, "Quick instructions shouldn't appear yet.");1534break;1535} /* of switch */1536}153715381539static void1540set_protected(context_type *context, unsigned int inumber, int key, int opcode)1541{1542JNIEnv *env = context->env;1543fullinfo_type clazz_info;1544if (opcode != JVM_OPC_invokevirtual && opcode != JVM_OPC_invokespecial) {1545clazz_info = cp_index_to_class_fullinfo(context, key,1546JVM_CONSTANT_Fieldref);1547} else {1548clazz_info = cp_index_to_class_fullinfo(context, key,1549JVM_CONSTANT_Methodref);1550}1551if (is_superclass(context, clazz_info)) {1552jclass calledClass =1553object_fullinfo_to_classclass(context, clazz_info);1554int access;1555/* 4734966: JVM_GetCPFieldModifiers() or JVM_GetCPMethodModifiers() only1556searches the referenced field or method in calledClass. The following1557while loop is added to search up the superclass chain to make this1558symbolic resolution consistent with the field/method resolution1559specified in VM spec 5.4.3. */1560calledClass = (*env)->NewLocalRef(env, calledClass);1561do {1562jclass tmp_cb;1563if (opcode != JVM_OPC_invokevirtual && opcode != JVM_OPC_invokespecial) {1564access = JVM_GetCPFieldModifiers1565(env, context->class, key, calledClass);1566} else {1567access = JVM_GetCPMethodModifiers1568(env, context->class, key, calledClass);1569}1570if (access != -1) {1571break;1572}1573tmp_cb = (*env)->GetSuperclass(env, calledClass);1574(*env)->DeleteLocalRef(env, calledClass);1575calledClass = tmp_cb;1576} while (calledClass != 0);15771578if (access == -1) {1579/* field/method not found, detected at runtime. */1580} else if (access & JVM_ACC_PROTECTED) {1581if (!JVM_IsSameClassPackage(env, calledClass, context->class))1582context->instruction_data[inumber].protected = JNI_TRUE;1583}1584(*env)->DeleteLocalRef(env, calledClass);1585}1586}158715881589static jboolean1590is_superclass(context_type *context, fullinfo_type clazz_info) {1591fullinfo_type *fptr = context->superclasses;15921593if (fptr == 0)1594return JNI_FALSE;1595for (; *fptr != 0; fptr++) {1596if (*fptr == clazz_info)1597return JNI_TRUE;1598}1599return JNI_FALSE;1600}160116021603/* Look through each item on the exception table. Each of the fields must1604* refer to a legal instruction.1605*/1606static void1607initialize_exception_table(context_type *context)1608{1609JNIEnv *env = context->env;1610int mi = context->method_index;1611struct handler_info_type *handler_info = context->handler_info;1612int *code_data = context->code_data;1613int code_length = context->code_length;1614int max_stack_size = JVM_GetMethodIxMaxStack(env, context->class, mi);1615int i = JVM_GetMethodIxExceptionTableLength(env, context->class, mi);1616if (max_stack_size < 1 && i > 0) {1617// If the method contains exception handlers, it must have room1618// on the expression stack for the exception that the VM could push1619CCerror(context, "Stack size too large");1620}1621for (; --i >= 0; handler_info++) {1622JVM_ExceptionTableEntryType einfo;1623stack_item_type *stack_item = NEW(stack_item_type, 1);16241625JVM_GetMethodIxExceptionTableEntry(env, context->class, mi,1626i, &einfo);16271628if (!(einfo.start_pc < einfo.end_pc &&1629einfo.start_pc >= 0 &&1630isLegalTarget(context, einfo.start_pc) &&1631(einfo.end_pc == code_length ||1632isLegalTarget(context, einfo.end_pc)))) {1633CFerror(context, "Illegal exception table range");1634}1635if (!((einfo.handler_pc > 0) &&1636isLegalTarget(context, einfo.handler_pc))) {1637CFerror(context, "Illegal exception table handler");1638}16391640handler_info->start = code_data[einfo.start_pc];1641/* einfo.end_pc may point to one byte beyond the end of bytecodes. */1642handler_info->end = (einfo.end_pc == context->code_length) ?1643context->instruction_count : code_data[einfo.end_pc];1644handler_info->handler = code_data[einfo.handler_pc];1645handler_info->stack_info.stack = stack_item;1646handler_info->stack_info.stack_size = 1;1647stack_item->next = NULL;1648if (einfo.catchType != 0) {1649const char *classname;1650/* Constant pool entry type has been checked in format checker */1651classname = JVM_GetCPClassNameUTF(env,1652context->class,1653einfo.catchType);1654check_and_push(context, classname, VM_STRING_UTF);1655stack_item->item = make_class_info_from_name(context, classname);1656if (!isAssignableTo(context,1657stack_item->item,1658context->throwable_info))1659CCerror(context, "catch_type not a subclass of Throwable");1660pop_and_free(context);1661} else {1662stack_item->item = context->throwable_info;1663}1664}1665}166616671668/* Given a pointer to an instruction, return its length. Use the table1669* opcode_length[] which is automatically built.1670*/1671static int instruction_length(unsigned char *iptr, unsigned char *end)1672{1673static unsigned char opcode_length[] = JVM_OPCODE_LENGTH_INITIALIZER;1674int instruction = *iptr;1675switch (instruction) {1676case JVM_OPC_tableswitch: {1677int *lpc = (int *)UCALIGN(iptr + 1);1678int index;1679if (lpc + 2 >= (int *)end) {1680return -1; /* do not read pass the end */1681}1682index = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]);1683if ((index < 0) || (index > 65535)) {1684return -1; /* illegal */1685} else {1686unsigned char *finish = (unsigned char *)(&lpc[index + 4]);1687assert(finish >= iptr);1688return (int)(finish - iptr);1689}1690}16911692case JVM_OPC_lookupswitch: {1693int *lpc = (int *) UCALIGN(iptr + 1);1694int npairs;1695if (lpc + 1 >= (int *)end)1696return -1; /* do not read pass the end */1697npairs = _ck_ntohl(lpc[1]);1698/* There can't be more than 64K labels because of the limit1699* on per-method byte code length.1700*/1701if (npairs < 0 || npairs >= 65536)1702return -1;1703else {1704unsigned char *finish = (unsigned char *)(&lpc[2 * (npairs + 1)]);1705assert(finish >= iptr);1706return (int)(finish - iptr);1707}1708}17091710case JVM_OPC_wide:1711if (iptr + 1 >= end)1712return -1; /* do not read pass the end */1713switch(iptr[1]) {1714case JVM_OPC_ret:1715case JVM_OPC_iload: case JVM_OPC_istore:1716case JVM_OPC_fload: case JVM_OPC_fstore:1717case JVM_OPC_aload: case JVM_OPC_astore:1718case JVM_OPC_lload: case JVM_OPC_lstore:1719case JVM_OPC_dload: case JVM_OPC_dstore:1720return 4;1721case JVM_OPC_iinc:1722return 6;1723default:1724return -1;1725}17261727default: {1728if (instruction < 0 || instruction > JVM_OPC_MAX)1729return -1;17301731/* A length of 0 indicates an error. */1732if (opcode_length[instruction] <= 0)1733return -1;17341735return opcode_length[instruction];1736}1737}1738}173917401741/* Given the target of a branch, make sure that it's a legal target. */1742static jboolean1743isLegalTarget(context_type *context, int offset)1744{1745int code_length = context->code_length;1746int *code_data = context->code_data;1747return (offset >= 0 && offset < code_length && code_data[offset] >= 0);1748}174917501751/* Make sure that an element of the constant pool really is of the indicated1752* type.1753*/1754static void1755verify_constant_pool_type(context_type *context, int index, unsigned mask)1756{1757int nconstants = context->nconstants;1758unsigned char *type_table = context->constant_types;1759unsigned type;17601761if ((index <= 0) || (index >= nconstants))1762CCerror(context, "Illegal constant pool index");17631764type = type_table[index];1765if ((mask & (1 << type)) == 0)1766CCerror(context, "Illegal type in constant pool");1767}176817691770static void1771initialize_dataflow(context_type *context)1772{1773JNIEnv *env = context->env;1774instruction_data_type *idata = context->instruction_data;1775int mi = context->method_index;1776jclass cb = context->class;1777int args_size = JVM_GetMethodIxArgsSize(env, cb, mi);1778fullinfo_type *reg_ptr;1779fullinfo_type full_info;1780const char *p;1781const char *signature;17821783/* Initialize the function entry, since we know everything about it. */1784idata[0].stack_info.stack_size = 0;1785idata[0].stack_info.stack = NULL;1786idata[0].register_info.register_count = args_size;1787idata[0].register_info.registers = NEW(fullinfo_type, args_size);1788idata[0].register_info.mask_count = 0;1789idata[0].register_info.masks = NULL;1790idata[0].and_flags = 0; /* nothing needed */1791idata[0].or_flags = FLAG_REACHED; /* instruction reached */1792reg_ptr = idata[0].register_info.registers;17931794if ((JVM_GetMethodIxModifiers(env, cb, mi) & JVM_ACC_STATIC) == 0) {1795/* A non static method. If this is an <init> method, the first1796* argument is an uninitialized object. Otherwise it is an object of1797* the given class type. java.lang.Object.<init> is special since1798* we don't call its superclass <init> method.1799*/1800if (JVM_IsConstructorIx(env, cb, mi)1801&& context->currentclass_info != context->object_info) {1802*reg_ptr++ = MAKE_FULLINFO(ITEM_InitObject, 0, 0);1803idata[0].or_flags |= FLAG_NEED_CONSTRUCTOR;1804} else {1805*reg_ptr++ = context->currentclass_info;1806}1807}1808signature = JVM_GetMethodIxSignatureUTF(env, cb, mi);1809check_and_push(context, signature, VM_STRING_UTF);1810/* Fill in each of the arguments into the registers. */1811for (p = signature + 1; *p != JVM_SIGNATURE_ENDFUNC; ) {1812char fieldchar = signature_to_fieldtype(context, &p, &full_info);1813switch (fieldchar) {1814case 'D': case 'L':1815*reg_ptr++ = full_info;1816*reg_ptr++ = full_info + 1;1817break;1818default:1819*reg_ptr++ = full_info;1820break;1821}1822}1823p++; /* skip over right parenthesis */1824if (*p == 'V') {1825context->return_type = MAKE_FULLINFO(ITEM_Void, 0, 0);1826} else {1827signature_to_fieldtype(context, &p, &full_info);1828context->return_type = full_info;1829}1830pop_and_free(context);1831/* Indicate that we need to look at the first instruction. */1832idata[0].changed = JNI_TRUE;1833}183418351836/* Run the data flow analysis, as long as there are things to change. */1837static void1838run_dataflow(context_type *context) {1839JNIEnv *env = context->env;1840int mi = context->method_index;1841jclass cb = context->class;1842int max_stack_size = JVM_GetMethodIxMaxStack(env, cb, mi);1843instruction_data_type *idata = context->instruction_data;1844unsigned int icount = context->instruction_count;1845jboolean work_to_do = JNI_TRUE;1846unsigned int inumber;18471848/* Run through the loop, until there is nothing left to do. */1849while (work_to_do) {1850work_to_do = JNI_FALSE;1851for (inumber = 0; inumber < icount; inumber++) {1852instruction_data_type *this_idata = &idata[inumber];1853if (this_idata->changed) {1854register_info_type new_register_info;1855stack_info_type new_stack_info;1856flag_type new_and_flags, new_or_flags;18571858this_idata->changed = JNI_FALSE;1859work_to_do = JNI_TRUE;1860#ifdef DEBUG1861if (verify_verbose) {1862int opcode = this_idata->opcode;1863jio_fprintf(stdout, "Instruction %d: ", inumber);1864print_stack(context, &this_idata->stack_info);1865print_registers(context, &this_idata->register_info);1866print_flags(context,1867this_idata->and_flags, this_idata->or_flags);1868fflush(stdout);1869}1870#endif1871/* Make sure the registers and flags are appropriate */1872check_register_values(context, inumber);1873check_flags(context, inumber);18741875/* Make sure the stack can deal with this instruction */1876pop_stack(context, inumber, &new_stack_info);18771878/* Update the registers and flags */1879update_registers(context, inumber, &new_register_info);1880update_flags(context, inumber, &new_and_flags, &new_or_flags);18811882/* Update the stack. */1883push_stack(context, inumber, &new_stack_info);18841885if (new_stack_info.stack_size > max_stack_size)1886CCerror(context, "Stack size too large");1887#ifdef DEBUG1888if (verify_verbose) {1889jio_fprintf(stdout, " ");1890print_stack(context, &new_stack_info);1891print_registers(context, &new_register_info);1892print_flags(context, new_and_flags, new_or_flags);1893fflush(stdout);1894}1895#endif1896/* Add the new stack and register information to any1897* instructions that can follow this instruction. */1898merge_into_successors(context, inumber,1899&new_register_info, &new_stack_info,1900new_and_flags, new_or_flags);1901}1902}1903}1904}190519061907/* Make sure that the registers contain a legitimate value for the given1908* instruction.1909*/19101911static void1912check_register_values(context_type *context, unsigned int inumber)1913{1914instruction_data_type *idata = context->instruction_data;1915instruction_data_type *this_idata = &idata[inumber];1916int opcode = this_idata->opcode;1917int operand = this_idata->operand.i;1918int register_count = this_idata->register_info.register_count;1919fullinfo_type *registers = this_idata->register_info.registers;1920jboolean double_word = JNI_FALSE; /* default value */1921int type;19221923switch (opcode) {1924default:1925return;1926case JVM_OPC_iload: case JVM_OPC_iinc:1927type = ITEM_Integer; break;1928case JVM_OPC_fload:1929type = ITEM_Float; break;1930case JVM_OPC_aload:1931type = ITEM_Object; break;1932case JVM_OPC_ret:1933type = ITEM_ReturnAddress; break;1934case JVM_OPC_lload:1935type = ITEM_Long; double_word = JNI_TRUE; break;1936case JVM_OPC_dload:1937type = ITEM_Double; double_word = JNI_TRUE; break;1938}1939if (!double_word) {1940fullinfo_type reg;1941/* Make sure we don't have an illegal register or one with wrong type */1942if (operand >= register_count) {1943CCerror(context,1944"Accessing value from uninitialized register %d", operand);1945}1946reg = registers[operand];19471948if (WITH_ZERO_EXTRA_INFO(reg) == (unsigned)MAKE_FULLINFO(type, 0, 0)) {1949/* the register is obviously of the given type */1950return;1951} else if (GET_INDIRECTION(reg) > 0 && type == ITEM_Object) {1952/* address type stuff be used on all arrays */1953return;1954} else if (GET_ITEM_TYPE(reg) == ITEM_ReturnAddress) {1955CCerror(context, "Cannot load return address from register %d",1956operand);1957/* alternatively1958(GET_ITEM_TYPE(reg) == ITEM_ReturnAddress)1959&& (opcode == JVM_OPC_iload)1960&& (type == ITEM_Object || type == ITEM_Integer)1961but this never occurs1962*/1963} else if (reg == ITEM_InitObject && type == ITEM_Object) {1964return;1965} else if (WITH_ZERO_EXTRA_INFO(reg) ==1966MAKE_FULLINFO(ITEM_NewObject, 0, 0) &&1967type == ITEM_Object) {1968return;1969} else {1970CCerror(context, "Register %d contains wrong type", operand);1971}1972} else {1973/* Make sure we don't have an illegal register or one with wrong type */1974if ((operand + 1) >= register_count) {1975CCerror(context,1976"Accessing value from uninitialized register pair %d/%d",1977operand, operand+1);1978} else {1979if ((registers[operand] == (unsigned)MAKE_FULLINFO(type, 0, 0)) &&1980(registers[operand + 1] == (unsigned)MAKE_FULLINFO(type + 1, 0, 0))) {1981return;1982} else {1983CCerror(context, "Register pair %d/%d contains wrong type",1984operand, operand+1);1985}1986}1987}1988}198919901991/* Make sure the flags contain legitimate values for this instruction.1992*/19931994static void1995check_flags(context_type *context, unsigned int inumber)1996{1997instruction_data_type *idata = context->instruction_data;1998instruction_data_type *this_idata = &idata[inumber];1999int opcode = this_idata->opcode;2000switch (opcode) {2001case JVM_OPC_return:2002/* We need a constructor, but we aren't guaranteed it's called */2003if ((this_idata->or_flags & FLAG_NEED_CONSTRUCTOR) &&2004!(this_idata->and_flags & FLAG_CONSTRUCTED))2005CCerror(context, "Constructor must call super() or this()");2006/* fall through */2007case JVM_OPC_ireturn: case JVM_OPC_lreturn:2008case JVM_OPC_freturn: case JVM_OPC_dreturn: case JVM_OPC_areturn:2009if (this_idata->or_flags & FLAG_NO_RETURN)2010/* This method cannot exit normally */2011CCerror(context, "Cannot return normally");2012default:2013break; /* nothing to do. */2014}2015}20162017/* Make sure that the top of the stack contains reasonable values for the2018* given instruction. The post-pop values of the stack and its size are2019* returned in *new_stack_info.2020*/20212022static void2023pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stack_info)2024{2025instruction_data_type *idata = context->instruction_data;2026instruction_data_type *this_idata = &idata[inumber];2027int opcode = this_idata->opcode;2028stack_item_type *stack = this_idata->stack_info.stack;2029int stack_size = this_idata->stack_info.stack_size;2030char *stack_operands, *p;2031char buffer[257]; /* for holding manufactured argument lists */2032fullinfo_type stack_extra_info_buffer[256]; /* save info popped off stack */2033fullinfo_type *stack_extra_info = &stack_extra_info_buffer[256];2034fullinfo_type full_info; /* only used in case of invoke instructions */2035fullinfo_type put_full_info; /* only used in case JVM_OPC_putstatic and JVM_OPC_putfield */20362037switch(opcode) {2038default:2039/* For most instructions, we just use a built-in table */2040stack_operands = opcode_in_out[opcode][0];2041break;20422043case JVM_OPC_putstatic: case JVM_OPC_putfield: {2044/* The top thing on the stack depends on the signature of2045* the object. */2046int operand = this_idata->operand.i;2047const char *signature =2048JVM_GetCPFieldSignatureUTF(context->env,2049context->class,2050operand);2051char *ip = buffer;2052check_and_push(context, signature, VM_STRING_UTF);2053#ifdef DEBUG2054if (verify_verbose) {2055print_formatted_fieldname(context, operand);2056}2057#endif2058if (opcode == JVM_OPC_putfield)2059*ip++ = 'A'; /* object for putfield */2060*ip++ = signature_to_fieldtype(context, &signature, &put_full_info);2061*ip = '\0';2062stack_operands = buffer;2063pop_and_free(context);2064break;2065}20662067case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial:2068case JVM_OPC_invokeinit: /* invokespecial call to <init> */2069case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: {2070/* The top stuff on the stack depends on the method signature */2071int operand = this_idata->operand.i;2072const char *signature =2073JVM_GetCPMethodSignatureUTF(context->env,2074context->class,2075operand);2076char *ip = buffer;2077const char *p;2078check_and_push(context, signature, VM_STRING_UTF);2079#ifdef DEBUG2080if (verify_verbose) {2081print_formatted_methodname(context, operand);2082}2083#endif2084if (opcode != JVM_OPC_invokestatic)2085/* First, push the object */2086*ip++ = (opcode == JVM_OPC_invokeinit ? '@' : 'A');2087for (p = signature + 1; *p != JVM_SIGNATURE_ENDFUNC; ) {2088*ip++ = signature_to_fieldtype(context, &p, &full_info);2089if (ip >= buffer + sizeof(buffer) - 1)2090CCerror(context, "Signature %s has too many arguments",2091signature);2092}2093*ip = 0;2094stack_operands = buffer;2095pop_and_free(context);2096break;2097}20982099case JVM_OPC_multianewarray: {2100/* Count can't be larger than 255. So can't overflow buffer */2101int count = this_idata->operand2.i; /* number of ints on stack */2102memset(buffer, 'I', count);2103buffer[count] = '\0';2104stack_operands = buffer;2105break;2106}21072108} /* of switch */21092110/* Run through the list of operands >>backwards<< */2111for ( p = stack_operands + strlen(stack_operands);2112p > stack_operands;2113stack = stack->next) {2114int type = *--p;2115fullinfo_type top_type = stack ? stack->item : 0;2116int size = (type == 'D' || type == 'L') ? 2 : 1;2117*--stack_extra_info = top_type;2118if (stack == NULL)2119CCerror(context, "Unable to pop operand off an empty stack");21202121switch (type) {2122case 'I':2123if (top_type != MAKE_FULLINFO(ITEM_Integer, 0, 0))2124CCerror(context, "Expecting to find integer on stack");2125break;21262127case 'F':2128if (top_type != MAKE_FULLINFO(ITEM_Float, 0, 0))2129CCerror(context, "Expecting to find float on stack");2130break;21312132case 'A': /* object or array */2133if ( (GET_ITEM_TYPE(top_type) != ITEM_Object)2134&& (GET_INDIRECTION(top_type) == 0)) {2135/* The thing isn't an object or an array. Let's see if it's2136* one of the special cases */2137if ( (WITH_ZERO_EXTRA_INFO(top_type) ==2138MAKE_FULLINFO(ITEM_ReturnAddress, 0, 0))2139&& (opcode == JVM_OPC_astore))2140break;2141if ( (GET_ITEM_TYPE(top_type) == ITEM_NewObject2142|| (GET_ITEM_TYPE(top_type) == ITEM_InitObject))2143&& ((opcode == JVM_OPC_astore) || (opcode == JVM_OPC_aload)2144|| (opcode == JVM_OPC_ifnull) || (opcode == JVM_OPC_ifnonnull)))2145break;2146/* The 2nd edition VM of the specification allows field2147* initializations before the superclass initializer,2148* if the field is defined within the current class.2149*/2150if ( (GET_ITEM_TYPE(top_type) == ITEM_InitObject)2151&& (opcode == JVM_OPC_putfield)) {2152int operand = this_idata->operand.i;2153int access_bits = JVM_GetCPFieldModifiers(context->env,2154context->class,2155operand,2156context->class);2157/* Note: This relies on the fact that2158* JVM_GetCPFieldModifiers retrieves only local fields,2159* and does not respect inheritance.2160*/2161if (access_bits != -1) {2162if ( cp_index_to_class_fullinfo(context, operand, JVM_CONSTANT_Fieldref) ==2163context->currentclass_info ) {2164top_type = context->currentclass_info;2165*stack_extra_info = top_type;2166break;2167}2168}2169}2170CCerror(context, "Expecting to find object/array on stack");2171}2172break;21732174case '@': { /* unitialized object, for call to <init> */2175int item_type = GET_ITEM_TYPE(top_type);2176if (item_type != ITEM_NewObject && item_type != ITEM_InitObject)2177CCerror(context,2178"Expecting to find unitialized object on stack");2179break;2180}21812182case 'O': /* object, not array */2183if (WITH_ZERO_EXTRA_INFO(top_type) !=2184MAKE_FULLINFO(ITEM_Object, 0, 0))2185CCerror(context, "Expecting to find object on stack");2186break;21872188case 'a': /* integer, object, or array */2189if ( (top_type != MAKE_FULLINFO(ITEM_Integer, 0, 0))2190&& (GET_ITEM_TYPE(top_type) != ITEM_Object)2191&& (GET_INDIRECTION(top_type) == 0))2192CCerror(context,2193"Expecting to find object, array, or int on stack");2194break;21952196case 'D': /* double */2197if (top_type != MAKE_FULLINFO(ITEM_Double, 0, 0))2198CCerror(context, "Expecting to find double on stack");2199break;22002201case 'L': /* long */2202if (top_type != MAKE_FULLINFO(ITEM_Long, 0, 0))2203CCerror(context, "Expecting to find long on stack");2204break;22052206case ']': /* array of some type */2207if (top_type == NULL_FULLINFO) {2208/* do nothing */2209} else switch(p[-1]) {2210case 'I': /* array of integers */2211if (top_type != MAKE_FULLINFO(ITEM_Integer, 1, 0) &&2212top_type != NULL_FULLINFO)2213CCerror(context,2214"Expecting to find array of ints on stack");2215break;22162217case 'L': /* array of longs */2218if (top_type != MAKE_FULLINFO(ITEM_Long, 1, 0))2219CCerror(context,2220"Expecting to find array of longs on stack");2221break;22222223case 'F': /* array of floats */2224if (top_type != MAKE_FULLINFO(ITEM_Float, 1, 0))2225CCerror(context,2226"Expecting to find array of floats on stack");2227break;22282229case 'D': /* array of doubles */2230if (top_type != MAKE_FULLINFO(ITEM_Double, 1, 0))2231CCerror(context,2232"Expecting to find array of doubles on stack");2233break;22342235case 'A': { /* array of addresses (arrays or objects) */2236int indirection = GET_INDIRECTION(top_type);2237if ((indirection == 0) ||2238((indirection == 1) &&2239(GET_ITEM_TYPE(top_type) != ITEM_Object)))2240CCerror(context,2241"Expecting to find array of objects or arrays "2242"on stack");2243break;2244}22452246case 'B': /* array of bytes or booleans */2247if (top_type != MAKE_FULLINFO(ITEM_Byte, 1, 0) &&2248top_type != MAKE_FULLINFO(ITEM_Boolean, 1, 0))2249CCerror(context,2250"Expecting to find array of bytes or Booleans on stack");2251break;22522253case 'C': /* array of characters */2254if (top_type != MAKE_FULLINFO(ITEM_Char, 1, 0))2255CCerror(context,2256"Expecting to find array of chars on stack");2257break;22582259case 'S': /* array of shorts */2260if (top_type != MAKE_FULLINFO(ITEM_Short, 1, 0))2261CCerror(context,2262"Expecting to find array of shorts on stack");2263break;22642265case '?': /* any type of array is okay */2266if (GET_INDIRECTION(top_type) == 0)2267CCerror(context,2268"Expecting to find array on stack");2269break;22702271default:2272CCerror(context, "Internal error #1");2273break;2274}2275p -= 2; /* skip over [ <char> */2276break;22772278case '1': case '2': case '3': case '4': /* stack swapping */2279if (top_type == MAKE_FULLINFO(ITEM_Double, 0, 0)2280|| top_type == MAKE_FULLINFO(ITEM_Long, 0, 0)) {2281if ((p > stack_operands) && (p[-1] == '+')) {2282context->swap_table[type - '1'] = top_type + 1;2283context->swap_table[p[-2] - '1'] = top_type;2284size = 2;2285p -= 2;2286} else {2287CCerror(context,2288"Attempt to split long or double on the stack");2289}2290} else {2291context->swap_table[type - '1'] = stack->item;2292if ((p > stack_operands) && (p[-1] == '+'))2293p--; /* ignore */2294}2295break;2296case '+': /* these should have been caught. */2297default:2298CCerror(context, "Internal error #2");2299}2300stack_size -= size;2301}23022303/* For many of the opcodes that had an "A" in their field, we really2304* need to go back and do a little bit more accurate testing. We can, of2305* course, assume that the minimal type checking has already been done.2306*/2307switch (opcode) {2308default: break;2309case JVM_OPC_aastore: { /* array index object */2310fullinfo_type array_type = stack_extra_info[0];2311fullinfo_type object_type = stack_extra_info[2];2312fullinfo_type target_type = decrement_indirection(array_type);2313if ((GET_ITEM_TYPE(object_type) != ITEM_Object)2314&& (GET_INDIRECTION(object_type) == 0)) {2315CCerror(context, "Expecting reference type on operand stack in aastore");2316}2317if ((GET_ITEM_TYPE(target_type) != ITEM_Object)2318&& (GET_INDIRECTION(target_type) == 0)) {2319CCerror(context, "Component type of the array must be reference type in aastore");2320}2321break;2322}23232324case JVM_OPC_putfield:2325case JVM_OPC_getfield:2326case JVM_OPC_putstatic: {2327int operand = this_idata->operand.i;2328fullinfo_type stack_object = stack_extra_info[0];2329if (opcode == JVM_OPC_putfield || opcode == JVM_OPC_getfield) {2330if (!isAssignableTo2331(context,2332stack_object,2333cp_index_to_class_fullinfo2334(context, operand, JVM_CONSTANT_Fieldref))) {2335CCerror(context,2336"Incompatible type for getting or setting field");2337}2338if (this_idata->protected &&2339!isAssignableTo(context, stack_object,2340context->currentclass_info)) {2341CCerror(context, "Bad access to protected data");2342}2343}2344if (opcode == JVM_OPC_putfield || opcode == JVM_OPC_putstatic) {2345int item = (opcode == JVM_OPC_putfield ? 1 : 0);2346if (!isAssignableTo(context,2347stack_extra_info[item], put_full_info)) {2348CCerror(context, "Bad type in putfield/putstatic");2349}2350}2351break;2352}23532354case JVM_OPC_athrow:2355if (!isAssignableTo(context, stack_extra_info[0],2356context->throwable_info)) {2357CCerror(context, "Can only throw Throwable objects");2358}2359break;23602361case JVM_OPC_aaload: { /* array index */2362/* We need to pass the information to the stack updater */2363fullinfo_type array_type = stack_extra_info[0];2364context->swap_table[0] = decrement_indirection(array_type);2365break;2366}23672368case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial:2369case JVM_OPC_invokeinit:2370case JVM_OPC_invokeinterface: case JVM_OPC_invokestatic: {2371int operand = this_idata->operand.i;2372const char *signature =2373JVM_GetCPMethodSignatureUTF(context->env,2374context->class,2375operand);2376int item;2377const char *p;2378check_and_push(context, signature, VM_STRING_UTF);2379if (opcode == JVM_OPC_invokestatic) {2380item = 0;2381} else if (opcode == JVM_OPC_invokeinit) {2382fullinfo_type init_type = this_idata->operand2.fi;2383fullinfo_type object_type = stack_extra_info[0];2384context->swap_table[0] = object_type; /* save value */2385if (GET_ITEM_TYPE(stack_extra_info[0]) == ITEM_NewObject) {2386/* We better be calling the appropriate init. Find the2387* inumber of the "JVM_OPC_new" instruction", and figure2388* out what the type really is.2389*/2390unsigned int new_inumber = GET_EXTRA_INFO(stack_extra_info[0]);2391fullinfo_type target_type = idata[new_inumber].operand2.fi;2392context->swap_table[1] = target_type;23932394if (target_type != init_type) {2395CCerror(context, "Call to wrong initialization method");2396}2397if (this_idata->protected2398&& !isAssignableTo(context, object_type,2399context->currentclass_info)) {2400CCerror(context, "Bad access to protected data");2401}2402} else {2403/* We better be calling super() or this(). */2404if (init_type != context->superclass_info &&2405init_type != context->currentclass_info) {2406CCerror(context, "Call to wrong initialization method");2407}2408context->swap_table[1] = context->currentclass_info;2409}2410item = 1;2411} else {2412fullinfo_type target_type = this_idata->operand2.fi;2413fullinfo_type object_type = stack_extra_info[0];2414if (!isAssignableTo(context, object_type, target_type)){2415CCerror(context,2416"Incompatible object argument for function call");2417}2418if (opcode == JVM_OPC_invokespecial2419&& !isAssignableTo(context, object_type,2420context->currentclass_info)) {2421/* Make sure object argument is assignment compatible to current class */2422CCerror(context,2423"Incompatible object argument for invokespecial");2424}2425if (this_idata->protected2426&& !isAssignableTo(context, object_type,2427context->currentclass_info)) {2428/* This is ugly. Special dispensation. Arrays pretend to2429implement public Object clone() even though they don't */2430const char *utfName =2431JVM_GetCPMethodNameUTF(context->env,2432context->class,2433this_idata->operand.i);2434int is_clone = utfName && (strcmp(utfName, "clone") == 0);2435JVM_ReleaseUTF(utfName);24362437if ((target_type == context->object_info) &&2438(GET_INDIRECTION(object_type) > 0) &&2439is_clone) {2440} else {2441CCerror(context, "Bad access to protected data");2442}2443}2444item = 1;2445}2446for (p = signature + 1; *p != JVM_SIGNATURE_ENDFUNC; item++)2447if (signature_to_fieldtype(context, &p, &full_info) == 'A') {2448if (!isAssignableTo(context,2449stack_extra_info[item], full_info)) {2450CCerror(context, "Incompatible argument to function");2451}2452}24532454pop_and_free(context);2455break;2456}24572458case JVM_OPC_return:2459if (context->return_type != MAKE_FULLINFO(ITEM_Void, 0, 0))2460CCerror(context, "Wrong return type in function");2461break;24622463case JVM_OPC_ireturn: case JVM_OPC_lreturn: case JVM_OPC_freturn:2464case JVM_OPC_dreturn: case JVM_OPC_areturn: {2465fullinfo_type target_type = context->return_type;2466fullinfo_type object_type = stack_extra_info[0];2467if (!isAssignableTo(context, object_type, target_type)) {2468CCerror(context, "Wrong return type in function");2469}2470break;2471}24722473case JVM_OPC_new: {2474/* Make sure that nothing on the stack already looks like what2475* we want to create. I can't image how this could possibly happen2476* but we should test for it anyway, since if it could happen, the2477* result would be an unitialized object being able to masquerade2478* as an initialized one.2479*/2480stack_item_type *item;2481for (item = stack; item != NULL; item = item->next) {2482if (item->item == this_idata->operand.fi) {2483CCerror(context,2484"Uninitialized object on stack at creating point");2485}2486}2487/* Info for update_registers */2488context->swap_table[0] = this_idata->operand.fi;2489context->swap_table[1] = MAKE_FULLINFO(ITEM_Bogus, 0, 0);24902491break;2492}2493}2494new_stack_info->stack = stack;2495new_stack_info->stack_size = stack_size;2496}249724982499/* We've already determined that the instruction is legal. Perform the2500* operation on the registers, and return the updated results in2501* new_register_count_p and new_registers.2502*/25032504static void2505update_registers(context_type *context, unsigned int inumber,2506register_info_type *new_register_info)2507{2508instruction_data_type *idata = context->instruction_data;2509instruction_data_type *this_idata = &idata[inumber];2510int opcode = this_idata->opcode;2511int operand = this_idata->operand.i;2512int register_count = this_idata->register_info.register_count;2513fullinfo_type *registers = this_idata->register_info.registers;2514stack_item_type *stack = this_idata->stack_info.stack;2515int mask_count = this_idata->register_info.mask_count;2516mask_type *masks = this_idata->register_info.masks;25172518/* Use these as default new values. */2519int new_register_count = register_count;2520int new_mask_count = mask_count;2521fullinfo_type *new_registers = registers;2522mask_type *new_masks = masks;25232524enum { ACCESS_NONE, ACCESS_SINGLE, ACCESS_DOUBLE } access = ACCESS_NONE;2525int i;25262527/* Remember, we've already verified the type at the top of the stack. */2528switch (opcode) {2529default: break;2530case JVM_OPC_istore: case JVM_OPC_fstore: case JVM_OPC_astore:2531access = ACCESS_SINGLE;2532goto continue_store;25332534case JVM_OPC_lstore: case JVM_OPC_dstore:2535access = ACCESS_DOUBLE;2536goto continue_store;25372538continue_store: {2539/* We have a modification to the registers. Copy them if needed. */2540fullinfo_type stack_top_type = stack->item;2541int max_operand = operand + ((access == ACCESS_DOUBLE) ? 1 : 0);25422543if ( max_operand < register_count2544&& registers[operand] == stack_top_type2545&& ((access == ACCESS_SINGLE) ||2546(registers[operand + 1]== stack_top_type + 1)))2547/* No changes have been made to the registers. */2548break;2549new_register_count = MAX(max_operand + 1, register_count);2550new_registers = NEW(fullinfo_type, new_register_count);2551for (i = 0; i < register_count; i++)2552new_registers[i] = registers[i];2553for (i = register_count; i < new_register_count; i++)2554new_registers[i] = MAKE_FULLINFO(ITEM_Bogus, 0, 0);2555new_registers[operand] = stack_top_type;2556if (access == ACCESS_DOUBLE)2557new_registers[operand + 1] = stack_top_type + 1;2558break;2559}25602561case JVM_OPC_iload: case JVM_OPC_fload: case JVM_OPC_aload:2562case JVM_OPC_iinc: case JVM_OPC_ret:2563access = ACCESS_SINGLE;2564break;25652566case JVM_OPC_lload: case JVM_OPC_dload:2567access = ACCESS_DOUBLE;2568break;25692570case JVM_OPC_jsr: case JVM_OPC_jsr_w:2571for (i = 0; i < new_mask_count; i++)2572if (new_masks[i].entry == operand)2573CCerror(context, "Recursive call to jsr entry");2574new_masks = add_to_masks(context, masks, mask_count, operand);2575new_mask_count++;2576break;25772578case JVM_OPC_invokeinit:2579case JVM_OPC_new: {2580/* For invokeinit, an uninitialized object has been initialized.2581* For new, all previous occurrences of an uninitialized object2582* from the same instruction must be made bogus.2583* We find all occurrences of swap_table[0] in the registers, and2584* replace them with swap_table[1];2585*/2586fullinfo_type from = context->swap_table[0];2587fullinfo_type to = context->swap_table[1];25882589int i;2590for (i = 0; i < register_count; i++) {2591if (new_registers[i] == from) {2592/* Found a match */2593break;2594}2595}2596if (i < register_count) { /* We broke out loop for match */2597/* We have to change registers, and possibly a mask */2598jboolean copied_mask = JNI_FALSE;2599int k;2600new_registers = NEW(fullinfo_type, register_count);2601memcpy(new_registers, registers,2602register_count * sizeof(registers[0]));2603for ( ; i < register_count; i++) {2604if (new_registers[i] == from) {2605new_registers[i] = to;2606for (k = 0; k < new_mask_count; k++) {2607if (!IS_BIT_SET(new_masks[k].modifies, i)) {2608if (!copied_mask) {2609new_masks = copy_masks(context, new_masks,2610mask_count);2611copied_mask = JNI_TRUE;2612}2613SET_BIT(new_masks[k].modifies, i);2614}2615}2616}2617}2618}2619break;2620}2621} /* of switch */26222623if ((access != ACCESS_NONE) && (new_mask_count > 0)) {2624int i, j;2625for (i = 0; i < new_mask_count; i++) {2626int *mask = new_masks[i].modifies;2627if ((!IS_BIT_SET(mask, operand)) ||2628((access == ACCESS_DOUBLE) &&2629!IS_BIT_SET(mask, operand + 1))) {2630new_masks = copy_masks(context, new_masks, mask_count);2631for (j = i; j < new_mask_count; j++) {2632SET_BIT(new_masks[j].modifies, operand);2633if (access == ACCESS_DOUBLE)2634SET_BIT(new_masks[j].modifies, operand + 1);2635}2636break;2637}2638}2639}26402641new_register_info->register_count = new_register_count;2642new_register_info->registers = new_registers;2643new_register_info->masks = new_masks;2644new_register_info->mask_count = new_mask_count;2645}2646264726482649/* We've already determined that the instruction is legal, and have updated2650* the registers. Update the flags, too.2651*/265226532654static void2655update_flags(context_type *context, unsigned int inumber,2656flag_type *new_and_flags, flag_type *new_or_flags)26572658{2659instruction_data_type *idata = context->instruction_data;2660instruction_data_type *this_idata = &idata[inumber];2661flag_type and_flags = this_idata->and_flags;2662flag_type or_flags = this_idata->or_flags;26632664/* Set the "we've done a constructor" flag */2665if (this_idata->opcode == JVM_OPC_invokeinit) {2666fullinfo_type from = context->swap_table[0];2667if (from == MAKE_FULLINFO(ITEM_InitObject, 0, 0))2668and_flags |= FLAG_CONSTRUCTED;2669}2670*new_and_flags = and_flags;2671*new_or_flags = or_flags;2672}2673267426752676/* We've already determined that the instruction is legal. Perform the2677* operation on the stack;2678*2679* new_stack_size_p and new_stack_p point to the results after the pops have2680* already been done. Do the pushes, and then put the results back there.2681*/26822683static void2684push_stack(context_type *context, unsigned int inumber, stack_info_type *new_stack_info)2685{2686instruction_data_type *idata = context->instruction_data;2687instruction_data_type *this_idata = &idata[inumber];2688int opcode = this_idata->opcode;2689int operand = this_idata->operand.i;26902691int stack_size = new_stack_info->stack_size;2692stack_item_type *stack = new_stack_info->stack;2693char *stack_results;26942695fullinfo_type full_info = 0;2696char buffer[5], *p; /* actually [2] is big enough */26972698/* We need to look at all those opcodes in which either we can't tell the2699* value pushed onto the stack from the opcode, or in which the value2700* pushed onto the stack is an object or array. For the latter, we need2701* to make sure that full_info is set to the right value.2702*/2703switch(opcode) {2704default:2705stack_results = opcode_in_out[opcode][1];2706break;27072708case JVM_OPC_ldc: case JVM_OPC_ldc_w: case JVM_OPC_ldc2_w: {2709/* Look to constant pool to determine correct result. */2710unsigned char *type_table = context->constant_types;2711switch (type_table[operand]) {2712case JVM_CONSTANT_Integer:2713stack_results = "I"; break;2714case JVM_CONSTANT_Float:2715stack_results = "F"; break;2716case JVM_CONSTANT_Double:2717stack_results = "D"; break;2718case JVM_CONSTANT_Long:2719stack_results = "L"; break;2720case JVM_CONSTANT_String:2721stack_results = "A";2722full_info = context->string_info;2723break;2724case JVM_CONSTANT_Class:2725if (context->major_version < LDC_CLASS_MAJOR_VERSION)2726CCerror(context, "Internal error #3");2727stack_results = "A";2728full_info = make_class_info_from_name(context,2729"java/lang/Class");2730break;2731case JVM_CONSTANT_MethodHandle:2732case JVM_CONSTANT_MethodType:2733if (context->major_version < LDC_METHOD_HANDLE_MAJOR_VERSION)2734CCerror(context, "Internal error #3");2735stack_results = "A";2736switch (type_table[operand]) {2737case JVM_CONSTANT_MethodType:2738full_info = make_class_info_from_name(context,2739"java/lang/invoke/MethodType");2740break;2741default: //JVM_CONSTANT_MethodHandle2742full_info = make_class_info_from_name(context,2743"java/lang/invoke/MethodHandle");2744break;2745}2746break;2747default:2748CCerror(context, "Internal error #3");2749stack_results = ""; /* Never reached: keep lint happy */2750}2751break;2752}27532754case JVM_OPC_getstatic: case JVM_OPC_getfield: {2755/* Look to signature to determine correct result. */2756int operand = this_idata->operand.i;2757const char *signature = JVM_GetCPFieldSignatureUTF(context->env,2758context->class,2759operand);2760check_and_push(context, signature, VM_STRING_UTF);2761#ifdef DEBUG2762if (verify_verbose) {2763print_formatted_fieldname(context, operand);2764}2765#endif2766buffer[0] = signature_to_fieldtype(context, &signature, &full_info);2767buffer[1] = '\0';2768stack_results = buffer;2769pop_and_free(context);2770break;2771}27722773case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial:2774case JVM_OPC_invokeinit:2775case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: {2776/* Look to signature to determine correct result. */2777int operand = this_idata->operand.i;2778const char *signature = JVM_GetCPMethodSignatureUTF(context->env,2779context->class,2780operand);2781const char *result_signature;2782check_and_push(context, signature, VM_STRING_UTF);2783result_signature = get_result_signature(signature);2784if (result_signature++ == NULL) {2785CCerror(context, "Illegal signature %s", signature);2786}2787if (result_signature[0] == JVM_SIGNATURE_VOID) {2788stack_results = "";2789} else {2790buffer[0] = signature_to_fieldtype(context, &result_signature,2791&full_info);2792buffer[1] = '\0';2793stack_results = buffer;2794}2795pop_and_free(context);2796break;2797}27982799case JVM_OPC_aconst_null:2800stack_results = opcode_in_out[opcode][1];2801full_info = NULL_FULLINFO; /* special NULL */2802break;28032804case JVM_OPC_new:2805case JVM_OPC_checkcast:2806case JVM_OPC_newarray:2807case JVM_OPC_anewarray:2808case JVM_OPC_multianewarray:2809stack_results = opcode_in_out[opcode][1];2810/* Conveniently, this result type is stored here */2811full_info = this_idata->operand.fi;2812break;28132814case JVM_OPC_aaload:2815stack_results = opcode_in_out[opcode][1];2816/* pop_stack() saved value for us. */2817full_info = context->swap_table[0];2818break;28192820case JVM_OPC_aload:2821stack_results = opcode_in_out[opcode][1];2822/* The register hasn't been modified, so we can use its value. */2823full_info = this_idata->register_info.registers[operand];2824break;2825} /* of switch */28262827for (p = stack_results; *p != 0; p++) {2828int type = *p;2829stack_item_type *new_item = NEW(stack_item_type, 1);2830new_item->next = stack;2831stack = new_item;2832switch (type) {2833case 'I':2834stack->item = MAKE_FULLINFO(ITEM_Integer, 0, 0); break;2835case 'F':2836stack->item = MAKE_FULLINFO(ITEM_Float, 0, 0); break;2837case 'D':2838stack->item = MAKE_FULLINFO(ITEM_Double, 0, 0);2839stack_size++; break;2840case 'L':2841stack->item = MAKE_FULLINFO(ITEM_Long, 0, 0);2842stack_size++; break;2843case 'R':2844stack->item = MAKE_FULLINFO(ITEM_ReturnAddress, 0, operand);2845break;2846case '1': case '2': case '3': case '4': {2847/* Get the info saved in the swap_table */2848fullinfo_type stype = context->swap_table[type - '1'];2849stack->item = stype;2850if (stype == MAKE_FULLINFO(ITEM_Long, 0, 0) ||2851stype == MAKE_FULLINFO(ITEM_Double, 0, 0)) {2852stack_size++; p++;2853}2854break;2855}2856case 'A':2857/* full_info should have the appropriate value. */2858assert(full_info != 0);2859stack->item = full_info;2860break;2861default:2862CCerror(context, "Internal error #4");28632864} /* switch type */2865stack_size++;2866} /* outer for loop */28672868if (opcode == JVM_OPC_invokeinit) {2869/* If there are any instances of "from" on the stack, we need to2870* replace it with "to", since calling <init> initializes all versions2871* of the object, obviously. */2872fullinfo_type from = context->swap_table[0];2873stack_item_type *ptr;2874for (ptr = stack; ptr != NULL; ptr = ptr->next) {2875if (ptr->item == from) {2876fullinfo_type to = context->swap_table[1];2877stack = copy_stack(context, stack);2878for (ptr = stack; ptr != NULL; ptr = ptr->next)2879if (ptr->item == from) ptr->item = to;2880break;2881}2882}2883}28842885new_stack_info->stack_size = stack_size;2886new_stack_info->stack = stack;2887}288828892890/* We've performed an instruction, and determined the new registers and stack2891* value. Look at all of the possibly subsequent instructions, and merge2892* this stack value into theirs.2893*/28942895static void2896merge_into_successors(context_type *context, unsigned int inumber,2897register_info_type *register_info,2898stack_info_type *stack_info,2899flag_type and_flags, flag_type or_flags)2900{2901instruction_data_type *idata = context->instruction_data;2902instruction_data_type *this_idata = &idata[inumber];2903int opcode = this_idata->opcode;2904int operand = this_idata->operand.i;2905struct handler_info_type *handler_info = context->handler_info;2906int handler_info_length =2907JVM_GetMethodIxExceptionTableLength(context->env,2908context->class,2909context->method_index);291029112912int buffer[2]; /* default value for successors */2913int *successors = buffer; /* table of successors */2914int successors_count;2915int i;29162917switch (opcode) {2918default:2919successors_count = 1;2920buffer[0] = inumber + 1;2921break;29222923case JVM_OPC_ifeq: case JVM_OPC_ifne: case JVM_OPC_ifgt:2924case JVM_OPC_ifge: case JVM_OPC_iflt: case JVM_OPC_ifle:2925case JVM_OPC_ifnull: case JVM_OPC_ifnonnull:2926case JVM_OPC_if_icmpeq: case JVM_OPC_if_icmpne: case JVM_OPC_if_icmpgt:2927case JVM_OPC_if_icmpge: case JVM_OPC_if_icmplt: case JVM_OPC_if_icmple:2928case JVM_OPC_if_acmpeq: case JVM_OPC_if_acmpne:2929successors_count = 2;2930buffer[0] = inumber + 1;2931buffer[1] = operand;2932break;29332934case JVM_OPC_jsr: case JVM_OPC_jsr_w:2935if (this_idata->operand2.i != UNKNOWN_RET_INSTRUCTION)2936idata[this_idata->operand2.i].changed = JNI_TRUE;2937/* FALLTHROUGH */2938case JVM_OPC_goto: case JVM_OPC_goto_w:2939successors_count = 1;2940buffer[0] = operand;2941break;294229432944case JVM_OPC_ireturn: case JVM_OPC_lreturn: case JVM_OPC_return:2945case JVM_OPC_freturn: case JVM_OPC_dreturn: case JVM_OPC_areturn:2946case JVM_OPC_athrow:2947/* The testing for the returns is handled in pop_stack() */2948successors_count = 0;2949break;29502951case JVM_OPC_ret: {2952/* This is slightly slow, but good enough for a seldom used instruction.2953* The EXTRA_ITEM_INFO of the ITEM_ReturnAddress indicates the2954* address of the first instruction of the subroutine. We can return2955* to 1 after any instruction that jsr's to that instruction.2956*/2957if (this_idata->operand2.ip == NULL) {2958fullinfo_type *registers = this_idata->register_info.registers;2959int called_instruction = GET_EXTRA_INFO(registers[operand]);2960int i, count, *ptr;;2961for (i = context->instruction_count, count = 0; --i >= 0; ) {2962if (((idata[i].opcode == JVM_OPC_jsr) ||2963(idata[i].opcode == JVM_OPC_jsr_w)) &&2964(idata[i].operand.i == called_instruction))2965count++;2966}2967this_idata->operand2.ip = ptr = NEW(int, count + 1);2968*ptr++ = count;2969for (i = context->instruction_count, count = 0; --i >= 0; ) {2970if (((idata[i].opcode == JVM_OPC_jsr) ||2971(idata[i].opcode == JVM_OPC_jsr_w)) &&2972(idata[i].operand.i == called_instruction))2973*ptr++ = i + 1;2974}2975}2976successors = this_idata->operand2.ip; /* use this instead */2977successors_count = *successors++;2978break;29792980}29812982case JVM_OPC_tableswitch:2983case JVM_OPC_lookupswitch:2984successors = this_idata->operand.ip; /* use this instead */2985successors_count = *successors++;2986break;2987}29882989#ifdef DEBUG2990if (verify_verbose) {2991jio_fprintf(stdout, " [");2992for (i = handler_info_length; --i >= 0; handler_info++)2993if (handler_info->start <= (int)inumber && handler_info->end > (int)inumber)2994jio_fprintf(stdout, "%d* ", handler_info->handler);2995for (i = 0; i < successors_count; i++)2996jio_fprintf(stdout, "%d ", successors[i]);2997jio_fprintf(stdout, "]\n");2998}2999#endif30003001handler_info = context->handler_info;3002for (i = handler_info_length; --i >= 0; handler_info++) {3003if (handler_info->start <= (int)inumber && handler_info->end > (int)inumber) {3004int handler = handler_info->handler;3005if (opcode != JVM_OPC_invokeinit) {3006merge_into_one_successor(context, inumber, handler,3007&this_idata->register_info, /* old */3008&handler_info->stack_info,3009(flag_type) (and_flags3010& this_idata->and_flags),3011(flag_type) (or_flags3012| this_idata->or_flags),3013JNI_TRUE);3014} else {3015/* We need to be a little bit more careful with this3016* instruction. Things could either be in the state before3017* the instruction or in the state afterwards */3018fullinfo_type from = context->swap_table[0];3019flag_type temp_or_flags = or_flags;3020if (from == MAKE_FULLINFO(ITEM_InitObject, 0, 0))3021temp_or_flags |= FLAG_NO_RETURN;3022merge_into_one_successor(context, inumber, handler,3023&this_idata->register_info, /* old */3024&handler_info->stack_info,3025this_idata->and_flags,3026this_idata->or_flags,3027JNI_TRUE);3028merge_into_one_successor(context, inumber, handler,3029register_info,3030&handler_info->stack_info,3031and_flags, temp_or_flags, JNI_TRUE);3032}3033}3034}3035for (i = 0; i < successors_count; i++) {3036int target = successors[i];3037if (target >= context->instruction_count)3038CCerror(context, "Falling off the end of the code");3039merge_into_one_successor(context, inumber, target,3040register_info, stack_info, and_flags, or_flags,3041JNI_FALSE);3042}3043}30443045/* We have a new set of registers and stack values for a given instruction.3046* Merge this new set into the values that are already there.3047*/30483049static void3050merge_into_one_successor(context_type *context,3051unsigned int from_inumber, unsigned int to_inumber,3052register_info_type *new_register_info,3053stack_info_type *new_stack_info,3054flag_type new_and_flags, flag_type new_or_flags,3055jboolean isException)3056{3057instruction_data_type *idata = context->instruction_data;3058register_info_type register_info_buf;3059stack_info_type stack_info_buf;3060#ifdef DEBUG3061instruction_data_type *this_idata = &idata[to_inumber];3062register_info_type old_reg_info;3063stack_info_type old_stack_info;3064flag_type old_and_flags = 0;3065flag_type old_or_flags = 0;3066#endif30673068#ifdef DEBUG3069if (verify_verbose) {3070old_reg_info = this_idata->register_info;3071old_stack_info = this_idata->stack_info;3072old_and_flags = this_idata->and_flags;3073old_or_flags = this_idata->or_flags;3074}3075#endif30763077/* All uninitialized objects are set to "bogus" when jsr and3078* ret are executed. Thus uninitialized objects can't propagate3079* into or out of a subroutine.3080*/3081if (idata[from_inumber].opcode == JVM_OPC_ret ||3082idata[from_inumber].opcode == JVM_OPC_jsr ||3083idata[from_inumber].opcode == JVM_OPC_jsr_w) {3084int new_register_count = new_register_info->register_count;3085fullinfo_type *new_registers = new_register_info->registers;3086int i;3087stack_item_type *item;30883089for (item = new_stack_info->stack; item != NULL; item = item->next) {3090if (GET_ITEM_TYPE(item->item) == ITEM_NewObject) {3091/* This check only succeeds for hand-contrived code.3092* Efficiency is not an issue.3093*/3094stack_info_buf.stack = copy_stack(context,3095new_stack_info->stack);3096stack_info_buf.stack_size = new_stack_info->stack_size;3097new_stack_info = &stack_info_buf;3098for (item = new_stack_info->stack; item != NULL;3099item = item->next) {3100if (GET_ITEM_TYPE(item->item) == ITEM_NewObject) {3101item->item = MAKE_FULLINFO(ITEM_Bogus, 0, 0);3102}3103}3104break;3105}3106}3107for (i = 0; i < new_register_count; i++) {3108if (GET_ITEM_TYPE(new_registers[i]) == ITEM_NewObject) {3109/* This check only succeeds for hand-contrived code.3110* Efficiency is not an issue.3111*/3112fullinfo_type *new_set = NEW(fullinfo_type,3113new_register_count);3114for (i = 0; i < new_register_count; i++) {3115fullinfo_type t = new_registers[i];3116new_set[i] = GET_ITEM_TYPE(t) != ITEM_NewObject ?3117t : MAKE_FULLINFO(ITEM_Bogus, 0, 0);3118}3119register_info_buf.register_count = new_register_count;3120register_info_buf.registers = new_set;3121register_info_buf.mask_count = new_register_info->mask_count;3122register_info_buf.masks = new_register_info->masks;3123new_register_info = ®ister_info_buf;3124break;3125}3126}3127}31283129/* Returning from a subroutine is somewhat ugly. The actual thing3130* that needs to get merged into the new instruction is a joining3131* of info from the ret instruction with stuff in the jsr instruction3132*/3133if (idata[from_inumber].opcode == JVM_OPC_ret && !isException) {3134int new_register_count = new_register_info->register_count;3135fullinfo_type *new_registers = new_register_info->registers;3136int new_mask_count = new_register_info->mask_count;3137mask_type *new_masks = new_register_info->masks;3138int operand = idata[from_inumber].operand.i;3139int called_instruction = GET_EXTRA_INFO(new_registers[operand]);3140instruction_data_type *jsr_idata = &idata[to_inumber - 1];3141register_info_type *jsr_reginfo = &jsr_idata->register_info;3142if (jsr_idata->operand2.i != (int)from_inumber) {3143if (jsr_idata->operand2.i != UNKNOWN_RET_INSTRUCTION)3144CCerror(context, "Multiple returns to single jsr");3145jsr_idata->operand2.i = from_inumber;3146}3147if (jsr_reginfo->register_count == UNKNOWN_REGISTER_COUNT) {3148/* We don't want to handle the returned-to instruction until3149* we've dealt with the jsr instruction. When we get to the3150* jsr instruction (if ever), we'll re-mark the ret instruction3151*/3152;3153} else {3154int register_count = jsr_reginfo->register_count;3155fullinfo_type *registers = jsr_reginfo->registers;3156int max_registers = MAX(register_count, new_register_count);3157fullinfo_type *new_set = NEW(fullinfo_type, max_registers);3158int *return_mask;3159struct register_info_type new_new_register_info;3160int i;3161/* Make sure the place we're returning from is legal! */3162for (i = new_mask_count; --i >= 0; )3163if (new_masks[i].entry == called_instruction)3164break;3165if (i < 0)3166CCerror(context, "Illegal return from subroutine");3167/* pop the masks down to the indicated one. Remember the mask3168* we're popping off. */3169return_mask = new_masks[i].modifies;3170new_mask_count = i;3171for (i = 0; i < max_registers; i++) {3172if (IS_BIT_SET(return_mask, i))3173new_set[i] = i < new_register_count ?3174new_registers[i] : MAKE_FULLINFO(ITEM_Bogus, 0, 0);3175else3176new_set[i] = i < register_count ?3177registers[i] : MAKE_FULLINFO(ITEM_Bogus, 0, 0);3178}3179new_new_register_info.register_count = max_registers;3180new_new_register_info.registers = new_set;3181new_new_register_info.mask_count = new_mask_count;3182new_new_register_info.masks = new_masks;318331843185merge_stack(context, from_inumber, to_inumber, new_stack_info);3186merge_registers(context, to_inumber - 1, to_inumber,3187&new_new_register_info);3188merge_flags(context, from_inumber, to_inumber, new_and_flags, new_or_flags);3189}3190} else {3191merge_stack(context, from_inumber, to_inumber, new_stack_info);3192merge_registers(context, from_inumber, to_inumber, new_register_info);3193merge_flags(context, from_inumber, to_inumber,3194new_and_flags, new_or_flags);3195}31963197#ifdef DEBUG3198if (verify_verbose && idata[to_inumber].changed) {3199register_info_type *register_info = &this_idata->register_info;3200stack_info_type *stack_info = &this_idata->stack_info;3201if (memcmp(&old_reg_info, register_info, sizeof(old_reg_info)) ||3202memcmp(&old_stack_info, stack_info, sizeof(old_stack_info)) ||3203(old_and_flags != this_idata->and_flags) ||3204(old_or_flags != this_idata->or_flags)) {3205jio_fprintf(stdout, " %2d:", to_inumber);3206print_stack(context, &old_stack_info);3207print_registers(context, &old_reg_info);3208print_flags(context, old_and_flags, old_or_flags);3209jio_fprintf(stdout, " => ");3210print_stack(context, &this_idata->stack_info);3211print_registers(context, &this_idata->register_info);3212print_flags(context, this_idata->and_flags, this_idata->or_flags);3213jio_fprintf(stdout, "\n");3214}3215}3216#endif32173218}32193220static void3221merge_stack(context_type *context, unsigned int from_inumber,3222unsigned int to_inumber, stack_info_type *new_stack_info)3223{3224instruction_data_type *idata = context->instruction_data;3225instruction_data_type *this_idata = &idata[to_inumber];32263227int new_stack_size = new_stack_info->stack_size;3228stack_item_type *new_stack = new_stack_info->stack;32293230int stack_size = this_idata->stack_info.stack_size;32313232if (stack_size == UNKNOWN_STACK_SIZE) {3233/* First time at this instruction. Just copy. */3234this_idata->stack_info.stack_size = new_stack_size;3235this_idata->stack_info.stack = new_stack;3236this_idata->changed = JNI_TRUE;3237} else if (new_stack_size != stack_size) {3238CCerror(context, "Inconsistent stack height %d != %d",3239new_stack_size, stack_size);3240} else {3241stack_item_type *stack = this_idata->stack_info.stack;3242stack_item_type *old, *new;3243jboolean change = JNI_FALSE;3244for (old = stack, new = new_stack; old != NULL;3245old = old->next, new = new->next) {3246if (!isAssignableTo(context, new->item, old->item)) {3247change = JNI_TRUE;3248break;3249}3250}3251if (change) {3252stack = copy_stack(context, stack);3253for (old = stack, new = new_stack; old != NULL;3254old = old->next, new = new->next) {3255if (new == NULL) {3256break;3257}3258old->item = merge_fullinfo_types(context, old->item, new->item,3259JNI_FALSE);3260if (GET_ITEM_TYPE(old->item) == ITEM_Bogus) {3261CCerror(context, "Mismatched stack types");3262}3263}3264if (old != NULL || new != NULL) {3265CCerror(context, "Mismatched stack types");3266}3267this_idata->stack_info.stack = stack;3268this_idata->changed = JNI_TRUE;3269}3270}3271}32723273static void3274merge_registers(context_type *context, unsigned int from_inumber,3275unsigned int to_inumber, register_info_type *new_register_info)3276{3277instruction_data_type *idata = context->instruction_data;3278instruction_data_type *this_idata = &idata[to_inumber];3279register_info_type *this_reginfo = &this_idata->register_info;32803281int new_register_count = new_register_info->register_count;3282fullinfo_type *new_registers = new_register_info->registers;3283int new_mask_count = new_register_info->mask_count;3284mask_type *new_masks = new_register_info->masks;328532863287if (this_reginfo->register_count == UNKNOWN_REGISTER_COUNT) {3288this_reginfo->register_count = new_register_count;3289this_reginfo->registers = new_registers;3290this_reginfo->mask_count = new_mask_count;3291this_reginfo->masks = new_masks;3292this_idata->changed = JNI_TRUE;3293} else {3294/* See if we've got new information on the register set. */3295int register_count = this_reginfo->register_count;3296fullinfo_type *registers = this_reginfo->registers;3297int mask_count = this_reginfo->mask_count;3298mask_type *masks = this_reginfo->masks;32993300jboolean copy = JNI_FALSE;3301int i, j;3302if (register_count > new_register_count) {3303/* Any register larger than new_register_count is now bogus */3304this_reginfo->register_count = new_register_count;3305register_count = new_register_count;3306this_idata->changed = JNI_TRUE;3307}3308for (i = 0; i < register_count; i++) {3309fullinfo_type prev_value = registers[i];3310if ((i < new_register_count)3311? (!isAssignableTo(context, new_registers[i], prev_value))3312: (prev_value != MAKE_FULLINFO(ITEM_Bogus, 0, 0))) {3313copy = JNI_TRUE;3314break;3315}3316}33173318if (copy) {3319/* We need a copy. So do it. */3320fullinfo_type *new_set = NEW(fullinfo_type, register_count);3321for (j = 0; j < i; j++)3322new_set[j] = registers[j];3323for (j = i; j < register_count; j++) {3324if (i >= new_register_count)3325new_set[j] = MAKE_FULLINFO(ITEM_Bogus, 0, 0);3326else3327new_set[j] = merge_fullinfo_types(context,3328new_registers[j],3329registers[j], JNI_FALSE);3330}3331/* Some of the end items might now be bogus. This step isn't3332* necessary, but it may save work later. */3333while ( register_count > 03334&& GET_ITEM_TYPE(new_set[register_count-1]) == ITEM_Bogus)3335register_count--;3336this_reginfo->register_count = register_count;3337this_reginfo->registers = new_set;3338this_idata->changed = JNI_TRUE;3339}3340if (mask_count > 0) {3341/* If the target instruction already has a sequence of masks, then3342* we need to merge new_masks into it. We want the entries on3343* the mask to be the longest common substring of the two.3344* (e.g. a->b->d merged with a->c->d should give a->d)3345* The bits set in the mask should be the or of the corresponding3346* entries in each of the original masks.3347*/3348int i, j, k;3349int matches = 0;3350int last_match = -1;3351jboolean copy_needed = JNI_FALSE;3352for (i = 0; i < mask_count; i++) {3353int entry = masks[i].entry;3354for (j = last_match + 1; j < new_mask_count; j++) {3355if (new_masks[j].entry == entry) {3356/* We have a match */3357int *prev = masks[i].modifies;3358int *new = new_masks[j].modifies;3359matches++;3360/* See if new_mask has bits set for "entry" that3361* weren't set for mask. If so, need to copy. */3362for (k = context->bitmask_size - 1;3363!copy_needed && k >= 0;3364k--)3365if (~prev[k] & new[k])3366copy_needed = JNI_TRUE;3367last_match = j;3368break;3369}3370}3371}3372if ((matches < mask_count) || copy_needed) {3373/* We need to make a copy for the new item, since either the3374* size has decreased, or new bits are set. */3375mask_type *copy = NEW(mask_type, matches);3376for (i = 0; i < matches; i++) {3377copy[i].modifies = NEW(int, context->bitmask_size);3378}3379this_reginfo->masks = copy;3380this_reginfo->mask_count = matches;3381this_idata->changed = JNI_TRUE;3382matches = 0;3383last_match = -1;3384for (i = 0; i < mask_count; i++) {3385int entry = masks[i].entry;3386for (j = last_match + 1; j < new_mask_count; j++) {3387if (new_masks[j].entry == entry) {3388int *prev1 = masks[i].modifies;3389int *prev2 = new_masks[j].modifies;3390int *new = copy[matches].modifies;3391copy[matches].entry = entry;3392for (k = context->bitmask_size - 1; k >= 0; k--)3393new[k] = prev1[k] | prev2[k];3394matches++;3395last_match = j;3396break;3397}3398}3399}3400}3401}3402}3403}340434053406static void3407merge_flags(context_type *context, unsigned int from_inumber,3408unsigned int to_inumber,3409flag_type new_and_flags, flag_type new_or_flags)3410{3411/* Set this_idata->and_flags &= new_and_flags3412this_idata->or_flags |= new_or_flags3413*/3414instruction_data_type *idata = context->instruction_data;3415instruction_data_type *this_idata = &idata[to_inumber];3416flag_type this_and_flags = this_idata->and_flags;3417flag_type this_or_flags = this_idata->or_flags;3418flag_type merged_and = this_and_flags & new_and_flags;3419flag_type merged_or = this_or_flags | new_or_flags;34203421if ((merged_and != this_and_flags) || (merged_or != this_or_flags)) {3422this_idata->and_flags = merged_and;3423this_idata->or_flags = merged_or;3424this_idata->changed = JNI_TRUE;3425}3426}342734283429/* Make a copy of a stack */34303431static stack_item_type *3432copy_stack(context_type *context, stack_item_type *stack)3433{3434int length;3435stack_item_type *ptr;34363437/* Find the length */3438for (ptr = stack, length = 0; ptr != NULL; ptr = ptr->next, length++);34393440if (length > 0) {3441stack_item_type *new_stack = NEW(stack_item_type, length);3442stack_item_type *new_ptr;3443for ( ptr = stack, new_ptr = new_stack;3444ptr != NULL;3445ptr = ptr->next, new_ptr++) {3446new_ptr->item = ptr->item;3447new_ptr->next = new_ptr + 1;3448}3449new_stack[length - 1].next = NULL;3450return new_stack;3451} else {3452return NULL;3453}3454}345534563457static mask_type *3458copy_masks(context_type *context, mask_type *masks, int mask_count)3459{3460mask_type *result = NEW(mask_type, mask_count);3461int bitmask_size = context->bitmask_size;3462int *bitmaps = NEW(int, mask_count * bitmask_size);3463int i;3464for (i = 0; i < mask_count; i++) {3465result[i].entry = masks[i].entry;3466result[i].modifies = &bitmaps[i * bitmask_size];3467memcpy(result[i].modifies, masks[i].modifies, bitmask_size * sizeof(int));3468}3469return result;3470}347134723473static mask_type *3474add_to_masks(context_type *context, mask_type *masks, int mask_count, int d)3475{3476mask_type *result = NEW(mask_type, mask_count + 1);3477int bitmask_size = context->bitmask_size;3478int *bitmaps = NEW(int, (mask_count + 1) * bitmask_size);3479int i;3480for (i = 0; i < mask_count; i++) {3481result[i].entry = masks[i].entry;3482result[i].modifies = &bitmaps[i * bitmask_size];3483memcpy(result[i].modifies, masks[i].modifies, bitmask_size * sizeof(int));3484}3485result[mask_count].entry = d;3486result[mask_count].modifies = &bitmaps[mask_count * bitmask_size];3487memset(result[mask_count].modifies, 0, bitmask_size * sizeof(int));3488return result;3489}3490349134923493/* We create our own storage manager, since we malloc lots of little items,3494* and I don't want to keep trace of when they become free. I sure wish that3495* we had heaps, and I could just free the heap when done.3496*/34973498#define CCSegSize 200034993500struct CCpool { /* a segment of allocated memory in the pool */3501struct CCpool *next;3502int segSize; /* almost always CCSegSize */3503int poolPad;3504char space[CCSegSize];3505};35063507/* Initialize the context's heap. */3508static void CCinit(context_type *context)3509{3510struct CCpool *new = (struct CCpool *) malloc(sizeof(struct CCpool));3511/* Set context->CCroot to 0 if new == 0 to tell CCdestroy to lay off */3512context->CCroot = context->CCcurrent = new;3513if (new == 0) {3514CCout_of_memory(context);3515}3516new->next = NULL;3517new->segSize = CCSegSize;3518context->CCfree_size = CCSegSize;3519context->CCfree_ptr = &new->space[0];3520}352135223523/* Reuse all the space that we have in the context's heap. */3524static void CCreinit(context_type *context)3525{3526struct CCpool *first = context->CCroot;3527context->CCcurrent = first;3528context->CCfree_size = CCSegSize;3529context->CCfree_ptr = &first->space[0];3530}35313532/* Destroy the context's heap. */3533static void CCdestroy(context_type *context)3534{3535struct CCpool *this = context->CCroot;3536while (this) {3537struct CCpool *next = this->next;3538free(this);3539this = next;3540}3541/* These two aren't necessary. But can't hurt either */3542context->CCroot = context->CCcurrent = NULL;3543context->CCfree_ptr = 0;3544}35453546/* Allocate an object of the given size from the context's heap. */3547static void *3548CCalloc(context_type *context, int size, jboolean zero)3549{35503551register char *p;3552/* Round CC to the size of a pointer */3553size = (size + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1);35543555if (context->CCfree_size < size) {3556struct CCpool *current = context->CCcurrent;3557struct CCpool *new;3558if (size > CCSegSize) { /* we need to allocate a special block */3559new = (struct CCpool *)malloc(sizeof(struct CCpool) +3560(size - CCSegSize));3561if (new == 0) {3562CCout_of_memory(context);3563}3564new->next = current->next;3565new->segSize = size;3566current->next = new;3567} else {3568new = current->next;3569if (new == NULL) {3570new = (struct CCpool *) malloc(sizeof(struct CCpool));3571if (new == 0) {3572CCout_of_memory(context);3573}3574current->next = new;3575new->next = NULL;3576new->segSize = CCSegSize;3577}3578}3579context->CCcurrent = new;3580context->CCfree_ptr = &new->space[0];3581context->CCfree_size = new->segSize;3582}3583p = context->CCfree_ptr;3584context->CCfree_ptr += size;3585context->CCfree_size -= size;3586if (zero)3587memset(p, 0, size);3588return p;3589}35903591/* Get the class associated with a particular field or method or class in the3592* constant pool. If is_field is true, we've got a field or method. If3593* false, we've got a class.3594*/3595static fullinfo_type3596cp_index_to_class_fullinfo(context_type *context, int cp_index, int kind)3597{3598JNIEnv *env = context->env;3599fullinfo_type result;3600const char *classname;3601switch (kind) {3602case JVM_CONSTANT_Class:3603classname = JVM_GetCPClassNameUTF(env,3604context->class,3605cp_index);3606break;3607case JVM_CONSTANT_Methodref:3608classname = JVM_GetCPMethodClassNameUTF(env,3609context->class,3610cp_index);3611break;3612case JVM_CONSTANT_Fieldref:3613classname = JVM_GetCPFieldClassNameUTF(env,3614context->class,3615cp_index);3616break;3617default:3618classname = NULL;3619CCerror(context, "Internal error #5");3620}36213622check_and_push(context, classname, VM_STRING_UTF);3623if (classname[0] == JVM_SIGNATURE_ARRAY) {3624/* This make recursively call us, in case of a class array */3625signature_to_fieldtype(context, &classname, &result);3626} else {3627result = make_class_info_from_name(context, classname);3628}3629pop_and_free(context);3630return result;3631}363236333634static int3635print_CCerror_info(context_type *context)3636{3637JNIEnv *env = context->env;3638jclass cb = context->class;3639const char *classname = JVM_GetClassNameUTF(env, cb);3640const char *name = 0;3641const char *signature = 0;3642int n = 0;3643if (context->method_index != -1) {3644name = JVM_GetMethodIxNameUTF(env, cb, context->method_index);3645signature =3646JVM_GetMethodIxSignatureUTF(env, cb, context->method_index);3647n += jio_snprintf(context->message, context->message_buf_len,3648"(class: %s, method: %s signature: %s) ",3649(classname ? classname : ""),3650(name ? name : ""),3651(signature ? signature : ""));3652} else if (context->field_index != -1 ) {3653name = JVM_GetMethodIxNameUTF(env, cb, context->field_index);3654n += jio_snprintf(context->message, context->message_buf_len,3655"(class: %s, field: %s) ",3656(classname ? classname : 0),3657(name ? name : 0));3658} else {3659n += jio_snprintf(context->message, context->message_buf_len,3660"(class: %s) ", classname ? classname : "");3661}3662JVM_ReleaseUTF(classname);3663JVM_ReleaseUTF(name);3664JVM_ReleaseUTF(signature);3665return n;3666}36673668static void3669CCerror (context_type *context, char *format, ...)3670{3671int n = print_CCerror_info(context);3672va_list args;3673if (n >= 0 && n < context->message_buf_len) {3674va_start(args, format);3675jio_vsnprintf(context->message + n, context->message_buf_len - n,3676format, args);3677va_end(args);3678}3679context->err_code = CC_VerifyError;3680longjmp(context->jump_buffer, 1);3681}36823683static void3684CCout_of_memory(context_type *context)3685{3686int n = print_CCerror_info(context);3687context->err_code = CC_OutOfMemory;3688longjmp(context->jump_buffer, 1);3689}36903691static void3692CFerror(context_type *context, char *format, ...)3693{3694int n = print_CCerror_info(context);3695va_list args;3696if (n >= 0 && n < context->message_buf_len) {3697va_start(args, format);3698jio_vsnprintf(context->message + n, context->message_buf_len - n,3699format, args);3700va_end(args);3701}3702context->err_code = CC_ClassFormatError;3703longjmp(context->jump_buffer, 1);3704}37053706/*3707* Need to scan the entire signature to find the result type because3708* types in the arg list and the result type could contain embedded ')'s.3709*/3710static const char* get_result_signature(const char* signature) {3711const char *p;3712for (p = signature; *p != JVM_SIGNATURE_ENDFUNC; p++) {3713switch (*p) {3714case JVM_SIGNATURE_BOOLEAN:3715case JVM_SIGNATURE_BYTE:3716case JVM_SIGNATURE_CHAR:3717case JVM_SIGNATURE_SHORT:3718case JVM_SIGNATURE_INT:3719case JVM_SIGNATURE_FLOAT:3720case JVM_SIGNATURE_DOUBLE:3721case JVM_SIGNATURE_LONG:3722case JVM_SIGNATURE_FUNC: /* ignore initial (, if given */3723break;3724case JVM_SIGNATURE_CLASS:3725while (*p != JVM_SIGNATURE_ENDCLASS) p++;3726break;3727case JVM_SIGNATURE_ARRAY:3728while (*p == JVM_SIGNATURE_ARRAY) p++;3729/* If an array of classes, skip over class name, too. */3730if (*p == JVM_SIGNATURE_CLASS) {3731while (*p != JVM_SIGNATURE_ENDCLASS) p++;3732}3733break;3734default:3735/* Indicate an error. */3736return NULL;3737}3738}3739return p++; /* skip over ')'. */3740}37413742static char3743signature_to_fieldtype(context_type *context,3744const char **signature_p, fullinfo_type *full_info_p)3745{3746const char *p = *signature_p;3747fullinfo_type full_info = MAKE_FULLINFO(ITEM_Bogus, 0, 0);3748char result;3749int array_depth = 0;37503751for (;;) {3752switch(*p++) {3753default:3754result = 0;3755break;37563757case JVM_SIGNATURE_BOOLEAN:3758full_info = (array_depth > 0)3759? MAKE_FULLINFO(ITEM_Boolean, 0, 0)3760: MAKE_FULLINFO(ITEM_Integer, 0, 0);3761result = 'I';3762break;37633764case JVM_SIGNATURE_BYTE:3765full_info = (array_depth > 0)3766? MAKE_FULLINFO(ITEM_Byte, 0, 0)3767: MAKE_FULLINFO(ITEM_Integer, 0, 0);3768result = 'I';3769break;37703771case JVM_SIGNATURE_CHAR:3772full_info = (array_depth > 0)3773? MAKE_FULLINFO(ITEM_Char, 0, 0)3774: MAKE_FULLINFO(ITEM_Integer, 0, 0);3775result = 'I';3776break;37773778case JVM_SIGNATURE_SHORT:3779full_info = (array_depth > 0)3780? MAKE_FULLINFO(ITEM_Short, 0, 0)3781: MAKE_FULLINFO(ITEM_Integer, 0, 0);3782result = 'I';3783break;37843785case JVM_SIGNATURE_INT:3786full_info = MAKE_FULLINFO(ITEM_Integer, 0, 0);3787result = 'I';3788break;37893790case JVM_SIGNATURE_FLOAT:3791full_info = MAKE_FULLINFO(ITEM_Float, 0, 0);3792result = 'F';3793break;37943795case JVM_SIGNATURE_DOUBLE:3796full_info = MAKE_FULLINFO(ITEM_Double, 0, 0);3797result = 'D';3798break;37993800case JVM_SIGNATURE_LONG:3801full_info = MAKE_FULLINFO(ITEM_Long, 0, 0);3802result = 'L';3803break;38043805case JVM_SIGNATURE_ARRAY:3806array_depth++;3807continue; /* only time we ever do the loop > 1 */38083809case JVM_SIGNATURE_CLASS: {3810char buffer_space[256];3811char *buffer = buffer_space;3812char *finish = strchr(p, JVM_SIGNATURE_ENDCLASS);3813int length;3814if (finish == NULL) {3815/* Signature must have ';' after the class name.3816* If it does not, return 0 and ITEM_Bogus in full_info. */3817result = 0;3818break;3819}3820assert(finish >= p);3821length = (int)(finish - p);3822if (length + 1 > (int)sizeof(buffer_space)) {3823buffer = calloc(length + 1, sizeof(char));3824check_and_push(context, buffer, VM_MALLOC_BLK);3825}3826memcpy(buffer, p, length);3827buffer[length] = '\0';3828full_info = make_class_info_from_name(context, buffer);3829result = 'A';3830p = finish + 1;3831if (buffer != buffer_space)3832pop_and_free(context);3833break;3834}3835} /* end of switch */3836break;3837}3838*signature_p = p;3839if (array_depth == 0 || result == 0) {3840/* either not an array, or result is bogus */3841*full_info_p = full_info;3842return result;3843} else {3844if (array_depth > MAX_ARRAY_DIMENSIONS)3845CCerror(context, "Array with too many dimensions");3846*full_info_p = MAKE_FULLINFO(GET_ITEM_TYPE(full_info),3847array_depth,3848GET_EXTRA_INFO(full_info));3849return 'A';3850}3851}385238533854/* Given an array type, create the type that has one less level of3855* indirection.3856*/38573858static fullinfo_type3859decrement_indirection(fullinfo_type array_info)3860{3861if (array_info == NULL_FULLINFO) {3862return NULL_FULLINFO;3863} else {3864int type = GET_ITEM_TYPE(array_info);3865int indirection = GET_INDIRECTION(array_info) - 1;3866int extra_info = GET_EXTRA_INFO(array_info);3867if ( (indirection == 0)3868&& ((type == ITEM_Short || type == ITEM_Byte || type == ITEM_Boolean || type == ITEM_Char)))3869type = ITEM_Integer;3870return MAKE_FULLINFO(type, indirection, extra_info);3871}3872}387338743875/* See if we can assign an object of the "from" type to an object3876* of the "to" type.3877*/38783879static jboolean isAssignableTo(context_type *context,3880fullinfo_type from, fullinfo_type to)3881{3882return (merge_fullinfo_types(context, from, to, JNI_TRUE) == to);3883}38843885/* Given two fullinfo_type's, find their lowest common denominator. If3886* the assignable_p argument is non-null, we're really just calling to find3887* out if "<target> := <value>" is a legitimate assignment.3888*3889* We treat all interfaces as if they were of type java/lang/Object, since the3890* runtime will do the full checking.3891*/3892static fullinfo_type3893merge_fullinfo_types(context_type *context,3894fullinfo_type value, fullinfo_type target,3895jboolean for_assignment)3896{3897JNIEnv *env = context->env;3898if (value == target) {3899/* If they're identical, clearly just return what we've got */3900return value;3901}39023903/* Both must be either arrays or objects to go further */3904if (GET_INDIRECTION(value) == 0 && GET_ITEM_TYPE(value) != ITEM_Object)3905return MAKE_FULLINFO(ITEM_Bogus, 0, 0);3906if (GET_INDIRECTION(target) == 0 && GET_ITEM_TYPE(target) != ITEM_Object)3907return MAKE_FULLINFO(ITEM_Bogus, 0, 0);39083909/* If either is NULL, return the other. */3910if (value == NULL_FULLINFO)3911return target;3912else if (target == NULL_FULLINFO)3913return value;39143915/* If either is java/lang/Object, that's the result. */3916if (target == context->object_info)3917return target;3918else if (value == context->object_info) {3919/* Minor hack. For assignments, Interface := Object, return Interface3920* rather than Object, so that isAssignableTo() will get the right3921* result. */3922if (for_assignment && (WITH_ZERO_EXTRA_INFO(target) ==3923MAKE_FULLINFO(ITEM_Object, 0, 0))) {3924jclass cb = object_fullinfo_to_classclass(context,3925target);3926int is_interface = cb && JVM_IsInterface(env, cb);3927if (is_interface)3928return target;3929}3930return value;3931}3932if (GET_INDIRECTION(value) > 0 || GET_INDIRECTION(target) > 0) {3933/* At least one is an array. Neither is java/lang/Object or NULL.3934* Moreover, the types are not identical.3935* The result must either be Object, or an array of some object type.3936*/3937fullinfo_type value_base, target_base;3938int dimen_value = GET_INDIRECTION(value);3939int dimen_target = GET_INDIRECTION(target);39403941if (target == context->cloneable_info ||3942target == context->serializable_info) {3943return target;3944}39453946if (value == context->cloneable_info ||3947value == context->serializable_info) {3948return value;3949}39503951/* First, if either item's base type isn't ITEM_Object, promote it up3952* to an object or array of object. If either is elemental, we can3953* punt.3954*/3955if (GET_ITEM_TYPE(value) != ITEM_Object) {3956if (dimen_value == 0)3957return MAKE_FULLINFO(ITEM_Bogus, 0, 0);3958dimen_value--;3959value = MAKE_Object_ARRAY(dimen_value);39603961}3962if (GET_ITEM_TYPE(target) != ITEM_Object) {3963if (dimen_target == 0)3964return MAKE_FULLINFO(ITEM_Bogus, 0, 0);3965dimen_target--;3966target = MAKE_Object_ARRAY(dimen_target);3967}3968/* Both are now objects or arrays of some sort of object type */3969value_base = WITH_ZERO_INDIRECTION(value);3970target_base = WITH_ZERO_INDIRECTION(target);3971if (dimen_value == dimen_target) {3972/* Arrays of the same dimension. Merge their base types. */3973fullinfo_type result_base =3974merge_fullinfo_types(context, value_base, target_base,3975for_assignment);3976if (result_base == MAKE_FULLINFO(ITEM_Bogus, 0, 0))3977/* bogus in, bogus out */3978return result_base;3979return MAKE_FULLINFO(ITEM_Object, dimen_value,3980GET_EXTRA_INFO(result_base));3981} else {3982/* Arrays of different sizes. If the smaller dimension array's base3983* type is java/lang/Cloneable or java/io/Serializable, return it.3984* Otherwise return java/lang/Object with a dimension of the smaller3985* of the two */3986if (dimen_value < dimen_target) {3987if (value_base == context->cloneable_info ||3988value_base == context ->serializable_info) {3989return value;3990}3991return MAKE_Object_ARRAY(dimen_value);3992} else {3993if (target_base == context->cloneable_info ||3994target_base == context->serializable_info) {3995return target;3996}3997return MAKE_Object_ARRAY(dimen_target);3998}3999}4000} else {4001/* Both are non-array objects. Neither is java/lang/Object or NULL */4002jclass cb_value, cb_target, cb_super_value, cb_super_target;4003fullinfo_type result_info;40044005/* Let's get the classes corresponding to each of these. Treat4006* interfaces as if they were java/lang/Object. See hack note above. */4007cb_target = object_fullinfo_to_classclass(context, target);4008if (cb_target == 0)4009return MAKE_FULLINFO(ITEM_Bogus, 0, 0);4010if (JVM_IsInterface(env, cb_target))4011return for_assignment ? target : context->object_info;4012cb_value = object_fullinfo_to_classclass(context, value);4013if (cb_value == 0)4014return MAKE_FULLINFO(ITEM_Bogus, 0, 0);4015if (JVM_IsInterface(env, cb_value))4016return context->object_info;40174018/* If this is for assignment of target := value, we just need to see if4019* cb_target is a superclass of cb_value. Save ourselves a lot of4020* work.4021*/4022if (for_assignment) {4023cb_super_value = (*env)->GetSuperclass(env, cb_value);4024while (cb_super_value != 0) {4025jclass tmp_cb;4026if ((*env)->IsSameObject(env, cb_super_value, cb_target)) {4027(*env)->DeleteLocalRef(env, cb_super_value);4028return target;4029}4030tmp_cb = (*env)->GetSuperclass(env, cb_super_value);4031(*env)->DeleteLocalRef(env, cb_super_value);4032cb_super_value = tmp_cb;4033}4034(*env)->DeleteLocalRef(env, cb_super_value);4035return context->object_info;4036}40374038/* Find out whether cb_value or cb_target is deeper in the class4039* tree by moving both toward the root, and seeing who gets there4040* first. */4041cb_super_value = (*env)->GetSuperclass(env, cb_value);4042cb_super_target = (*env)->GetSuperclass(env, cb_target);4043while((cb_super_value != 0) &&4044(cb_super_target != 0)) {4045jclass tmp_cb;4046/* Optimization. If either hits the other when going up looking4047* for a parent, then might as well return the parent immediately */4048if ((*env)->IsSameObject(env, cb_super_value, cb_target)) {4049(*env)->DeleteLocalRef(env, cb_super_value);4050(*env)->DeleteLocalRef(env, cb_super_target);4051return target;4052}4053if ((*env)->IsSameObject(env, cb_super_target, cb_value)) {4054(*env)->DeleteLocalRef(env, cb_super_value);4055(*env)->DeleteLocalRef(env, cb_super_target);4056return value;4057}4058tmp_cb = (*env)->GetSuperclass(env, cb_super_value);4059(*env)->DeleteLocalRef(env, cb_super_value);4060cb_super_value = tmp_cb;40614062tmp_cb = (*env)->GetSuperclass(env, cb_super_target);4063(*env)->DeleteLocalRef(env, cb_super_target);4064cb_super_target = tmp_cb;4065}4066cb_value = (*env)->NewLocalRef(env, cb_value);4067cb_target = (*env)->NewLocalRef(env, cb_target);4068/* At most one of the following two while clauses will be executed.4069* Bring the deeper of cb_target and cb_value to the depth of the4070* shallower one.4071*/4072while (cb_super_value != 0) {4073/* cb_value is deeper */4074jclass cb_tmp;40754076cb_tmp = (*env)->GetSuperclass(env, cb_super_value);4077(*env)->DeleteLocalRef(env, cb_super_value);4078cb_super_value = cb_tmp;40794080cb_tmp = (*env)->GetSuperclass(env, cb_value);4081(*env)->DeleteLocalRef(env, cb_value);4082cb_value = cb_tmp;4083}4084while (cb_super_target != 0) {4085/* cb_target is deeper */4086jclass cb_tmp;40874088cb_tmp = (*env)->GetSuperclass(env, cb_super_target);4089(*env)->DeleteLocalRef(env, cb_super_target);4090cb_super_target = cb_tmp;40914092cb_tmp = (*env)->GetSuperclass(env, cb_target);4093(*env)->DeleteLocalRef(env, cb_target);4094cb_target = cb_tmp;4095}40964097/* Walk both up, maintaining equal depth, until a join is found. We4098* know that we will find one. */4099while (!(*env)->IsSameObject(env, cb_value, cb_target)) {4100jclass cb_tmp;4101cb_tmp = (*env)->GetSuperclass(env, cb_value);4102(*env)->DeleteLocalRef(env, cb_value);4103cb_value = cb_tmp;4104cb_tmp = (*env)->GetSuperclass(env, cb_target);4105(*env)->DeleteLocalRef(env, cb_target);4106cb_target = cb_tmp;4107}4108result_info = make_class_info(context, cb_value);4109(*env)->DeleteLocalRef(env, cb_value);4110(*env)->DeleteLocalRef(env, cb_super_value);4111(*env)->DeleteLocalRef(env, cb_target);4112(*env)->DeleteLocalRef(env, cb_super_target);4113return result_info;4114} /* both items are classes */4115}411641174118/* Given a fullinfo_type corresponding to an Object, return the jclass4119* of that type.4120*4121* This function always returns a global reference!4122*/41234124static jclass4125object_fullinfo_to_classclass(context_type *context, fullinfo_type classinfo)4126{4127unsigned short info = GET_EXTRA_INFO(classinfo);4128return ID_to_class(context, info);4129}41304131static void free_block(void *ptr, int kind)4132{4133switch (kind) {4134case VM_STRING_UTF:4135JVM_ReleaseUTF(ptr);4136break;4137case VM_MALLOC_BLK:4138free(ptr);4139break;4140}4141}41424143static void check_and_push(context_type *context, const void *ptr, int kind)4144{4145alloc_stack_type *p;4146if (ptr == 0)4147CCout_of_memory(context);4148if (context->alloc_stack_top < ALLOC_STACK_SIZE)4149p = &(context->alloc_stack[context->alloc_stack_top++]);4150else {4151/* Otherwise we have to malloc */4152p = malloc(sizeof(alloc_stack_type));4153if (p == 0) {4154/* Make sure we clean up. */4155free_block((void *)ptr, kind);4156CCout_of_memory(context);4157}4158}4159p->kind = kind;4160p->ptr = (void *)ptr;4161p->next = context->allocated_memory;4162context->allocated_memory = p;4163}41644165static void pop_and_free(context_type *context)4166{4167alloc_stack_type *p = context->allocated_memory;4168context->allocated_memory = p->next;4169free_block(p->ptr, p->kind);4170if (p < context->alloc_stack + ALLOC_STACK_SIZE &&4171p >= context->alloc_stack)4172context->alloc_stack_top--;4173else4174free(p);4175}41764177static int signature_to_args_size(const char *method_signature)4178{4179const char *p;4180int args_size = 0;4181for (p = method_signature; *p != JVM_SIGNATURE_ENDFUNC; p++) {4182switch (*p) {4183case JVM_SIGNATURE_BOOLEAN:4184case JVM_SIGNATURE_BYTE:4185case JVM_SIGNATURE_CHAR:4186case JVM_SIGNATURE_SHORT:4187case JVM_SIGNATURE_INT:4188case JVM_SIGNATURE_FLOAT:4189args_size += 1;4190break;4191case JVM_SIGNATURE_CLASS:4192args_size += 1;4193while (*p != JVM_SIGNATURE_ENDCLASS) p++;4194break;4195case JVM_SIGNATURE_ARRAY:4196args_size += 1;4197while ((*p == JVM_SIGNATURE_ARRAY)) p++;4198/* If an array of classes, skip over class name, too. */4199if (*p == JVM_SIGNATURE_CLASS) {4200while (*p != JVM_SIGNATURE_ENDCLASS)4201p++;4202}4203break;4204case JVM_SIGNATURE_DOUBLE:4205case JVM_SIGNATURE_LONG:4206args_size += 2;4207break;4208case JVM_SIGNATURE_FUNC: /* ignore initial (, if given */4209break;4210default:4211/* Indicate an error. */4212return 0;4213}4214}4215return args_size;4216}42174218#ifdef DEBUG42194220/* Below are for debugging. */42214222static void print_fullinfo_type(context_type *, fullinfo_type, jboolean);42234224static void4225print_stack(context_type *context, stack_info_type *stack_info)4226{4227stack_item_type *stack = stack_info->stack;4228if (stack_info->stack_size == UNKNOWN_STACK_SIZE) {4229jio_fprintf(stdout, "x");4230} else {4231jio_fprintf(stdout, "(");4232for ( ; stack != 0; stack = stack->next)4233print_fullinfo_type(context, stack->item,4234(jboolean)(verify_verbose > 1 ? JNI_TRUE : JNI_FALSE));4235jio_fprintf(stdout, ")");4236}4237}42384239static void4240print_registers(context_type *context, register_info_type *register_info)4241{4242int register_count = register_info->register_count;4243if (register_count == UNKNOWN_REGISTER_COUNT) {4244jio_fprintf(stdout, "x");4245} else {4246fullinfo_type *registers = register_info->registers;4247int mask_count = register_info->mask_count;4248mask_type *masks = register_info->masks;4249int i, j;42504251jio_fprintf(stdout, "{");4252for (i = 0; i < register_count; i++)4253print_fullinfo_type(context, registers[i],4254(jboolean)(verify_verbose > 1 ? JNI_TRUE : JNI_FALSE));4255jio_fprintf(stdout, "}");4256for (i = 0; i < mask_count; i++) {4257char *separator = "";4258int *modifies = masks[i].modifies;4259jio_fprintf(stdout, "<%d: ", masks[i].entry);4260for (j = 0;4261j < JVM_GetMethodIxLocalsCount(context->env,4262context->class,4263context->method_index);4264j++)4265if (IS_BIT_SET(modifies, j)) {4266jio_fprintf(stdout, "%s%d", separator, j);4267separator = ",";4268}4269jio_fprintf(stdout, ">");4270}4271}4272}427342744275static void4276print_flags(context_type *context, flag_type and_flags, flag_type or_flags)4277{4278if (and_flags != ((flag_type)-1) || or_flags != 0) {4279jio_fprintf(stdout, "<%x %x>", and_flags, or_flags);4280}4281}42824283static void4284print_fullinfo_type(context_type *context, fullinfo_type type, jboolean verbose)4285{4286int i;4287int indirection = GET_INDIRECTION(type);4288for (i = indirection; i-- > 0; )4289jio_fprintf(stdout, "[");4290switch (GET_ITEM_TYPE(type)) {4291case ITEM_Integer:4292jio_fprintf(stdout, "I"); break;4293case ITEM_Float:4294jio_fprintf(stdout, "F"); break;4295case ITEM_Double:4296jio_fprintf(stdout, "D"); break;4297case ITEM_Double_2:4298jio_fprintf(stdout, "d"); break;4299case ITEM_Long:4300jio_fprintf(stdout, "L"); break;4301case ITEM_Long_2:4302jio_fprintf(stdout, "l"); break;4303case ITEM_ReturnAddress:4304jio_fprintf(stdout, "a"); break;4305case ITEM_Object:4306if (!verbose) {4307jio_fprintf(stdout, "A");4308} else {4309unsigned short extra = GET_EXTRA_INFO(type);4310if (extra == 0) {4311jio_fprintf(stdout, "/Null/");4312} else {4313const char *name = ID_to_class_name(context, extra);4314const char *name2 = strrchr(name, '/');4315jio_fprintf(stdout, "/%s/", name2 ? name2 + 1 : name);4316}4317}4318break;4319case ITEM_Char:4320jio_fprintf(stdout, "C"); break;4321case ITEM_Short:4322jio_fprintf(stdout, "S"); break;4323case ITEM_Boolean:4324jio_fprintf(stdout, "Z"); break;4325case ITEM_Byte:4326jio_fprintf(stdout, "B"); break;4327case ITEM_NewObject:4328if (!verbose) {4329jio_fprintf(stdout, "@");4330} else {4331int inum = GET_EXTRA_INFO(type);4332fullinfo_type real_type =4333context->instruction_data[inum].operand2.fi;4334jio_fprintf(stdout, ">");4335print_fullinfo_type(context, real_type, JNI_TRUE);4336jio_fprintf(stdout, "<");4337}4338break;4339case ITEM_InitObject:4340jio_fprintf(stdout, verbose ? ">/this/<" : "@");4341break;43424343default:4344jio_fprintf(stdout, "?"); break;4345}4346for (i = indirection; i-- > 0; )4347jio_fprintf(stdout, "]");4348}434943504351static void4352print_formatted_fieldname(context_type *context, int index)4353{4354JNIEnv *env = context->env;4355jclass cb = context->class;4356const char *classname = JVM_GetCPFieldClassNameUTF(env, cb, index);4357const char *fieldname = JVM_GetCPFieldNameUTF(env, cb, index);4358jio_fprintf(stdout, " <%s.%s>",4359classname ? classname : "", fieldname ? fieldname : "");4360JVM_ReleaseUTF(classname);4361JVM_ReleaseUTF(fieldname);4362}43634364static void4365print_formatted_methodname(context_type *context, int index)4366{4367JNIEnv *env = context->env;4368jclass cb = context->class;4369const char *classname = JVM_GetCPMethodClassNameUTF(env, cb, index);4370const char *methodname = JVM_GetCPMethodNameUTF(env, cb, index);4371jio_fprintf(stdout, " <%s.%s>",4372classname ? classname : "", methodname ? methodname : "");4373JVM_ReleaseUTF(classname);4374JVM_ReleaseUTF(methodname);4375}43764377#endif /*DEBUG*/437843794380