You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ml...@apache.org on 2007/07/16 08:44:56 UTC
svn commit: r556523 [3/4] - in /harmony/enhanced/drlvm/trunk:
build/make/components/vm/ vm/vmcore/src/verifier-3363/
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/Pass2.cpp
------------------------------------------------------------------------------
svn:executable = *
Added: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/Ver.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/Ver.cpp?view=auto&rev=556523
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/Ver.cpp (added)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/Ver.cpp Sun Jul 15 23:44:55 2007
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Loenko, Vladimir Molotkov
+ */
+
+
+
+#include <iostream>
+
+using namespace std;
+
+#include "verifier.h"
+#include "context.h"
+#include "time.h"
+
+using namespace CPVerifier;
+char err_message[5000];
+
+/**
+* Function provides initial verification of class.
+*
+* If when verifying the class a check of type "class A must be assignable to class B" needs to be done
+* and either A or B is not loaded at the moment then a constraint
+* "class A must be assignable to class B" is recorded into the classloader's data
+*/
+vf_Result
+vf_verify_class( class_handler klass, unsigned verifyAll, char **error )
+{
+ int index;
+ vf_Result result = VF_OK;
+
+ // Create context
+ vf_Context_t context(klass);
+
+ // Verify method
+ for( index = 0; index < class_get_method_number( klass ); index++ ) {
+ result = context.verify_method(class_get_method( klass, index ));
+
+ if (result != VF_OK) {
+ *error = &(err_message[0]);
+ method_handler method = class_get_method( klass, index );
+ sprintf(*error, "%s/%s%s, pass: %d, instr: %d, reason: %s", class_get_name( klass ), method_get_name( method ),
+ method_get_descriptor( method ), context.pass, context.processed_instruction, context.error_message );
+ break;
+ }
+ }
+
+ /**
+ * Set method constraints
+ */
+ context.set_class_constraints();
+
+ return result;
+} // vf_verify_class
+
+
+/**
+* Function verifies all the constraints "class A must be assignable to class B"
+* that are recorded into the classloader for the given class
+* If some class is not loaded yet -- load it now
+*/
+vf_Result
+vf_verify_class_constraints( class_handler klass, unsigned verifyAll, char **error )
+{
+
+ // get class loader of current class
+ classloader_handler class_loader = class_get_class_loader( klass );
+
+ // get class loader verify data
+ vf_ClassLoaderData_t *cl_data =
+ (vf_ClassLoaderData_t*)cl_get_verify_data_ptr( class_loader );
+
+ // check class loader data
+ if( cl_data == NULL ) {
+ // no constraint data
+ return VF_OK;
+ }
+
+ // get class hash and memory pool
+ vf_Hash_t *hash = cl_data->hash;
+
+ // get constraints for class
+ vf_HashEntry_t *hash_entry = hash->Lookup( class_get_name( klass ) );
+ if( !hash_entry || !hash_entry->data ) {
+ // no constraint data
+ return VF_OK;
+ }
+
+ // check method constraints
+ vf_TypeConstraint_t *constraint = (vf_TypeConstraint_t*)hash_entry->data;
+ for( ; constraint; constraint = constraint->next )
+ {
+ vf_Result result = vf_force_check_constraint( klass, constraint );
+ if( result != VF_OK ) {
+ *error = &(err_message[0]);
+ sprintf(*error, "constraint check failed, class: %s, source: %s, target: %s", class_get_name( klass ), constraint->source, constraint->target);
+ return result;
+ }
+ }
+
+ return VF_OK;
+} // vf_verify_method_constraints
+
+
+/**
+* Function releases verify data in class loader (used to store constraints)
+*/
+void
+vf_release_verify_data( void *data )
+{
+ vf_ClassLoaderData_t *cl_data = (vf_ClassLoaderData_t*)data;
+
+ delete cl_data->string;
+ delete cl_data->hash;
+ delete cl_data->pool;
+} // vf_release_verify_data
+
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/Ver.cpp
------------------------------------------------------------------------------
svn:executable = *
Added: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/context.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/context.h?view=auto&rev=556523
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/context.h (added)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/context.h Sun Jul 15 23:44:55 2007
@@ -0,0 +1,605 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Loenko, Vladimir Molotkov
+ */
+
+#ifndef __CONTEXT_H__
+#define __CONTEXT_H__
+
+#include <assert.h>
+#include <string.h>
+#include "verifier.h"
+#include "stackmap.h"
+#include "memory.h"
+#include "tpool.h"
+#include "instr_props.h"
+
+namespace CPVerifier {
+
+ //
+ // Context - main class of Type Checker
+ //
+
+ class vf_Context_t {
+ public:
+ vf_Context_t(class_handler _klass) :
+
+#pragma warning( push )
+#pragma warning( disable : 4355 )
+ k_class(_klass), tpool(this, 256),
+#pragma warning( pop )
+
+ constraintPool(), class_constraints(0)
+ {
+ k_major = class_get_version( _klass );
+ }
+
+ vf_Result verify_method(method_handler method);
+ void set_class_constraints();
+ Address processed_instruction;
+ int pass;
+
+ const char *error_message;
+ protected:
+ friend class vf_TypePool;
+
+ //class handler for the current class
+ class_handler k_class;
+
+ //major version of current class
+ unsigned short k_major;
+
+ //method handler for the method being verified
+ method_handler m_method;
+
+ //method's bytecode
+ unsigned char *m_bytecode;
+
+ //legth of the code in the method being verified
+ unsigned m_code_length;
+
+ //max number of locals for the method being verified (as recorded in the classfile)
+ unsigned m_max_locals;
+
+ //is the current method construcor (and current class in not a j.l.Object)?
+ bool m_is_constructor;
+
+ //m_max_locals or m_max_locals+1 if it's a constructor
+ unsigned m_stack_start;
+
+ //max stack size for the method being verified (as recorded in the classfile)
+ unsigned m_max_stack;
+
+ //number of exception handlers for the being verified (as recorded in the classfile)
+ unsigned short m_handlecount;
+
+ //stores constraints in the classloader for reuse in vf_verify_class_constraints()
+ vf_TypeConstraint_s *class_constraints;
+
+ //storage for these constraints. class-wide
+ //TODO: makes sense to unite it with tpool containing other class-wide data?
+ Memory constraintPool;
+
+
+ /*****************/
+
+ // method's return type
+ SmConstant return_type;
+
+ // various flags for all the method's bytecode instructions
+ InstrProps props;
+
+ // table used to get various info (type, length, etc) about possible bytecode instructions
+ static ParseInfo parseTable[255];
+
+ // current set of derived types
+ WorkmapHead *workmap;
+
+ // stack to push instrauctions like branch targets, etc to go thru the method. the stack is method-wide.
+ MarkableStack stack;
+
+ FastStack dead_code_stack;
+ bool dead_code_parsing;
+
+ static const short MARK_SUBROUTINE_DONE = -1;
+ public:
+ // basic storage for most of the method-wide data
+ Memory mem;
+ protected:
+
+ //basic storage for class-wide data, like mapping from Java classes to SmConstant types
+ vf_TypePool tpool;
+
+ /******* exception handling **********/
+
+ //flag array. if a local var i was changed by the previous instruction ==> changed_locals[i]=1, otherwise it's 0
+ byte *changed_locals;
+
+ //if there is at least one local changed
+ int locals_changed;
+
+ //if we don't know whether previous instruction changed locals (like if we are at the branch target)
+ int no_locals_info;
+
+ //number of the first handler valid for the given instruction
+ int loop_start;
+
+ //<number of the last handler valid for the given instruction> + 1
+ int loop_finish;
+
+ //start of the nearest next try block. 0 means "don't know"
+ Address next_start_pc;
+
+ /*****************/
+
+ //report verify error and store a message if any
+ vf_Result error(vf_Result result, const char* message) {
+ error_message = message ? message : "";
+ //assert(0);
+ return result;
+ }
+
+ //init method-wide data
+ void init(method_handler _m_method) {
+ //store method's parameters
+ //TODO: it might be mot slower not to store them
+ m_method = _m_method;
+ m_max_locals = method_get_max_local( m_method );
+ m_max_stack = method_get_max_stack( m_method );
+ m_code_length = method_get_code_length( m_method );
+ m_handlecount = method_get_exc_handler_number( m_method );
+ m_bytecode = method_get_bytecode( m_method );
+
+ m_is_constructor = !strcmp(method_get_name(m_method), "<init>")
+ && class_get_super_class(k_class);
+
+ m_stack_start = m_max_locals + (m_is_constructor ? 1 : 0);
+
+ // initialize own parameters
+ mem.init();
+ props.init(mem, m_code_length);
+
+ stack.init();
+ dead_code_stack.init();
+
+ changed_locals = (byte*)mem.malloc((m_stack_start & ~3) + 4);
+
+ //to correct it later
+ return_type = SM_TOP;
+ }
+
+ // load derived types previously stored for the given instruction
+ void fill_workmap(Address instr) {
+ PropsHead *head = props.getInstrProps(instr);
+ if( head->is_workmap() ) {
+ tc_memcpy(workmap, head->getWorkmap(), sizeof(WorkmapHead) + sizeof(WorkmapElement) * (m_stack_start + head->workmap.depth));
+ } else {
+ StackmapHead *stackmap = head->getStackmap();
+
+ workmap->depth = stackmap->depth;
+
+ for( unsigned i = 0; i < m_stack_start + stackmap->depth; i++) {
+ workmap->elements[i] = _WorkmapElement(&stackmap->elements[i]);
+ assert( workmap->elements[i].getAnyPossibleValue() != SM_TOP );
+ }
+ }
+ no_locals_info = 1;
+ }
+
+ //store a copy of the current workmap for another instruction (such as a branch target)
+ void storeWorkmapCopy(Address target) {
+ int sz = m_stack_start + workmap->depth;
+ PropsHead* copy = newWorkmap(sz);
+ tc_memcpy(copy->getWorkmap(), workmap, sizeof(WorkmapHead) + sizeof(WorkmapElement) * sz);
+
+ props.setInstrProps(target, copy);
+ }
+
+ //create a stackmap vector of the given size sz (max_locals <= sz <= max_locals+max_stack)
+ PropsHead* newStackmap(int sz) {
+ return (PropsHead*)mem.calloc(sizeof(PropsHead) + sizeof(StackmapElement) * sz);
+ }
+
+ //create a workmap vector for the given size sz (max_locals <= sz <= max_locals+max_stack)
+ PropsHead *newWorkmap(int sz) {
+ PropsHead * ret = (PropsHead*)mem.malloc(sizeof(PropsHead) + sizeof(WorkmapElement) * sz);
+ ret->set_as_workmap();
+ return ret;
+ }
+
+ //create a vector that will be used for JSR procesing.
+ //It contains ether stackmap or workmap vector, SubrouitineData, and flags vector indicating
+ //changed locals
+ PropsHead *newRetData() {
+ assert( sizeof(StackmapElement) >= sizeof(WorkmapElement) );
+
+ int sz = sizeof(PropsHead) + sizeof(StackmapElement) * (m_max_stack + m_stack_start) + //stackmap
+ ((sizeof(SubroutineData)+ m_stack_start) & (~3)) + 4; // fixed data and changed locals vector
+
+ PropsHead * ret = (PropsHead *) mem.calloc(sz);
+ ret->set_as_workmap();
+ return ret;
+ }
+
+ //creates a temporary variable for converting
+ StackmapElement *new_variable() {
+ return (StackmapElement *)mem.calloc(sizeof(StackmapElement));
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ //First verification pass thru the method. checks that no jump outside the method or to the middle of instruction
+ //checks that opcodes are valid
+ vf_Result parse(Address instr);
+
+ //Second pass: dataflow of a piece of the method starting from the beginning or a branch target and finishing
+ //on return, athrow or hitting previously passed instruction.
+ //This function initializes workmap and calls DataflowLoop
+ vf_Result StartLinearDataflow(Address start);
+
+ //Second pass: Finilize subroutie processing -- once we are here, then all the RETs from achievable for
+ //the given subroutine are passed, so we can resume passing for JSRs to the given address
+ //This function initializes workmap properly and calls DataflowLoop
+ vf_Result SubroutineDone(Address start);
+
+ //Second pass: dataflow of a piece of the method starting from the beginning or a branch target and finishing
+ //on return, athrow or hitting previously passed instruction
+ vf_Result DataflowLoop(Address start, int workmap_is_a_copy_of_stackmap);
+
+ //Second pass: check type-safety of a single instruction
+ vf_Result dataflow_instruction(Address instr);
+
+ //Second pass: check type-safety for exception handlers of a single instruction
+ vf_Result dataflow_handlers(Address instr);
+
+ //specail care for <init> calls is in try blocks
+ vf_Result propagate_bogus_to_handlers(Address instr, SmConstant uninit_value);
+
+ //create constraint vector in case of a branch
+ //simple conatraints are created for pairs of both locals and stack (current must be assignable to target)
+ vf_Result new_generic_vector_constraint(Address target);
+
+ //create constraint vector for exception handler
+ //simple conatraints are created for pairs of local variable (current must be assignable to start of exception handler)
+ vf_Result new_handler_vector_constraint(Address handler);
+
+ //create simple single constraint: "'from' is assingable to 'to'"
+ vf_Result new_scalar_constraint(WorkmapElement *from, StackmapElement *to);
+
+ //create special type of conatraint: "'from' is an array and it's element is assignable to 'to'"
+ vf_Result new_scalar_array2ref_constraint(WorkmapElement *from, WorkmapElement *to);
+
+ //constraint propagation
+ vf_Result propagate(StackmapElement *changed, SmConstant new_value);
+
+ //update current derived types according to what was changed in subroutine
+ void restore_workmap_after_jsr(Address jsr_target);
+
+ //when we hit RET instruction we update the data for the given subroutine with current derived types
+ vf_Result vf_Context_t::new_ret_vector_constraint(Address target_instr);
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ //add one more possible value (type) that can come to the given point (local or stack)
+ vf_Result add_incoming_value(SmConstant new_value, StackmapElement *destination);
+
+ //returns stackmap for the 'instr' instruction
+ //if it does not exists yet -- create it. When created use 'depth' as stack depth
+ StackmapHead *getStackmap(Address instr, int depth) {
+ PropsHead *pro = props.getInstrProps(instr);
+ if( !pro ) {
+ pro = newStackmap(m_stack_start + depth);
+ props.setInstrProps(instr, pro);
+ pro->getStackmap()->depth = depth;
+ }
+ return pro->getStackmap();
+ }
+
+ //create stackmap for exception handler start
+ void createHandlerStackmap(Address handler_pc, SmConstant type) {
+ StackmapHead *map = getStackmap(handler_pc, 1);
+ //handler stackmaps are created before any dataflow analysis is done
+ assert(map->depth == 0 || map->depth == 1);
+ map->depth = 1;
+
+ vf_Result tcr = add_incoming_value(type, &map->elements[m_stack_start]);
+
+ // it is initialization stage
+ assert(tcr == VF_OK);
+ }
+
+
+ /////////////// set, get locals; push, pop stack; check... //////////////
+
+ //when exercizing instructions: POP operand from the stack
+ WorkmapElement workmap_pop() {
+ assert( workmap_can_pop(1) );
+ return workmap->elements[ (--workmap->depth) + m_stack_start ];
+ }
+
+ //looking the operand stack
+ WorkmapElement workmap_stackview(int depth) {
+ assert( depth >= 0 && workmap_can_pop(depth+1) );
+ return workmap->elements[ workmap->depth + m_stack_start - depth - 1];
+ }
+
+ //when exercizing instructions: PUSH operand to the stack
+ void workmap_push(WorkmapElement el) {
+ assert( workmap_can_push(1) );
+ workmap->elements[ (workmap->depth++) + m_stack_start ] = el;
+ }
+
+ //when exercizing instructions: PUSH a const (known) type to the stack (except long and double)
+ void workmap_push_const(SmConstant value) {
+ assert( workmap_can_push(1) );
+ workmap->elements[ workmap->depth + m_stack_start ] = _WorkmapElement(value);
+ workmap->depth++;
+ }
+
+ //when exercizing instructions: PUSH a const (known) long or double type to the stack
+ void workmap_2w_push_const(SmConstant value) {
+ workmap_push_const(SM_HIGH_WORD);
+ workmap_push_const(value);
+ }
+
+ //when exercizing instructions: check if the local idx is valid for long and double
+ bool workmap_valid_2w_local(unsigned idx) {
+ return workmap_valid_local(idx + 1);
+ }
+
+ //when exercizing instructions: check if the local idx is valid (except long and double)
+ bool workmap_valid_local(unsigned idx) {
+ return idx < m_max_locals;
+ }
+
+ //get local type by idx
+ WorkmapElement workmap_get_local(unsigned idx) {
+ assert( workmap_valid_local(idx) );
+ return workmap->elements[ idx ];
+ }
+
+ //set local type
+ void workmap_set_local(unsigned idx, WorkmapElement &el) {
+ assert( workmap_valid_local(idx) );
+
+ changed_locals[ idx ] = 1;
+ locals_changed = true;
+
+ el.setJsrModified();
+ workmap->elements[ idx ] = el;
+ }
+
+ //set local to a const (known) type except long and double
+ void workmap_set_local_const(unsigned idx, SmConstant value) {
+ assert( workmap_valid_local(idx) );
+
+ changed_locals[ idx ] = 1;
+ locals_changed = true;
+
+ workmap->elements[idx] = _WorkmapElement(value);
+
+ //don't need to set "jsr modified" flag for constants
+ //because they are already odd
+ assert(workmap->elements[idx].isJsrModified());
+ }
+
+ //set local to a const (known) long or double type
+ void workmap_set_2w_local_const(unsigned idx, SmConstant value) {
+ assert( workmap_valid_2w_local(idx) );
+ workmap_set_local_const(idx + 1, value);
+ workmap_set_local_const(idx, SM_HIGH_WORD);
+ }
+
+ //check whether we can pop 'number' elements from the operand stack
+ int workmap_can_pop(unsigned number) {
+ return workmap->depth >= number;
+ }
+
+ //check whether we can push 'number' elements to the operand stack
+ int workmap_can_push(unsigned number) {
+ return workmap->depth + number <= m_max_stack;
+ }
+
+ /////////////// expect some type //////////////
+
+ //expect exactly this type (or SM_TOP)
+ int workmap_expect_strict( WorkmapElement &el, SmConstant type ) {
+ assert(type != SM_BOGUS);
+
+ if( !el.isVariable() ) {
+ return type == el.getConst();
+ }
+
+ IncomingType *in = el.getVariable()->firstIncoming();
+ while( in ) {
+ if( type != in->value ) {
+ return false;
+ }
+ in = in->next();
+ }
+
+ ExpectedType *exp = el.getVariable()->firstExpected();
+ while( exp ) {
+ if( type == exp->value ) {
+ return true;
+ }
+ exp = exp->next();
+ }
+
+ el.getVariable()->newExpectedType(&mem, type);
+
+ return true;
+ }
+
+ int workmap_expect( WorkmapElement &el, SmConstant type ) {
+ if( !el.isVariable() ) {
+ return tpool.mustbe_assignable(el.getConst(), type);
+ } else {
+ ExpectedType* exp = el.getVariable()->firstExpected();
+ while( exp ) {
+ if( type == exp->value ) {
+ return true;
+ }
+ exp = exp->next();
+ }
+
+ IncomingType *in = el.getVariable()->firstIncoming();
+ //check that all existing incoming type are assignable to the new expected type
+ while( in ) {
+ if( !tpool.mustbe_assignable(in->value, type) ) {
+ return false;
+ }
+ in = in->next();
+ }
+ //add the new expected type
+ el.getVariable()->newExpectedType(&mem, type);
+ }
+ return true;
+ }
+
+ vf_Result create_method_initial_workmap();
+
+
+ //////////////// get constant SM_ELEMENTs ///////////////////////
+
+ //for given uninit_value create SmConstant for initialized value
+ //this function is used when <init>s and invoked
+ SmConstant sm_convert_to_initialized(SmConstant uninit_value) {
+ if( uninit_value == SM_THISUNINIT ) {
+ return tpool.sm_get_const_this();
+ }
+
+ if( uninit_value.isNewObject() ) {
+ Address addr = uninit_value.getNewInstr();
+
+ unsigned cp_idx = read_int16(m_bytecode + addr + 1);
+ SmConstant new_type;
+ if( !tpool.cpool_get_class(cp_idx, &new_type) ) {
+ assert(0);
+ return SM_BOGUS;
+ }
+ return new_type;
+ }
+
+ assert(0);
+ return SM_BOGUS;
+ }
+
+ //create vector constraints for each target of a switch
+ vf_Result processSwitchTarget(Address target) {
+ vf_Result tcr;
+ if( props.isMultiway(target) ) {
+ if( (tcr=new_generic_vector_constraint(target)) != VF_OK ) {
+ return tcr;
+ }
+
+ if( !props.isDataflowPassed(target) ) {
+ stack.xPush(target);
+ }
+ } else {
+ assert( !props.isDataflowPassed(target) );
+ storeWorkmapCopy(target);
+
+ stack.xPush(target);
+ }
+ return VF_OK;
+ }
+
+ /////////////////////// convinient methods //////////////////////////////////////////
+
+ //get length of variable size instruction (WIDE, *SWITCH)
+ int instr_get_len_compound(Address instr, OpCode opcode);
+
+ //read two-byte value
+ static int16 read_int16(byte* ptr) {
+ return (ptr[0] << 8) | ptr[1];
+ }
+
+ //read four-byte value
+ static int32 read_int32(byte* ptr) {
+ return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
+ }
+
+ //get properties specific for the given opcode
+ static ParseInfo &instr_get_parse_info(OpCode opcode) {
+ return parseTable[opcode];
+ }
+
+ //get the length of the given instruction or minimal length if unknown
+ static byte instr_get_minlen(ParseInfo &pi) {
+ return pi.instr_min_len;
+ }
+
+ //whether this instruction GOTO, IF*, or JSR
+ static int instr_is_jump(ParseInfo &pi) {
+ return pi.flags & PI_JUMP;
+ }
+
+ //whether this instruction GOTO, RETURN, ATHROW, or RET
+ static int instr_direct(ParseInfo &pi) {
+ return pi.flags & PI_DIRECT;
+ }
+
+ //whether this instruction a *SWITCH
+ static int instr_is_switch(ParseInfo &pi) {
+ return pi.flags & PI_SWITCH;
+ }
+
+ //other types of instructions
+ static int instr_is_regular(ParseInfo &pi) {
+ return !(pi.flags & (PI_SWITCH|PI_JUMP|PI_DIRECT));
+ }
+
+ //whether instruction length is unknown
+ static int instr_is_compound(OpCode opcode, ParseInfo &pi) {
+ return (pi.flags & PI_SWITCH) || opcode == OP_WIDE;
+ }
+
+ //JSR ?
+ static int instr_is_jsr(OpCode opcode) {
+ return opcode == OP_JSR || opcode == OP_JSR_W;
+ }
+
+ //RET ?
+ static int instr_is_ret(OpCode opcode, byte* code, Address instr) {
+ return opcode == OP_RET || opcode == OP_WIDE && code[instr + 1] == OP_RET;
+ }
+
+ //return the jump target for the given instruction
+ static Address instr_get_jump_target(ParseInfo &pi, byte* code, Address instr) {
+ if( pi.flags & PI_WIDEJUMP ) {
+ return instr + read_int32(code + instr + 1);
+ } else {
+ return instr + read_int16(code + instr + 1);
+ }
+ }
+
+ //is this opcode valid?
+ static int instr_is_valid_bytecode(OpCode opcode) {
+ return opcode <= OP_MAXCODE && opcode != OP_XXX_UNUSED_XXX;
+ }
+ };
+
+ //check conatraints stored in the classloader data. force loading if necessary
+ vf_Result
+ vf_force_check_constraint(class_handler klass,
+ vf_TypeConstraint_t *constraint);
+
+} // namespace CPVerifier
+
+#endif
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/context.h
------------------------------------------------------------------------------
svn:executable = *
Added: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/instr_props.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/instr_props.h?view=auto&rev=556523
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/instr_props.h (added)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/instr_props.h Sun Jul 15 23:44:55 2007
@@ -0,0 +1,395 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Loenko, Vladimir Molotkov
+ */
+
+#ifndef __INSTR_PROPS_H_
+#define __INSTR_PROPS_H_
+
+#include <assert.h>
+#include "stackmap.h"
+
+namespace CPVerifier {
+
+ //store flags and properties (stackmaps, workmaps, etc) for each instruction
+ class InstrProps {
+ private:
+ //array of bit flags
+ byte* packed_flags;
+
+ //hash table to store data for instructions
+ PropsHead **propHashTable;
+
+ //storage for all the data
+ Memory *memory;
+
+ //to avoid divisions we do bit AND with hash_mask when looking a starting index in hash table list
+ int hash_mask;
+
+ //returns flags for the instruction 'instr'. other bits are not necessary 0s
+ int get_dirty_mask(Address instr) {
+ int b = packed_flags[instr/4];
+ b = b >> ((instr % 4) * 2);
+ return b;
+ }
+
+ //bit OR flags for the instruction 'instr' with 'mask'
+ void fill_mask(Address instr, int mask) {
+ assert((mask & ~3) == 0);
+ mask = mask << ((instr % 4) * 2);
+
+ packed_flags[instr/4] |= mask;
+ }
+
+ //clears bits the are set in the 'mask' (& ~mask) for the instruction 'instr'
+ void clear_mask(Address instr, int mask) {
+ assert((mask & ~3) == 0);
+ mask = mask << (instr % 4) * 2;
+
+ packed_flags[instr/4] &= ~mask;
+ }
+
+ public:
+ //initializes the class. this function is invoked once per method - removes old data in initializes storages.
+ void init(Memory &mem, int code_len) {
+ memory = &mem;
+ packed_flags = (byte*)mem.calloc( ((code_len/4) & ~3) + 4);
+
+ //calcluate hash_size
+ int hash_size = 16;
+ int clen = code_len >> 8;
+ while( clen ) {
+ hash_size = hash_size << 1;
+ clen = clen >> 1;
+ }
+
+ hash_mask = hash_size - 1;
+ propHashTable = (PropsHead**)mem.calloc(hash_size * sizeof(PropsHead*));
+ }
+
+ //pass1: 00 - new (or dead code), 01 - parsed, 10 - middle of instruction, 11 - 'special' parsed (special == has stackmap)
+ //returns 1 if mask is 01 (parsed) or 11 ('special' parsed special == has stackmap)
+ int isParsePassed(Address instr) {
+ return get_dirty_mask(instr) & 1;
+ }
+
+ //pass1: 00 - new (or dead code), 01 - parsed, 10 - middle of instruction, 11 - 'special' parsed (special == has stackmap)
+ //returns 1 if mask is 10 (middle of instruction)
+ int isOperand(Address instr) {
+ return (get_dirty_mask(instr) & 3) == 2;
+ }
+
+ //pass1: 00 - new (or dead code), 01 - parsed, 10 - middle of instruction, 11 - 'special' parsed (special == has stackmap)
+ //setls low mask bit to 1
+ void setParsePassed(Address instr) {
+ fill_mask(instr, 1);
+ }
+
+ //pass1: 00 - new (or dead code), 01 - parsed, 10 - middle of instruction, 11 - 'special' parsed (special == has stackmap)
+ //sets mask to 10
+ int setOperand(Address instr) {
+ int idx = instr/4;
+ int shift = ((instr % 4) * 2);
+
+ int mask01 = 1 << shift;
+ int mask10 = 2 << shift;
+
+ //is an instruction
+ if( packed_flags[idx] & mask01 ) return 0;
+
+ //mark as a middle
+ packed_flags[idx] |= mask10;
+ return 1;
+ }
+
+ //pass1: 00 - new (or dead code), 01 - parsed, 10 - middle of instruction, 11 - 'special' parsed (special == has stackmap)
+ //set mask to 11
+ void setMultiway(Address instr) {
+ fill_mask(instr, 3);
+ }
+
+ //pass2: 01 - new, 11 - special, 00 - passed (or unused), 10 - special passed (or unused)
+ //for all instructions (except unuzed) returns 1 if it's 'passed' or 'special passed'
+ //return 0 otherwise
+ int isDataflowPassed(Address instr) {
+ return !(get_dirty_mask(instr) & 1);
+ }
+
+ //return 1 for special and special passed instructions (instructions that are achievable by multiple passes)
+ int isMultiway(Address instr) { //II_MULTIWAY
+ return get_dirty_mask(instr) & 2;
+ }
+
+ //mark instruction as passed
+ void setDataflowPassed(Address instr) {
+ clear_mask(instr, 1);
+ }
+
+ ////////////////////////////////////////////////////////setting getting properties
+
+ //return properties for the given instruction
+ PropsHead* getInstrProps(Address instr) {
+ PropsHead *pro = propHashTable[instr & hash_mask];
+ while( pro && pro->instr != instr ) {
+ pro = pro->next;
+ }
+ return pro;
+ }
+
+ //sets properties for the given instruction
+ void setInstrProps(Address instr, PropsHead *map) {
+ //properties for the instruction don't exit yet
+ assert(!getInstrProps(instr));
+
+ int hash = instr & hash_mask;
+ map->next = propHashTable[hash];
+ map->instr = instr;
+ propHashTable[hash] = map;
+
+ }
+ };
+
+ //
+ // instruction's possible characteristics (flags)
+ //
+ const byte PI_JUMP = 1;
+ const byte PI_WIDEJUMP = 2;
+ const byte PI_DIRECT = 4;
+ const byte PI_SWITCH = 8;
+ const byte PI_CANWIDE = 16;
+
+ struct ParseInfo {
+ byte instr_min_len; // length of the instruction with operands
+ byte flags; // union of appropriate masks, see above
+ };
+
+
+ //
+ // instruction's opcodes
+ //
+ enum OpCode {
+ OP_AALOAD = 0x32,
+ OP_AASTORE = 0x53,
+ OP_ACONST_NULL = 0x01,
+ OP_ALOAD = 0x19,
+ OP_ALOAD_0 = 0x2a,
+ OP_ALOAD_1 = 0x2b,
+ OP_ALOAD_2 = 0x2c,
+ OP_ALOAD_3 = 0x2d,
+ OP_ANEWARRAY = 0xbd,
+ OP_ARETURN = 0xb0,
+ OP_ARRAYLENGTH = 0xbe,
+ OP_ASTORE = 0x3a,
+ OP_ASTORE_0 = 0x4b,
+ OP_ASTORE_1 = 0x4c,
+ OP_ASTORE_2 = 0x4d,
+ OP_ASTORE_3 = 0x4e,
+ OP_ATHROW = 0xbf,
+ OP_BALOAD = 0x33,
+ OP_BASTORE = 0x54,
+ OP_BIPUSH = 0x10,
+ OP_CALOAD = 0x34,
+ OP_CASTORE = 0x55,
+ OP_CHECKCAST = 0xc0,
+ OP_D2F = 0x90,
+ OP_D2I = 0x8e,
+ OP_D2L = 0x8f,
+ OP_DADD = 0x63,
+ OP_DALOAD = 0x31,
+ OP_DASTORE = 0x52,
+ OP_DCMPG = 0x98,
+ OP_DCMPL = 0x97,
+ OP_DCONST_0 = 0x0e,
+ OP_DCONST_1 = 0x0f,
+ OP_DDIV = 0x6f,
+ OP_DLOAD = 0x18,
+ OP_DLOAD_0 = 0x26,
+ OP_DLOAD_1 = 0x27,
+ OP_DLOAD_2 = 0x28,
+ OP_DLOAD_3 = 0x29,
+ OP_DMUL = 0x6b,
+ OP_DNEG = 0x77,
+ OP_DREM = 0x73,
+ OP_DRETURN = 0xaf,
+ OP_DSTORE = 0x39,
+ OP_DSTORE_0 = 0x47,
+ OP_DSTORE_1 = 0x48,
+ OP_DSTORE_2 = 0x49,
+ OP_DSTORE_3 = 0x4a,
+ OP_DSUB = 0x67,
+ OP_DUP = 0x59,
+ OP_DUP_X1 = 0x5a,
+ OP_DUP_X2 = 0x5b,
+ OP_DUP2 = 0x5c,
+ OP_DUP2_X1 = 0x5d,
+ OP_DUP2_X2 = 0x5e,
+ OP_F2D = 0x8d,
+ OP_F2I = 0x8b,
+ OP_F2L = 0x8c,
+ OP_FADD = 0x62,
+ OP_FALOAD = 0x30,
+ OP_FASTORE = 0x51,
+ OP_FCMPG = 0x96,
+ OP_FCMPL = 0x95,
+ OP_FCONST_0 = 0x0b,
+ OP_FCONST_1 = 0x0c,
+ OP_FCONST_2 = 0x0d,
+ OP_FDIV = 0x6e,
+ OP_FLOAD = 0x17,
+ OP_FLOAD_0 = 0x22,
+ OP_FLOAD_1 = 0x23,
+ OP_FLOAD_2 = 0x24,
+ OP_FLOAD_3 = 0x25,
+ OP_FMUL = 0x6a,
+ OP_FNEG = 0x76,
+ OP_FREM = 0x72,
+ OP_FRETURN = 0xae,
+ OP_FSTORE = 0x38,
+ OP_FSTORE_0 = 0x43,
+ OP_FSTORE_1 = 0x44,
+ OP_FSTORE_2 = 0x45,
+ OP_FSTORE_3 = 0x46,
+ OP_FSUB = 0x66,
+ OP_GETFIELD = 0xb4,
+ OP_GETSTATIC = 0xb2,
+ OP_GOTO = 0xa7,
+ OP_GOTO_W = 0xc8,
+ OP_I2B = 0x91,
+ OP_I2C = 0x92,
+ OP_I2D = 0x87,
+ OP_I2F = 0x86,
+ OP_I2L = 0x85,
+ OP_I2S = 0x93,
+ OP_IADD = 0x60,
+ OP_IALOAD = 0x2e,
+ OP_IAND = 0x7e,
+ OP_IASTORE = 0x4f,
+ OP_ICONST_0 = 0x03,
+ OP_ICONST_1 = 0x04,
+ OP_ICONST_2 = 0x05,
+ OP_ICONST_3 = 0x06,
+ OP_ICONST_4 = 0x07,
+ OP_ICONST_5 = 0x08,
+ OP_ICONST_M1 = 0x02,
+ OP_IDIV = 0x6c,
+ OP_IF_ACMPEQ = 0xa5,
+ OP_IF_ACMPNE = 0xa6,
+ OP_IF_ICMPEQ = 0x9f,
+ OP_IF_ICMPGE = 0xa2,
+ OP_IF_ICMPGT = 0xa3,
+ OP_IF_ICMPLE = 0xa4,
+ OP_IF_ICMPLT = 0xa1,
+ OP_IF_ICMPNE = 0xa0,
+ OP_IFEQ = 0x99,
+ OP_IFGE = 0x9c,
+ OP_IFGT = 0x9d,
+ OP_IFLE = 0x9e,
+ OP_IFLT = 0x9b,
+ OP_IFNE = 0x9a,
+ OP_IFNONNULL = 0xc7,
+ OP_IFNULL = 0xc6,
+ OP_IINC = 0x84,
+ OP_ILOAD = 0x15,
+ OP_ILOAD_0 = 0x1a,
+ OP_ILOAD_1 = 0x1b,
+ OP_ILOAD_2 = 0x1c,
+ OP_ILOAD_3 = 0x1d,
+ OP_IMUL = 0x68,
+ OP_INEG = 0x74,
+ OP_INSTANCEOF = 0xc1,
+ OP_INVOKEINTERFACE = 0xb9,
+ OP_INVOKESPECIAL = 0xb7,
+ OP_INVOKESTATIC = 0xb8,
+ OP_INVOKEVIRTUAL = 0xb6,
+ OP_IOR = 0x80,
+ OP_IREM = 0x70,
+ OP_IRETURN = 0xac,
+ OP_ISHL = 0x78,
+ OP_ISHR = 0x7a,
+ OP_ISTORE = 0x36,
+ OP_ISTORE_0 = 0x3b,
+ OP_ISTORE_1 = 0x3c,
+ OP_ISTORE_2 = 0x3d,
+ OP_ISTORE_3 = 0x3e,
+ OP_ISUB = 0x64,
+ OP_IUSHR = 0x7c,
+ OP_IXOR = 0x82,
+ OP_JSR = 0xa8,
+ OP_JSR_W = 0xc9,
+ OP_L2D = 0x8a,
+ OP_L2F = 0x89,
+ OP_L2I = 0x88,
+ OP_LADD = 0x61,
+ OP_LALOAD = 0x2f,
+ OP_LAND = 0x7f,
+ OP_LASTORE = 0x50,
+ OP_LCMP = 0x94,
+ OP_LCONST_0 = 0x09,
+ OP_LCONST_1 = 0x0a,
+ OP_LDC = 0x12,
+ OP_LDC_W = 0x13,
+ OP_LDC2_W = 0x14,
+ OP_LDIV = 0x6d,
+ OP_LLOAD = 0x16,
+ OP_LLOAD_0 = 0x1e,
+ OP_LLOAD_1 = 0x1f,
+ OP_LLOAD_2 = 0x20,
+ OP_LLOAD_3 = 0x21,
+ OP_LMUL = 0x69,
+ OP_LNEG = 0x75,
+ OP_LOOKUPSWITCH = 0xab,
+ OP_LOR = 0x81,
+ OP_LREM = 0x71,
+ OP_LRETURN = 0xad,
+ OP_LSHL = 0x79,
+ OP_LSHR = 0x7b,
+ OP_LSTORE = 0x37,
+ OP_LSTORE_0 = 0x3f,
+ OP_LSTORE_1 = 0x40,
+ OP_LSTORE_2 = 0x41,
+ OP_LSTORE_3 = 0x42,
+ OP_LSUB = 0x65,
+ OP_LUSHR = 0x7d,
+ OP_LXOR = 0x83,
+ OP_MONITORENTER = 0xc2,
+ OP_MONITOREXIT = 0xc3,
+ OP_MULTIANEWARRAY = 0xc5,
+ OP_NEW = 0xbb,
+ OP_NEWARRAY = 0xbc,
+ OP_NOP = 0x00,
+ OP_POP = 0x57,
+ OP_POP2 = 0x58,
+ OP_PUTFIELD = 0xb5,
+ OP_PUTSTATIC = 0xb3,
+ OP_RET = 0xa9,
+ OP_RETURN = 0xb1,
+ OP_SALOAD = 0x35,
+ OP_SASTORE = 0x56,
+ OP_SIPUSH = 0x11,
+ OP_SWAP = 0x5f,
+ OP_TABLESWITCH = 0xaa,
+ OP_WIDE = 0xc4,
+
+ OP_XXX_UNUSED_XXX = 0xba,
+ OP_MAXCODE = 0xc9,
+ };
+
+} // namespace CPVerifier
+
+
+#endif
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/instr_props.h
------------------------------------------------------------------------------
svn:executable = *
Added: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/stackmap.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/stackmap.h?view=auto&rev=556523
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/stackmap.h (added)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/stackmap.h Sun Jul 15 23:44:55 2007
@@ -0,0 +1,536 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Loenko, Vladimir Molotkov
+ */
+
+#ifndef __STACKMAP_H__
+#define __STACKMAP_H__
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "ver_utils.h"
+
+#ifdef WIN32
+#define intptr int64
+#else
+#define intptr long
+#endif
+
+namespace CPVerifier {
+
+ //predefined verification types
+ enum SmConstPredefined {
+ SM_TOP = 0,
+ SM_ONEWORDED = 1,
+ SM_REF_OR_UNINIT_OR_RETADR = 3,
+ SM_REF_OR_UNINIT = 5,
+ SM_THISUNINIT = 7,
+ SM_ANYARRAY = 9,
+ SM_NULL = 11,
+ SM_HIGH_WORD = 13,
+ SM_INTEGER = 15,
+ SM_FLOAT = 17,
+ SM_BOGUS = 19,
+ SM_LONG = 21,
+ SM_DOUBLE = 23,
+ };
+
+ //verification types with comparision operators
+ struct _SmConstant {
+ unsigned c;
+
+ int operator ==(_SmConstant other) {
+ return c == other.c;
+ }
+
+ int operator ==(unsigned other) {
+ return c == other;
+ }
+
+ int operator !=(_SmConstant other) {
+ return c != other.c;
+ }
+
+ int operator !=(unsigned other) {
+ return c != other;
+ }
+
+
+ };
+
+ //verification types with convinient functions
+ struct SmConstant : _SmConstant {
+ //all constants except SM_TOP must be odd
+
+ //default constructor
+ SmConstant() {}
+
+ //creating from unsigned
+ SmConstant(unsigned int other) {
+ c = other;
+ }
+
+ //copy constructor
+ SmConstant(const _SmConstant other) {
+ c = other.c;
+ }
+
+ ///////////////////////////////////////
+
+ //is it a RETADDR verification type? (that's pushed by JSR instructions)
+ int isRetAddr() {
+ return c & TYPE_RETADDR;
+ }
+
+ //is it a reference? (like Object)
+ int isReference() {
+ return c & TYPE_REFERENCE;
+ }
+
+ //is it a new object? (e.g. just created by 'new' instruction)
+ int isNewObject() {
+ return c & TYPE_NEWOBJECT;
+ }
+
+ //is it a primitive verification type? (e.g. int, long)
+ int isPrimitive() {
+ return !(c & (TYPE_NEWOBJECT | TYPE_REFERENCE | TYPE_RETADDR));
+ }
+
+ //is it a two-word type?
+ int isLongOrDouble() {
+ return c == SM_LONG || c == SM_DOUBLE;
+ }
+
+ //does merge with any other type results in SM_BOGUS?
+ int isNonMergeable() {
+ return (c & (TYPE_NEWOBJECT|TYPE_RETADDR)) || c == SM_THISUNINIT;
+ }
+
+ ///////////////////////////////////////
+
+ //for a reference: return class id in the table (see tpool)
+ int getReferenceIdx() {
+ assert(isReference());
+ return (c & ~TYPE_REFERENCE) >> 1;
+ }
+
+ //for 'new' type: return address of the 'new' instruction created this SmConstant
+ Address getNewInstr() {
+ assert(isNewObject());
+ return (c & ~TYPE_NEWOBJECT) >> 1;
+ }
+
+ //for RetAddress: return address of the subroutine start (i.e. target of JSR instruction)
+ //Note: this is different from what is recorded in RetAddress type when actual execution happens
+ Address getRetInstr() {
+ assert(isRetAddr());
+ return (c & ~TYPE_RETADDR) >> 1;
+ }
+
+ ///////////////////////////////////////
+
+ //create "new object" verification type corresponding to 'instr'
+ static SmConstant getNewObject(Address instr) {
+ return ((instr<<1) | (TYPE_NEWOBJECT | 1));
+ }
+
+ //create "ret address" verification type corresponding to subroutine startig at 'instr'
+ //Note: this is different from what is recorded in RetAddress type when actual execution happens
+ static SmConstant getRetAddr(Address instr) {
+ return ((instr<<1) | (TYPE_RETADDR | 1));
+ }
+
+ //create "object" verification type
+ static SmConstant getReference(unsigned idx) {
+ return ((idx<<1) | (TYPE_REFERENCE | 1));
+ }
+
+ ////////////////////////////////////////
+
+ static const unsigned TYPE_RETADDR = 0x2000000;
+ static const unsigned TYPE_REFERENCE = 0x4000000;
+ static const unsigned TYPE_NEWOBJECT = 0x8000000;
+
+ };
+
+ //possible relations between verificaton types
+ enum ConstraintType {
+ CT_GENERIC, // sub-defined type A is assignable to sub-defined type B
+ CT_ARRAY2REF, // A is a known-type array. element of A is assignable to sub-defined type B
+ CT_EXPECTED_TYPE, // sub-defined type A is assignable to known-type B
+ CT_INCOMING_VALUE // known-type A is assignable to sub-defined type B
+ };
+
+ struct StackmapHead;
+ struct WorkmapHead;
+ struct StackmapElement;
+
+ //structure for maintaining subroutine-specific data
+ //until subroutine is passed with the second (dataflow) pass we record to the wait list all JSR instructions
+ //calling this subroutine. Once the subroutine is over we continue 2nd pass for each wait-listed instruction
+ //see vf_Context_t::SubroutineDone
+ struct SubroutineData {
+ Address caller; //first JSR instruction that called this subroutine
+ short retCount; //number of ret instructions for this subroutine
+ byte subrDataflowed; // =1 if dataflow pass for the subroutine is over
+ };
+
+ //list constant verification type (i.e. known-type) that are assignable to some sub-definite type (i.e. StackMapElement)
+ //see StackmapElement
+ struct IncomingType {
+ //next in the list
+ IncomingType *nxt;
+
+ //value of the verification type recorded as int
+ //TODO: don't remember why it's 'int' rather than 'SmConstant'
+ int value;
+
+ //simple next in the list
+ IncomingType *next() {
+ return nxt;
+ }
+ };
+
+ //list of constraints for some sub-definite verification type (i.e. StackMapElement)
+ //see StackmapElement
+
+ struct Constraint {
+ //next in the list
+ Constraint *nxt;
+
+ //either
+ union {
+ StackmapElement *variable; // sub-definite verificarion type
+ int value; // or constant (known) verification type rcorded as int
+ };
+
+ //consatrint type
+ ConstraintType type;
+
+ //next constrait of type 't'
+ static Constraint *next(Constraint *cur, ConstraintType t) {
+ while( cur && cur->type != t ) {
+ cur = (Constraint*)cur->next();
+ }
+ return cur;
+ }
+
+ //simple next in the list
+ Constraint *next() {
+ return nxt;
+ }
+ };
+
+ //constraint of the CT_EXPECTED_TYPE type: sub-defined type A is assignable to known-type B
+ struct ExpectedType : Constraint {
+ ExpectedType *next() {
+ return (ExpectedType *) Constraint::next(Constraint::next(), CT_EXPECTED_TYPE);
+ }
+ };
+
+ //constraint of the CT_GENERIC type: sub-defined type A is assignable to sub-defined type B
+ struct GenericCnstr : Constraint {
+ GenericCnstr *next() {
+ return (GenericCnstr *) Constraint::next(Constraint::next(), CT_GENERIC);
+ }
+ };
+
+ //constraint of the CT_ARRAY2REF type: A is a known-type array. element of A is assignable to sub-defined type B
+ struct ArrayCnstr : Constraint {
+ //there can be only one CT_ARRAY2REF per StackMap Element
+ ArrayCnstr *next() {
+ assert(0);
+ return 0;
+ }
+ };
+
+
+ //StackMapElement structure represens sub-definite verification type: we don't know what type is it, but
+ //we know about instructions that expect ExpectedTypes here and we know that IncomingValues can be here
+ //we also know that this type must be assignable to other sub-defenite types as indicated by CT_GENERIC
+ //constrains and there can be special limitations represented by CT_ARRAY2REF constraints
+ struct StackmapElement { //TODO: should be rewritten to save footprint
+ //list of IncomingType constraint
+ IncomingType *incoming;
+
+ //list of all the conatraints of other types
+ Constraint *others;
+
+ //return value from any IncomingType constraint
+ //when we need to compae to some unmergable type we don;t need to interate thru the list
+ //also used to assert that an IncomingValue constraint exists
+ SmConstant getAnyIncomingValue() {
+ assert(firstIncoming());
+ return firstIncoming()->value;
+ }
+
+ //return first IncomingType constraint
+ IncomingType *firstIncoming() {
+ //TODO: I have to store somewhere the "modified" bit. Sorry.
+ return (IncomingType*)( (intptr)incoming & ~3 );
+ }
+
+ //return first conatrint of any type except IncomingType
+ Constraint *firstOthers() {
+ return others;
+ }
+
+ //return first CT_EXPECTED_TYPE constraint
+ ExpectedType *firstExpected() {
+ return (ExpectedType*)Constraint::next(others, CT_EXPECTED_TYPE);
+ }
+
+ //return first CT_GENERIC constraint
+ GenericCnstr *firstGenericCnstr() {
+ return (GenericCnstr*)Constraint::next(others, CT_GENERIC);
+ }
+
+ //return first (and the only) CT_ARRAY2REF constraint
+ ArrayCnstr *firstArrayCnstr() {
+ return (ArrayCnstr*)Constraint::next(others, CT_ARRAY2REF);
+ }
+
+ //clean-up
+ void init() {
+ incoming = 0;
+ others = 0;
+ }
+
+ //add incoming type with the 'value' value
+ void newIncomingType(Memory *mem, SmConstant value) {
+ IncomingType *in = (IncomingType *)mem->malloc(sizeof(IncomingType));
+
+ intptr mask = (intptr)incoming & 3;
+ incoming = (IncomingType *) ((intptr)incoming & ~3);
+
+ in->nxt = value == SM_BOGUS ? 0 : incoming;
+ //in->type = CT_INCOMING_VALUE;
+ in->value = value.c;
+
+ incoming = in;
+
+ incoming = (IncomingType *) ((intptr)incoming | mask);
+ }
+
+ //add expected type with the 'value' value
+ void newExpectedType(Memory *mem, SmConstant value) {
+ Constraint *o = (Constraint *)mem->malloc(sizeof(Constraint));
+
+ o->nxt = others;
+ o->type = CT_EXPECTED_TYPE;
+ o->value = value.c;
+
+ others = o;
+ }
+
+ //add generic constraint ('this' is assignable to 'to')
+ void newGenericConstraint(Memory *mem, StackmapElement *to) {
+ Constraint *o = (Constraint *)mem->malloc(sizeof(Constraint));
+
+ o->nxt = others;
+ o->type = CT_GENERIC;
+ o->variable = to;
+
+ others = o;
+ }
+
+ //add generic constraint ('this' is an array, which element is assignable to 'to')
+ void newArrayConversionConstraint(Memory *mem, StackmapElement *to) {
+ assert(!firstArrayCnstr());
+ Constraint *o = (Constraint *)mem->malloc(sizeof(Constraint));
+
+ //at most one array conversion constraint per variable is possible
+ o->nxt = others;
+ o->type = CT_ARRAY2REF;
+ o->variable = to;
+
+ others = o;
+ }
+
+ // return 'modified' flag for the stackmap. the flag is stored in the first bit of the 'incoming' pointer
+ // "modified" is about subroutines: you have to track which locals were changed
+ int isJsrModified() {
+ return (int)(intptr)incoming & 1;
+ }
+
+ //set 'modified' flag for the stackmap. the flag is stored in the first bit of the 'incoming' pointer
+ // "modified" is about subroutines: you have to track which locals were changed
+ void setJsrModified() {
+ incoming = (IncomingType *) ((intptr)incoming | 1);
+ }
+
+ //clear 'modified' flag for the stackmap. the flag is stored in the first bit of the 'incoming' pointer
+ // "modified" is about subroutines: you have to track which locals were changed
+ void clearJsrModified() {
+ incoming = (IncomingType *) ((intptr)incoming & ~1);
+ }
+ };
+
+ //WorkMapElement structure represent an element of the workmap vector -- vector of the derived types
+ //a type might be either constant (or known) (e.g. if some previous instruction has put something on stack or locals)
+ //or sub-definite (e.g. if we've recently passed a branch target and don't know which types were on stack or locals)
+ struct WorkmapElement {
+ //value. two low bits a used to store flags
+ union {
+ _SmConstant const_val; //either a constant (known-type)
+ StackmapElement *var_ptr; //or a variable (sub-definite type)
+ };
+
+ //is it a sub-definite (not constant) type?
+ int isVariable() {
+ assert(const_val != SM_TOP);
+ return !((intptr)var_ptr & 1);
+ }
+
+ //get value for the constant (known) verification type
+ SmConstant getConst() {
+ return const_val;
+ }
+
+ //get variable representing sub-definite verification type
+ StackmapElement *getVariable() {
+ return (StackmapElement *) ((intptr)var_ptr & ~3);
+ }
+
+ //when we need to compae to some unmergable type we don;t need to interate thru the list
+ //also used to assert that an IncomingValue constraint exists
+ SmConstant getAnyPossibleValue() {
+ SmConstant ret = isVariable() ? getVariable()->getAnyIncomingValue() : const_val;
+ assert(ret != SM_TOP);
+ return ret;
+ }
+
+ // return 'modified' flag for the workmap element. the flag is stored in the second bit of the union
+ //"modified" is about subroutines: you have to track which locals were changed
+ //it's easier to think of all the constants as "modified"
+ int isJsrModified() {
+ return (int)(intptr)var_ptr & 3;
+ }
+
+ // set 'modified' flag for the workmap element. the flag is stored in the second bit of the union
+ void setJsrModified() {
+ if( isVariable() ) {
+ var_ptr = (StackmapElement*)((intptr)var_ptr | 2);
+ }
+ }
+ };
+
+ //WorkmapElement type with some constructors
+ struct _WorkmapElement : WorkmapElement{
+ _WorkmapElement(WorkmapElement other) {
+ const_val = other.const_val;
+ }
+
+ _WorkmapElement(StackmapElement *s) {
+ var_ptr = s;
+ if( s->isJsrModified() ) {
+ setJsrModified();
+ }
+ }
+
+ _WorkmapElement(SmConstant c) {
+ const_val = c;
+ }
+ };
+
+#pragma warning( push )
+#pragma warning( disable : 4200 )
+
+ //vector of StackMap elements. the size is known at the moment of allocation
+ struct StackmapHead {
+ unsigned short depth;
+ StackmapElement elements[0];
+ };
+
+ //vector of WorkMap elements. the size is known at the moment of allocation
+ struct WorkmapHead {
+ unsigned short depth;
+ WorkmapElement elements[0];
+ };
+
+#pragma warning( pop )
+
+ //Store various data for the given instruction. Possible data are: StackMap vector, WorkMap vector,
+ //Subroutine-specific data
+ //for a single instruction it might be either
+ // 1) no data
+ // 2) workmap only
+ // 3) stackmap only
+ // 4) stackmap and subroutine data. in this case two PropsHead structures are created the first one for the StackMap,
+ // it's 'next' points to the second PropsHead containing Subroutine info. In this case second PropsHead keeps 0xFFFF
+ // instead of 'instr'
+ // the list is used to organize storing Props as a HashTable
+ struct PropsHead {
+ // Address of the instruction for which this properties are stored
+ // or 0xFFFF if this is a subroutine data for previous PropsHead
+ // TODO: if instr_flags are not optimized, introduce a 'subroutine data' flag and get rid of 0xFFFF instructions
+ Address instr;
+
+ //next property in the list
+ PropsHead* next;
+
+ // really one bit is used: FF_ISWORKMAP. TODO: merge with (Stack|Work)map->flags
+ unsigned short instr_flags;
+
+ //possible flag value
+ static const short FF_ISWORKMAP = 1;
+
+ //actual properties
+ union {
+ WorkmapHead workmap;
+ StackmapHead stackmap;
+ };
+
+ //get workmap stored here
+ WorkmapHead *getWorkmap() {
+ assert(is_workmap());
+ return &workmap;
+ }
+
+ //get stackmap stored here
+ StackmapHead *getStackmap() {
+ assert(!is_workmap());
+ return &stackmap;
+ }
+
+ //get subroutine data stored here
+ SubroutineData *getSubrData(int el_cnt) {
+ assert(instr == 0xFFFF);
+ return (SubroutineData *) &stackmap.elements[el_cnt];
+ }
+
+ //is it a workmap?
+ int is_workmap() {
+ return instr_flags & FF_ISWORKMAP;
+ }
+
+ //set 'is workmap' flag
+ void set_as_workmap() {
+ instr_flags |= FF_ISWORKMAP;
+ }
+
+ //clear flag
+ void clearInstrFlag(short flag) {
+ instr_flags &= ~flag;
+ }
+ };
+} // namespace CPVerifier
+
+#endif
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/stackmap.h
------------------------------------------------------------------------------
svn:executable = *
Added: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/tpool.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/tpool.cpp?view=auto&rev=556523
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/tpool.cpp (added)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/tpool.cpp Sun Jul 15 23:44:55 2007
@@ -0,0 +1,511 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Loenko, Vladimir Molotkov
+ */
+
+#include <assert.h>
+#include "tpool.h"
+#include "context.h"
+
+namespace CPVerifier {
+
+ vf_TypePool::vf_TypePool(vf_Context_t *_context, unsigned init_table_size)
+ : context(_context), k_class(_context->k_class), tableIncr(init_table_size),
+ tableSize(init_table_size), currentTypeId(0)
+ {
+ validTypes = (vf_ValidType *)tc_malloc(sizeof(vf_ValidType)*tableIncr);
+
+ const_object = const_class = const_string = const_throwable = const_arrayref_of_bb =
+ const_arrayref_of_char = const_arrayref_of_double = const_arrayref_of_float =
+ const_arrayref_of_integer = const_arrayref_of_long = const_arrayref_of_short =
+ const_arrayref_of_object = const_this = SM_TOP;
+
+ k_cp_length = class_get_cp_size( k_class );
+ }
+
+ /*
+ * Returns name length if it is array of boolean or 0
+ */
+ inline int vf_TypePool::is_bool_array_conv_needed(const char *type_name, int length) {
+ return length > 1 && type_name[length - 1] == 'Z' && type_name[length - 2] == '[';
+ }
+
+ /*
+ * Get SmConstant by type name.
+ */
+ SmConstant vf_TypePool::get_ref_type(const char *type_name, int length) {
+ assert(type_name[0] != 'L');
+
+ int index = -1;
+ // find type in hash
+ vf_HashEntry_t *entry = hash.NewHashEntry( type_name, length );
+ if( entry->data ) {
+ index = (int)((vf_ValidType*)entry->data - validTypes);
+ assert(index >= 0 && (unsigned)index < tableSize);
+ } else {
+ //convert array of booleans to array of bytes
+ if( is_bool_array_conv_needed(type_name, length) ) {
+ char *new_name = (char*)context->mem.malloc(length+1);
+ tc_memcpy(new_name, type_name, length);
+ new_name[length-1] = 'B';
+ index = get_ref_type(new_name, length).getReferenceIdx();
+ context->mem.dealloc_last(new_name, length+1);
+ }
+ // Get next free table entry index
+ if( index == -1 ) {
+ index = check_table();
+ (validTypes+index)->cls = 0;
+ (validTypes+index)->name = entry->key;
+ }
+ entry->data = (void*)(validTypes+index);
+ }
+ return SmConstant::getReference(index);
+ }
+
+ SmConstant vf_TypePool::get_primitive_type(const char type_char) {
+ switch( type_char ) {
+ case 'I':
+ case 'B':
+ case 'Z':
+ case 'C':
+ case 'S':
+ return SM_INTEGER;
+ case 'J':
+ return SM_LONG;
+ case 'F':
+ return SM_FLOAT;
+ case 'V':
+ return SM_BOGUS;
+ case 'D':
+ return SM_DOUBLE;
+ default:
+ assert(0);
+ return SM_BOGUS;
+ }
+ }
+
+ SmConstant vf_TypePool::get_type(const char *type_name, int name_len) {
+ if( name_len > 1 ) {
+ if( type_name[0] == '[' ) {
+ return get_ref_type(type_name, name_len);
+ }
+
+ if( type_name[0] == 'L' ) {
+ return get_ref_type(type_name + 1, name_len - 2);
+ }
+
+ return SM_BOGUS;
+ } else {
+ return get_primitive_type(type_name[0]);
+ }
+ }
+
+
+ SmConstant vf_TypePool::get_ref_from_array(SmConstant element) {
+ if( element == SM_NULL ) return SM_NULL;
+
+ assert(element.isReference());
+ assert(sm_get_refname(element)[0] == '[');
+ return get_type(sm_get_refname(element) + 1);
+ }
+
+
+ int vf_TypePool::mustbe_assignable(SmConstant from, SmConstant to) {
+ if( from == to || to == SM_TOP ) return true;
+ if( from == SM_BOGUS ) return false;
+
+ if( to.isReference() ) {
+ if( from == SM_NULL ) return true;
+
+ if( from.isReference() ) {
+ return ref_mustbe_assignable(from, to);
+ }
+
+ return false;
+ }
+
+ if( !to.isPrimitive() ) {
+ assert( to != from ); // checked above
+ return false;
+ }
+
+ //migth have to change switch below if merging is done with constants
+ assert( from != SM_TOP );
+ assert( from != SM_ONEWORDED );
+ assert( from != SM_REF_OR_UNINIT_OR_RETADR );
+ assert( from != SM_REF_OR_UNINIT );
+ assert( from != SM_ANYARRAY );
+ assert( from != SM_TOP );
+ assert( from != SM_BOGUS );
+
+ switch ( to.c ) {
+ case SM_ONEWORDED:
+ return !from.isLongOrDouble();
+
+ case SM_REF_OR_UNINIT_OR_RETADR:
+ return from == SM_NULL || from == SM_THISUNINIT || !from.isPrimitive();
+
+ case SM_REF_OR_UNINIT:
+ return from == SM_NULL || from == SM_THISUNINIT || from.isNewObject() || from.isReference();
+
+ case SM_ANYARRAY:
+ return from == SM_NULL || from.isReference() && sm_get_refname(from)[0] == '[';
+
+ case SM_NULL:
+ case SM_THISUNINIT:
+ assert(0);
+ return false;
+
+ case SM_HIGH_WORD:
+ case SM_INTEGER:
+ case SM_FLOAT:
+ case SM_LONG:
+ case SM_DOUBLE:
+ case SM_BOGUS:
+ return false;
+ default:
+ assert(0);
+ return false;
+ }
+ }
+
+ int vf_TypePool::ref_mustbe_assignable(SmConstant from, SmConstant to) {
+ if( to == sm_get_const_object() ) return true;
+
+ vf_ValidType *to_type = &validTypes[to.getReferenceIdx()];
+ vf_ValidType *from_type = &validTypes[from.getReferenceIdx()];
+
+ const char *to_name = to_type->name;
+ const char *from_name = from_type->name;
+
+ int to_array = to_name[0] == '[';
+ int from_array = from_name[0] == '[';
+
+ if( to_array && !from_array ) {
+ return false;
+ } else if( to_array && from_array ) {
+ int dim = 0;
+ while( to_name[dim] == '[' && from_name[dim] == '[' ) dim++;
+
+ if( from_name[dim] != 'L' && from_name[dim] != '[' ) {
+ //primitive type
+ dim--;
+ }
+
+ if( to_name[dim] != 'L' ) return false;
+
+ if( from_name[dim] == 'L' ) {
+ //merge refs
+ return ref_mustbe_assignable(get_type(from_name + dim), get_type(to_name + dim) );
+ } else {
+ //to must be Object or an interface
+ return ref_mustbe_assignable(sm_get_const_object(), get_type(to_name + dim) );
+ }
+ } else {
+ //check whether TO class is loaded
+ if( !to_type->cls ) {
+ to_type->cls = vf_resolve_class(k_class, to_type->name, false);
+ if( !to_type->cls ) to_type->cls = CLASS_NOT_LOADED;
+ }
+
+ if( to_type->cls && to_type->cls != CLASS_NOT_LOADED ) {
+ //if to is loaded and it is an interface, treat it as an object
+ if( class_is_interface_( to_type->cls ) ) {
+ return true;
+ }
+ } else {
+ NewConstraint(from_type->name, to_type->name);
+ return true;
+ }
+
+
+ //check whether FROM class is loaded
+
+ if( from_array ) from = sm_get_const_object();
+
+ if( !from_type->cls ) {
+ from_type->cls = vf_resolve_class(k_class, from_type->name, false);
+ if( !from_type->cls ) from_type->cls = CLASS_NOT_LOADED;
+ }
+
+ if( from_type->cls && from_type->cls != CLASS_NOT_LOADED ) {
+ return vf_is_valid(from_type->cls, to_type->cls);
+ } else {
+ NewConstraint(from_type->name, to_type->name);
+ return 1;
+ }
+ }
+ }
+
+ void vf_TypePool::NewConstraint(const char *available,
+ const char *required)
+ {
+ vf_TypeConstraint_s *constraint;
+
+ // lookup constraint
+ for( constraint = context->class_constraints; constraint; constraint = constraint->next) {
+ if( constraint->target == required && constraint->source == available ) {
+ // this constraint is already present
+ return;
+ }
+ }
+
+ // set constraint
+ constraint = (vf_TypeConstraint_s*)context->constraintPool.malloc(sizeof(vf_TypeConstraint_s));
+ constraint->target = required;
+ constraint->source = available;
+ constraint->next = context->class_constraints;
+ context->class_constraints = constraint;
+
+ return;
+ }
+
+ SmConstant vf_TypePool::cpool_get_ldcarg(unsigned short cp_idx) {
+ if( cp_idx >= k_cp_length || !cp_idx ) return SM_BOGUS;
+
+ switch (class_get_cp_tag( k_class, cp_idx ) ) {
+ case _CONSTANT_String:
+ return sm_get_const_string();
+
+ case _CONSTANT_Integer:
+ return SM_INTEGER;
+
+ case _CONSTANT_Float:
+ return SM_FLOAT;
+
+ case _CONSTANT_Class:
+ //check if it's a 1.5 class (major version is 49)
+ return context->k_major < 49 ? SM_BOGUS : sm_get_const_class();
+
+ default:
+ return SM_BOGUS;
+ }
+ }
+
+
+ SmConstant vf_TypePool::cpool_get_ldc2arg(unsigned short cp_idx) {
+ if( cp_idx >= k_cp_length || !cp_idx ) return SM_BOGUS;
+
+ switch (class_get_cp_tag( k_class, cp_idx ) ) {
+ case _CONSTANT_Double:
+ return SM_DOUBLE;
+
+ case _CONSTANT_Long:
+ return SM_LONG;
+
+ default:
+ return SM_BOGUS;
+ }
+ }
+
+
+ int vf_TypePool::cpool_is_reftype(unsigned short cp_idx) {
+ return cp_idx && cp_idx < k_cp_length && class_get_cp_tag( k_class, cp_idx ) == _CONSTANT_Class;
+ }
+
+
+ int vf_TypePool::cpool_get_class(unsigned short cp_idx, SmConstant *ref, int expected_dim) {
+ if( !cpool_is_reftype(cp_idx) ) return false;
+
+ unsigned short name_idx = class_get_cp_class_name_index(k_class, cp_idx);
+ if( name_idx >= k_cp_length ) return false;
+
+ const char* name = class_get_cp_utf8_bytes( k_class, name_idx );
+
+ //validate dimensions
+ int ptr = 0;
+ while (name[ptr] == '[' ) {
+ ptr++;
+ }
+ //'name' already contains final '[', so max dimension of class 'name' is 255
+ if( ptr < expected_dim || ptr > 255 ) return false;
+
+ //array is not allowed here
+ if( ptr && expected_dim == -1 ) return false;
+
+
+ //TODO: do we need to resolve if we don't need SmConstant?
+ //e.g. do we need to resolve class of a static variable?
+ //constantpool validation should be done whereever else
+ if( ref ) *ref = get_ref_type(name, (int)strlen(name));
+
+ return true;
+ }
+
+ int vf_TypePool::cpool_get_array(unsigned short cp_idx, SmConstant *ref) {
+ assert(ref);
+ if( !cpool_is_reftype(cp_idx) ) return false;
+
+ unsigned short name_idx = class_get_cp_class_name_index(k_class, cp_idx);
+ if( name_idx >= k_cp_length ) return false;
+
+ const char* name = class_get_cp_utf8_bytes( k_class, name_idx );
+ int len = (int)strlen(name);
+
+
+ //validate dimensions
+ int ptr = 0;
+ while (name[ptr] == '[' ) {
+ ptr++;
+ }
+
+ //'name' does not contain final '[', so max dimension of class 'name' is 254
+ if( ptr > 254 ) return false;
+
+
+
+ char* arr_name = (char*)context->mem.malloc(len + 4);
+ arr_name[0] = '[';
+
+ if( name[0] == '[' ) {
+ tc_memcpy(arr_name + 1, name, len);
+ *ref = get_ref_type(arr_name, len + 1);
+ } else {
+ arr_name[1] = 'L';
+ tc_memcpy(arr_name + 2, name, len);
+ arr_name[len + 2] = ';';
+ *ref = get_ref_type(arr_name, len + 3);
+ }
+
+ context->mem.dealloc_last(arr_name, len + 4);
+ return true;
+ }
+
+
+ int vf_TypePool::cpool_get_field(unsigned short cp_idx, SmConstant *ref, SmConstant *value) {
+ //check it is a field
+ if( !cp_idx || cp_idx >= k_cp_length || class_get_cp_tag( k_class, cp_idx ) != _CONSTANT_Fieldref ) {
+ return false;
+ }
+
+ unsigned short class_idx = class_get_cp_ref_class_index( k_class, cp_idx );
+ if( !cpool_get_class(class_idx, ref) ) return false;
+
+ unsigned short name_and_type_idx = class_get_cp_ref_name_and_type_index( k_class, cp_idx );
+ if( !name_and_type_idx || name_and_type_idx >= k_cp_length || class_get_cp_tag( k_class, name_and_type_idx ) != _CONSTANT_NameAndType ) return false;
+
+ //TODO: do we need this check?
+ //unsigned short name_idx = class_get_cp_name_index( k_class, name_and_type_idx );
+ //if( !name_idx || name_idx >= k_cp_length || class_get_cp_tag( k_class, name_idx ) != _CONSTANT_Utf8 ) return false;
+
+ //get filed type
+ unsigned short type_idx = class_get_cp_descriptor_index( k_class, name_and_type_idx );
+ if( !type_idx || type_idx >= k_cp_length || class_get_cp_tag( k_class, type_idx ) != _CONSTANT_Utf8 ) return false;
+
+ const char *type = class_get_cp_utf8_bytes( k_class, type_idx );
+ *value = get_type(type);
+
+ return true;
+ }
+
+ int vf_TypePool::cpool_method_start(unsigned short cp_idx, const char **state, SmConstant *objectref,
+ unsigned short *name_idx, int opcode) {
+
+ ClassConstantPoolTags expected_tag = opcode == OP_INVOKEINTERFACE ? _CONSTANT_InterfaceMethodref : _CONSTANT_Methodref;
+
+ //check it is a method
+ if( !cp_idx || cp_idx >= k_cp_length || class_get_cp_tag( k_class, cp_idx ) != expected_tag ) {
+ return false;
+ }
+
+ unsigned short class_idx = class_get_cp_ref_class_index( k_class, cp_idx );
+ if( opcode == OP_INVOKEVIRTUAL || opcode == OP_INVOKESPECIAL ) {
+ if( !cpool_get_class(class_idx, objectref) ) return false;
+ } else {
+ if( !cpool_get_class(class_idx, 0) ) return false;
+ (*objectref) = sm_get_const_object();
+ }
+
+ unsigned short name_and_type_idx = class_get_cp_ref_name_and_type_index( k_class, cp_idx );
+ if( !name_and_type_idx || name_and_type_idx >= k_cp_length || class_get_cp_tag( k_class, name_and_type_idx ) != _CONSTANT_NameAndType ) return false;
+
+ *name_idx = class_get_cp_name_index( k_class, name_and_type_idx );
+ //TODO: do we need this check?
+ if( !(*name_idx) || *name_idx >= k_cp_length || class_get_cp_tag( k_class, *name_idx ) != _CONSTANT_Utf8 ) return false;
+
+ //get filed type or function args & rettype
+ unsigned short type_idx = class_get_cp_descriptor_index( k_class, name_and_type_idx );
+ if( !type_idx || type_idx >= k_cp_length || class_get_cp_tag( k_class, type_idx ) != _CONSTANT_Utf8 ) return false;
+
+ (*state) = class_get_cp_utf8_bytes( k_class, type_idx );
+ return true;
+ }
+
+
+ //find return type and count number of arguments
+ int vf_TypePool::cpool_method_get_rettype(const char **state, SmConstant *rettype, int *args_sz) {
+ const char *name = (*state);
+ if( name[0] != '(' ) return 0;
+
+ int i = 1;
+ //count number of args: skip '['s and all between 'L' and ';'
+ (*args_sz) = 0;
+ bool on = true;
+ char current;
+ while ( (current = name[i]) != ')' ) {
+ if( !current ) return 0;
+ if( current == 'L' ) on = false;
+ if( current == ';' ) on = true;
+ if( on && current != '[') {
+ (*args_sz)++;
+ //it is long or double and not an array of long or double
+ if ((current == 'J' || current == 'D') && name[i-1] != '[') {
+ (*args_sz)++;
+ }
+ }
+ i++;
+ }
+ (*state) = i == 1 ? 0 : name + 1;
+ name = name + i + 1;
+
+ *rettype = get_type(name);
+ return 1;
+ }
+
+ int vf_TypePool::cpool_method_next_arg(const char **state, SmConstant *argument) {
+ const char *name = (*state);
+
+ //define name length
+ int len = 0;
+ //skip '['s
+ if ((*state)[len] == '[') {
+ while( (*state)[++len] == '[' ) ;//len++;
+ }
+ //skip up to ';'
+ if( (*state)[len] == 'L' ) {
+ while( (*state)[++len] != ';' ) ;
+ // already checked for '\0' by cpool_method_getrettype
+ // {
+ // assert((*state)[len]);
+ // if( !(*state)[len] ) return false;
+ // len++;
+ // }
+ }
+ len++;
+
+ *argument = get_type((*state), len);
+
+ (*state) = (*state)[len] == ')' ? 0 : (*state) + len;
+ return true;
+ }
+
+ int vf_TypePool::cpool_method_is_constructor_call(unsigned short name_idx) {
+ return !strcmp(class_get_cp_utf8_bytes( k_class, name_idx ), "<init>");
+ }
+
+} // namespace CPVerifier
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/tpool.cpp
------------------------------------------------------------------------------
svn:executable = *