blob: 72303dbd8d6f3b0d61595ce262572ad2c8931e92 [file] [log] [blame]
/*
* 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.
*/
#ifndef __CONTEXT_X_H__
#define __CONTEXT_X_H__
#include <assert.h>
#include <string.h>
#include "context_base.h"
#include "stackmap_x.h"
//
// Context - main class of Type Checker
//
template<typename ActualClass, typename WorkmapElement, typename _WorkmapElement, typename StackmapElement>
class vf_Context_x : public vf_Context_Base {
public:
vf_Context_x(SharedClasswideData &classwide) : vf_Context_Base(classwide) {}
typedef MapHead<WorkmapElement> WorkmapHead;
typedef MapHead<StackmapElement> StackmapHead;
protected:
// current set of derived types
WorkmapHead *workmap;
/////////////////////////////////////////////////////////////////////////////////////////////////////
//create an uninitialized workmap vector for the given size sz (max_locals <= sz <= max_locals+max_stack)
WorkmapHead *newWorkmap(int sz) {
return (WorkmapHead*)mem.malloc(sizeof(WorkmapHead) + sizeof(WorkmapElement) * sz);
}
//create workmap for zero instruction from method's arguments (second pass in case of java5 verification)
vf_Result create_method_initial_workmap();
//check type-safety of a single instruction (second pass in case of java5 verification)
vf_Result dataflow_instruction(Address instr);
//check type-safety for exception handlers of a single instruction (second pass in case of java5 verification)
vf_Result dataflow_handlers(Address instr);
//specail care for <init> calls 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_impl(StackmapHead *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);
/////////////////////////////////////////////////////////////////////////////////////////////////////
//check conditions for accessing protected non-static fields in different package
vf_Result popFieldRef(SmConstant expected_ref, unsigned short cp_idx);
//check conditions for accessing protected virtual methods in different package
vf_Result popVirtualRef(SmConstant expected_ref, unsigned short cp_idx);
/////////////// 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(value);
workmap_push_const(SM_HIGH_WORD);
}
//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, value);
workmap_set_local_const(idx + 1, 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;
}
//////////////// 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_uint16(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;
}
};
#endif