blob: e94b7de5bb583d3642fc79834581384db57bede6 [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 __RECOMPUTE_H__
#define __RECOMPUTE_H__
#include <assert.h>
#include <string.h>
#include "../java5/context_5.h"
#include "x_class_interface.h"
vf_Result vf_recompute_stackmaptable(Method_Handle method, U_8** attrBytes, char** error, void* trustedPairs);
//possible relations between verificaton types
enum ConstraintType_Ex {
CTX_REVERSED_GENERIC = 4,
CTX_REVERSED_ARRAY2REF = 5,
CTX_POSSIBLE_STACKMAP = 6
};
struct ReversedGenericCnstr : Constraint {
ReversedGenericCnstr *next() {
return (ReversedGenericCnstr *) Constraint::next(Constraint::next(), CTX_REVERSED_GENERIC);
}
};
struct ReversedArrayCnstr : Constraint {
ReversedArrayCnstr *next() {
return (ReversedArrayCnstr *) Constraint::next(Constraint::next(), CTX_REVERSED_ARRAY2REF);
}
};
struct StackmapAttrCnstr : Constraint {
int depth;
StackmapAttrCnstr *next() {
return (StackmapAttrCnstr *) Constraint::next(Constraint::next(), CTX_POSSIBLE_STACKMAP);
}
};
struct StackmapElement_Ex : StackmapElement_5 { //TODO: should be rewritten to save footprint
ReversedGenericCnstr *firstReversedGenericCnstr() {
return (ReversedGenericCnstr*)Constraint::next(others, CTX_REVERSED_GENERIC);
}
ReversedArrayCnstr *firstReversedArrayCnstr() {
return (ReversedArrayCnstr*)Constraint::next(others, CTX_REVERSED_ARRAY2REF);
}
StackmapAttrCnstr *firstStackmapAttrCnstr() {
return (StackmapAttrCnstr*)Constraint::next(others, CTX_POSSIBLE_STACKMAP);
}
int newReversedGenericCnstr_safe(Memory *mem, StackmapElement_5 *to) {
ReversedGenericCnstr *rgen = firstReversedGenericCnstr();
while( rgen ) {
if( rgen->variable == to ) return false;
rgen = rgen->next();
}
newConstraint(mem, CTX_REVERSED_GENERIC)->variable = to;
return true;
}
int newReversedArrayCnstr_safe(Memory *mem, StackmapElement_5 *to) {
ReversedArrayCnstr *rarr = firstReversedArrayCnstr();
while( rarr ) {
if( rarr->variable == to ) return false;
rarr = rarr->next();
}
newConstraint(mem, CTX_REVERSED_ARRAY2REF)->variable = to;
return true;
}
void newStackmapAttrCnstr(Memory *mem, SmConstant value) {
StackmapAttrCnstr *sm = (StackmapAttrCnstr *)mem->malloc(sizeof(StackmapAttrCnstr));
sm->nxt = others;
sm->type = (ConstraintType)CTX_POSSIBLE_STACKMAP;
sm->value = value.c;
sm->depth = 0;
others = sm;
}
void removeIncoming(IncomingType *inc) {
IncomingType *ptr = firstIncoming();
assert(ptr);
if( inc == ptr ) {
POINTER_SIZE_INT mask = (POINTER_SIZE_INT)incoming & 3;
incoming = (IncomingType *) ((POINTER_SIZE_INT)inc->next() | mask);
} else {
while( ptr->next() != inc ) {
ptr = ptr->next();
assert(ptr);
}
ptr->nxt = inc->nxt;
}
}
void removeOther(Constraint *o) {
Constraint *ptr = firstOthers();
assert(ptr);
if( o == ptr ) {
others = o->next();
} else {
while( ptr->next() != o ) {
ptr = ptr->next();
assert(ptr);
}
ptr->nxt = o->nxt;
}
}
};
struct RefInfo {
union {
SmConstant *supercls;
unsigned mask;
};
void init() {
mask = 0xFFFFFFFF;
}
int is_being_calculated() {
return mask == 0xFFFFFFFE;
}
void set_being_calculated() {
mask = 0xFFFFFFFE;
}
int is_calculated() {
return mask != 0xFFFFFFFF && !is_being_calculated();
}
int is_interface() {
return !supercls;
}
void set_interface() {
supercls = 0;
*((SmConstant*)&mask) = SM_NONE;
}
SmConstant *superclasses() {
//always return valis pointer
return supercls ? supercls : (SmConstant*)&mask;
}
void set_superclasses(SmConstant *s) {
mask = 0; //just in case
supercls = s;
}
};
struct TrustedPair {
SmConstant from;
SmConstant to;
};
//
// Context - main class of Type Checker
//
class vf_Context_5e : public vf_Context_5 {
public:
vf_Context_5e(SharedClasswideData &classwide, void *_unparsedPairs) :
vf_Context_5(classwide), parsedTrustedData(0), parsedDataSz(0), unparsedPairs(_unparsedPairs)
{
//we would like to flush StackMapTable attribute from this method
stackmapattr_calculation = true;
}
vf_Result recompute_stackmaptable(Method_Handle method);
~vf_Context_5e() {
tc_free(parsedTrustedData);
}
U_8* written_stackmap;
protected:
void writeStackMapFrame(Address instr);
vf_Result fillCurFrame(PropsHead_5 *head);
void writeStackMapFrame_Full(Address offset);
void writeStackMapFrame_SameLocalsOneStack(Address offset);
void writeStackMapFrame_Same(Address offset);
void writeStackMapFrame_Cut(Address offset, int attr_delta, int workmap_delta);
void writeStackMapFrame_Append(Address offset, int attr_delta, int workmap_delta);
void writeStackMapElements(Address start, U_32 cnt);
void writeByte(uint16 byte) {
assert(byte < 256);
if( !written_stackmap ) {
attrLen = 2; // reserve uint16 for number of enries
attrSz = 0;
}
if( attrLen + 6 >= attrSz ) {
attrSz += 4096;
written_stackmap = (U_8*) tc_realloc(written_stackmap, attrSz);
}
written_stackmap[attrLen + 6] = (U_8) byte;
attrLen++;
}
unsigned lastLocalsNo;
int lastInstr;
WorkmapHead *curFrame;
///////////////////////
vf_Result do_recompute();
vf_Result mantain_node_consistency(StackmapElement_5 *el);
vf_Result arc_consistensy_in_node(StackmapElement_5 *el, int depth);
vf_Result mantain_arc_consistency(int depth);
vf_Result calculate_subgraph(StackmapElement_5 *el);
vf_Result do_backtracking(int depth);
void push_subgraph(StackmapElement_5 *el);
void insert_back_refs(StackmapElement_5 *el);
SmConstant get_node_value(PropsHead_5 *head, int i) {
StackmapElement_Ex *el;
if( head->is_workmap() ) {
WorkmapHead *w = head->getWorkmap();
if( !w->elements[i].isVariable() ) {
return w->elements[i].getConst();
}
el = (StackmapElement_Ex*)(w->elements[i].getVariable());
} else {
el = (StackmapElement_Ex*)(&head->getStackmap()->elements[i]);
}
if( is_node_calculated(el) ) {
return el->firstIncoming()->value;
}
assert(no_stackmap_choice(el));
for( StackmapAttrCnstr *sm = el->firstStackmapAttrCnstr(); sm; sm=sm->next() ) {
if( !sm->depth ) {
return sm->value;
}
}
assert(0);
return SM_BOGUS;
}
int is_node_calculated(StackmapElement_5 *el) {
assert(el->firstIncoming());
//assert( el->firstIncoming()->next() || !SmConstant(el->firstIncoming()->value).isReference() || class_get_cp_class_entry(k_class, tpool.sm_get_refname(el->firstIncoming()->value)));
return !el->firstIncoming()->next();
}
int no_stackmap_choice(StackmapElement_Ex *el) {
assert(el->firstStackmapAttrCnstr());
int stackmapcnt = 0;
for( StackmapAttrCnstr *sm = el->firstStackmapAttrCnstr(); sm; sm=sm->next() ) {
if( !sm->depth ) {
stackmapcnt++;
if( stackmapcnt == 2 ) return false;
}
}
assert(stackmapcnt == 1);
//assert( class_get_cp_class_entry(k_class, tpool.sm_get_refname(el->firstStackmapAttrCnstr()->value)));
return true;
}
SmConstant get_object_array(int dimension) {
return dimension ? get_ref_array(dimension, "java/lang/Object") : tpool.sm_get_const_object();
}
SmConstant get_ref_array(int dimension, SmConstant ref) {
return dimension ? get_ref_array(dimension, tpool.sm_get_refname(ref)) : ref;
}
SmConstant get_ref_array(int dimension, const char* ref_name) {
assert(dimension);
int name_len = (int)strlen(ref_name);
char *name = (char*)mem.malloc(name_len + dimension + 2);
tc_memset(name, '[', dimension);
name[dimension] = 'L';
tc_memcpy(name + dimension + 1, ref_name, name_len);
name[dimension + name_len + 1] = ';';
SmConstant ret = tpool.get_ref_type(name, name_len + dimension + 2);
mem.dealloc_last(name, name_len + dimension + 2);
return ret;
}
SmConstant get_zerodim(SmConstant value) {
const char* name = tpool.sm_get_refname(value);
if( name[0] != '[' ) return value;
while( name[0] == '[' ) name++;
return tpool.get_type(name);
}
unsigned array_dims(SmConstant ref) {
const char* start = tpool.sm_get_refname(ref);
const char* name = start;
while( name[0] == '[' ) name++;
return (unsigned)(name-start);
}
int isObjectOrInterface(SmConstant ref) {
if( ref == tpool.sm_get_const_object() ) return true;
Class_Handle h = tpool.sm_get_handler(ref);
if( h && h != CLASS_NOT_LOADED ) return class_is_interface(h);
parseTrustedData(ref);
return parsedTrustedData[ref.getReferenceIdx()].is_interface();
}
int knownly_assignable(SmConstant from, SmConstant to, int array_element = 0) {
if( from == to && !array_element ) return true;
unsigned from_dims = array_dims(from);
unsigned to_dims = array_dims(to) + (array_element ? 1 : 0);
if( to_dims > from_dims ) return false;
if( to_dims < from_dims ) return isObjectOrInterface( get_zerodim(to) );
from = get_zerodim(from);
to = get_zerodim(to);
if( isObjectOrInterface(to) ) return true;
parseTrustedData(from); // it may change class_handler for 'to'
Class_Handle t = tpool.sm_get_handler(to);
assert(t);
for( SmConstant *sm = parsedTrustedData[from.getReferenceIdx()].superclasses(); *sm != SM_NONE; sm++ ) {
if( *sm == to ) {
return true;
}
if( t != CLASS_NOT_LOADED ) {
Class_Handle f = tpool.sm_get_handler(*sm);
if( f != CLASS_NOT_LOADED && vf_is_extending(f, t) ) return true;
}
}
return false;
}
int check_possible_stackmap(StackmapElement_5 *el, SmConstant sm) {
for( IncomingType *inc = el->firstIncoming()->next(); inc; inc = inc->next()) {
if( !knownly_assignable(inc->value, sm) ) {
//bad stackmap element
return false;
}
}
for( ExpectedType *exp = el->firstExpected(); exp; exp = exp->next() ) {
if( !knownly_assignable(sm, exp->value) ) {
//bad stackmap element
return false;
}
}
return true;
}
int is_arc(Constraint *c) {
return is_direct_arc(c) || is_reversed_arc(c);
}
int is_direct_arc(Constraint *c) {
return c->type == CT_GENERIC || c->type == CT_ARRAY2REF;
}
int is_reversed_arc(Constraint *c) {
return (ConstraintType_Ex)c->type == CTX_REVERSED_GENERIC || (ConstraintType_Ex)c->type == CTX_REVERSED_ARRAY2REF;
}
void reduceTryBlocks(Address dead_code_start, Address dead_code_end) {
uint16 start_pc;
uint16 end_pc;
uint16 handler_pc;
uint16 handler_cp_index;
for( uint16 idx = 0; idx < m_handlecount; idx++ ) {
method_get_exc_handler_info( m_method, idx, &start_pc, &end_pc, &handler_pc, &handler_cp_index );
if( start_pc >= dead_code_start && end_pc <= dead_code_end ) {
method_remove_exc_handler( m_method, idx );
idx--;
} else if( end_pc > dead_code_start && end_pc <= dead_code_end ) {
method_modify_exc_handler_info( m_method, idx, start_pc, dead_code_start, handler_pc, handler_cp_index );
} else if( start_pc >= dead_code_start && start_pc < dead_code_end ) {
method_modify_exc_handler_info( m_method, idx, dead_code_end, end_pc, handler_pc, handler_cp_index );
}
}
}
void parseTrustedData(SmConstant value, int knownly_interface = false);
void parseTrustedPairs();
void tryResolve(SmConstant ref) {
vf_ValidType *f = tpool.getVaildType(ref.getReferenceIdx());
if( !f->cls ) {
f->cls = vf_resolve_class(k_class, f->name, false);
if( !f->cls ) f->cls = CLASS_NOT_LOADED;
}
}
FastStack<StackmapElement_5*> arc_stack;
FastStack<StackmapElement_5*> subgraph_stack;
FastStack<SmConstant> class_stack;
RefInfo *parsedTrustedData;
int parsedDataSz;
TrustedPair* trustedPairs;
int trustedPairsCnt;
void* unparsedPairs;
U_32 attrLen;
U_32 attrSz;
};
#define ITERATE_THRU_STACKMAP_VECTORS(CODE) \
for( i = 0; i < props.hash_size; i++ ) { \
PropsHead_5 *pro = (PropsHead_5*)(props.propHashTable[i]); \
while(pro) { \
if( !pro->is_workmap() ) { \
StackmapHead *sm = pro->getStackmap(); \
\
for( unsigned j = 0; j < m_stack_start + sm->depth; j++ ) { \
/*skip uninit flag*/ \
if( j == m_max_locals && j < m_stack_start ) continue; \
\
StackmapElement_5 *el = &(sm->elements[j]); \
CODE; \
} \
} \
pro=(PropsHead_5 *)pro->next; \
} \
} \
#endif