// true if the previous instruction is an aload to absorb
boolean prevAload = false;
// class of most recent new; helps compress <init> calls
Entry newClass = null;
for (Instruction i = code.instructionAt(0); i != null; i = i.next()) {
// %%% Add a stress mode which issues _ref/_byte_escape.
if (verbose > 3) Utils.log.fine(i.toString());
if (i.isNonstandard()
&& (!p200.getBoolean(Utils.COM_PREFIX+"invokedynamic")
|| i.getBC() != _xxxunusedxxx)) {
// Crash and burn with a complaint if there are funny
// bytecodes in this class file.
String complaint = code.getMethod()
+" contains an unrecognized bytecode "+i
+"; please use the pass-file option on this class.";
Utils.log.warning(complaint);
throw new IOException(complaint);
}
if (i.isWide()) {
if (verbose > 1) {
Utils.log.fine("_wide opcode in "+code);
Utils.log.fine(i.toString());
}
bc_codes.putByte(_wide);
codeHist[_wide]++;
}
int bc = i.getBC();
// Begin "bc_linker" compression.
if (bc == _aload_0) {
// Try to group aload_0 with a following operation.
Instruction ni = code.instructionAt(i.getNextPC());
if (selfOpVariant(ni) >= 0) {
prevAload = true;
continue;
}
}
// Test for <init> invocations:
int init_bc = initOpVariant(i, newClass);
if (init_bc >= 0) {
if (prevAload) {
// get rid of it
bc_codes.putByte(_aload_0);
codeHist[_aload_0]++;
prevAload = false; //used up
}
// Write special bytecode.
bc_codes.putByte(init_bc);
codeHist[init_bc]++;
MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
// Write operand to a separate band.
int coding = cp.getOverloadingIndex(ref);
bc_initref.putInt(coding);
continue;
}
int self_bc = selfOpVariant(i);
if (self_bc >= 0) {
boolean isField = Instruction.isFieldOp(bc);
boolean isSuper = (self_bc >= _self_linker_op+_self_linker_super_flag);
boolean isAload = prevAload;
prevAload = false; //used up
if (isAload)
self_bc += _self_linker_aload_flag;
// Write special bytecode.
bc_codes.putByte(self_bc);
codeHist[self_bc]++;
// Write field or method ref to a separate band.
MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
CPRefBand bc_which = selfOpRefBand(self_bc);
Index which_ix = cp.getMemberIndex(ref.tag, ref.classRef);
bc_which.putRef(ref, which_ix);
continue;
}
assert(!prevAload);
// End "bc_linker" compression.
// Normal bytecode.
codeHist[bc]++;
switch (bc) {
case _tableswitch: // apc: (df, lo, hi, (hi-lo+1)*(label))
case _lookupswitch: // apc: (df, nc, nc*(case, label))
bc_codes.putByte(bc);
Instruction.Switch isw = (Instruction.Switch) i;
// Note that we do not write the alignment bytes.
int apc = isw.getAlignedPC();
int npc = isw.getNextPC();
// write a length specification into the bytecode stream
int caseCount = isw.getCaseCount();
bc_case_count.putInt(caseCount);
putLabel(bc_label, code, i.getPC(), isw.getDefaultLabel());
for (int j = 0; j < caseCount; j++) {
putLabel(bc_label, code, i.getPC(), isw.getCaseLabel(j));
}
// Transmit case values in their own band.
if (bc == _tableswitch) {
bc_case_value.putInt(isw.getCaseValue(0));
} else {
for (int j = 0; j < caseCount; j++) {
bc_case_value.putInt(isw.getCaseValue(j));
}
}
// Done with the switch.
continue;
}
switch (bc) {
case _xxxunusedxxx: // %%% pretend this is invokedynamic
{
i.setNonstandardLength(3);
int refx = i.getShortAt(1);
Entry ref = (refx == 0)? null: curCPMap[refx];
// transmit the opcode, carefully:
bc_codes.putByte(_byte_escape);
bc_escsize.putInt(1); // one byte of opcode
bc_escbyte.putByte(bc); // the opcode
// transmit the CP reference, carefully:
bc_codes.putByte(_ref_escape);
bc_escrefsize.putInt(2); // two bytes of ref
bc_escref.putRef(ref); // the ref
continue;
}
}
int branch = i.getBranchLabel();
if (branch >= 0) {
bc_codes.putByte(bc);
putLabel(bc_label, code, i.getPC(), branch);
continue;
}
Entry ref = i.getCPRef(curCPMap);
if (ref != null) {
if (bc == _new) newClass = ref;
if (bc == _ldc) ldcHist[ref.tag]++;
CPRefBand bc_which;
int vbc = bc;