blob: 240af5ee4fe93997a59e74ccea6a67b32771e592 [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.
*/
#include "recompute.h"
#include "../java6/stackmap_6.h"
#include "time.h"
void vf_Context_5e::writeStackMapFrame( Address instr )
{
assert(instr < m_code_length || 1 + lastInstr < instr );
Address offset = lastInstr == -1 ? instr : instr - lastInstr - 1;
lastInstr = instr;
if( curFrame->depth == 0 ) {
//possible variants when not the whole frame is recorded:
//locals are the same, 0-2 locals are cut, locals are extended by 0-2 elements
bool all_locals_same = true;
unsigned first_changed_local = 0;
unsigned last_changed_local = 0;
for( int i = (int)m_max_locals - 1; i >= 0; i-- ) {
if( curFrame->elements[i].getConst() != workmap->elements[i].getConst() ) {
all_locals_same = false;
first_changed_local = i;
if( !last_changed_local ) last_changed_local = i;
}
}
if( all_locals_same ) {
writeStackMapFrame_Same(offset);
return;
}
if( first_changed_local < lastLocalsNo ) {
//check whether it's a CUT
if( last_changed_local >= lastLocalsNo ) {
writeStackMapFrame_Full(offset);
return;
}
int cut_sz = 0; // number of elements cut in attribute (long and double are single size units)
int cut_realsz = 0; // number of elements cut in workmap structure (long and double are double size units)
for( unsigned i = first_changed_local; i < lastLocalsNo; i++ ) {
if( curFrame->elements[i].getConst() != SM_BOGUS ) {
writeStackMapFrame_Full(offset);
return;
}
cut_realsz++;
if( workmap->elements[i].getConst() != SM_HIGH_WORD ) {
//can't cut more than 3 elements
cut_sz++;
}
}
if( cut_sz > 3 ) {
writeStackMapFrame_Full(offset);
return;
}
writeStackMapFrame_Cut(offset, cut_sz, cut_realsz);
return;
} else {
//check whether it's an APPEND
int app_sz = 0; // number of elements appended in attribute (long and double are single size units)
int app_realsz = 0; // number of elements appended in workmap structure (long and double are double size units)
for( unsigned i = lastLocalsNo; i < last_changed_local + 1; i++ ) {
assert( workmap->elements[i].getConst() == SM_BOGUS );
app_realsz++;
if( curFrame->elements[i].getConst() != SM_HIGH_WORD ) {
app_sz++;
}
}
if( app_sz > 3 ) {
//can't append more than 3 elements
writeStackMapFrame_Full(offset);
return;
}
writeStackMapFrame_Append(offset, app_sz, app_realsz);
return;
}
} else if( curFrame->depth == 1 || curFrame->depth == 2 && curFrame->elements[m_stack_start + 1].getConst() == SM_HIGH_WORD) {
for( unsigned i = 0; i < m_max_locals; i++ ) {
if( curFrame->elements[i].getConst() != workmap->elements[i].getConst() ) {
writeStackMapFrame_Full(offset);
return;
}
}
writeStackMapFrame_SameLocalsOneStack(offset);
return;
} else {
writeStackMapFrame_Full(offset);
return;
}
} // writeStackMapFrame
void vf_Context_5e::writeStackMapFrame_Full( Address offset ) {
writeByte(255); // full stack frame
writeByte(offset >> 8); // offset
writeByte(offset & 0xFF); // offset
unsigned locals_realsz; // number of elements in workmap structure (long and double are double size units)
for( locals_realsz = m_max_locals; locals_realsz > 0; locals_realsz-- ) {
if( curFrame->elements[locals_realsz - 1].getConst() != SM_BOGUS ) {
break;
}
}
unsigned locals_sz = 0; // number of elements in attribute (long and double are single size units)
unsigned i;
for( i = 0; i < locals_realsz; i++ ) {
if( curFrame->elements[i].getConst() != SM_HIGH_WORD ) {
locals_sz++;
}
}
writeByte(locals_sz >> 8); // locals_sz
writeByte(locals_sz & 0xFF); // locals_sz
writeStackMapElements(0, locals_realsz);
lastLocalsNo = locals_realsz;
/////////////////////////////////
unsigned stack_sz = 0; // number of stack elements in attribute (long and double are single size units)
for( i = 0; i < curFrame->depth; i++ ) {
if( curFrame->elements[m_stack_start + i].getConst() != SM_HIGH_WORD ) {
stack_sz++;
}
}
writeByte(stack_sz >> 8); // stack depth
writeByte(stack_sz & 0xFF); // stack depth
writeStackMapElements(m_stack_start, curFrame->depth);
}
void vf_Context_5e::writeStackMapFrame_SameLocalsOneStack( Address offset ) {
if( offset < 64 ) {
writeByte(offset + 64); // same locals one stack item
writeStackMapElements(m_stack_start, 1);
} else {
writeByte(247); // one stack extended
writeByte(offset >> 8); // offset
writeByte(offset & 0xFF); // offset
writeStackMapElements(m_stack_start, 1);
}
}
void vf_Context_5e::writeStackMapFrame_Same( Address offset ) {
if( offset < 64 ) {
writeByte(offset); // same
} else {
writeByte(251); // same extended
writeByte(offset >> 8); // offset
writeByte(offset & 0xFF); // offset
}
}
void vf_Context_5e::writeStackMapFrame_Cut( Address offset, int cut_sz, int cut_realsz ) {
writeByte(251 - cut_sz); // same extended
writeByte(offset >> 8); // offset
writeByte(offset & 0xFF); // offset
lastLocalsNo -= cut_realsz;
}
void vf_Context_5e::writeStackMapFrame_Append( Address offset, int app_sz, int app_realsz ) {
writeByte(251 + app_sz); // same extended
writeByte(offset >> 8); // offset
writeByte(offset & 0xFF); // offset
writeStackMapElements(lastLocalsNo, app_realsz);
lastLocalsNo += app_realsz;
}
void vf_Context_5e::writeStackMapElements( Address start, U_32 cnt ) {
while( cnt ) {
SmConstant el = curFrame->elements[start].const_val;
workmap->elements[start].const_val = el;
if( el.isReference() ) {
writeByte(ITEM_OBJECT);
uint16 cp_idx = class_cp_get_class_entry( k_class, tpool.sm_get_refname(el));
writeByte(cp_idx >> 8);
writeByte(cp_idx & 0xFF);
} else if( el.isNewObject() ) {
writeByte(ITEM_UNINITIALIZED);
uint16 instr = el.getNewInstr();
writeByte(instr >> 8);
writeByte(instr & 0xFF);
} else switch ( el.c ) {
case SM_HIGH_WORD:
break;
case SM_NULL:
writeByte(ITEM_NULL);
break;
case SM_INTEGER:
writeByte(ITEM_INTEGER);
break;
case SM_FLOAT:
writeByte(ITEM_FLOAT);
break;
case SM_LONG:
writeByte(ITEM_LONG);
break;
case SM_DOUBLE:
writeByte(ITEM_DOUBLE);
break;
case SM_THISUNINIT:
writeByte(ITEM_UNINITIALIZEDTHIS);
break;
default:
writeByte(ITEM_TOP);
break;
}
start++;
cnt--;
}
}