// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.
package wyil.util;
import java.util.Arrays;
import wybs.lang.NameID;
import wyil.lang.Bytecode;
import wyil.lang.Constant;
import wyil.lang.Type;
import wyil.lang.Bytecode.Blocks;
import wyil.lang.Bytecode.Extras;
import wyil.lang.Bytecode.OperandGroups;
import wyil.lang.Bytecode.Operands;
import wyil.lang.Bytecode.Schema;
public abstract class AbstractBytecode {
private final int[] operands;
private final int[][] operandGroups;
private final int[] blocks;
public AbstractBytecode() {
this.operands = null;
this.operandGroups = null;
this.blocks = null;
}
public AbstractBytecode(int operand) {
this.operands = new int[] { operand };
this.operandGroups = null;
this.blocks = null;
}
public AbstractBytecode(int[] operands) {
this.operands = operands;
this.operandGroups = null;
this.blocks = null;
}
public AbstractBytecode(int[][] operandGroups) {
this.operands = null;
this.operandGroups = operandGroups;
this.blocks = null;
}
public AbstractBytecode(int operand, int[][] operandGroups) {
this.operands = new int[] { operand };
this.operandGroups = operandGroups;
this.blocks = null;
}
public AbstractBytecode(int[] operands, int[][] operandGroups) {
this.operands = operands;
this.operandGroups = operandGroups;
this.blocks = null;
}
public AbstractBytecode(int operand, int[][] operandGroups, int[] blocks) {
this.operands = new int[] {operand};
this.operandGroups = operandGroups;
this.blocks = blocks;
}
public AbstractBytecode(int[] operands, int[][] operandGroups, int[] blocks) {
this.operands = operands;
this.operandGroups = operandGroups;
this.blocks = blocks;
}
@Override
public int hashCode() {
return getOpcode() ^ Arrays.hashCode(getOperands()) & Arrays.deepHashCode(operandGroups);
}
@Override
public boolean equals(Object o) {
if (o instanceof AbstractBytecode) {
AbstractBytecode bo = (AbstractBytecode) o;
return getOpcode() == bo.getOpcode() && Arrays.equals(getOperands(), bo.getOperands())
&& Arrays.deepEquals(operandGroups, operandGroups) && Arrays.equals(blocks, bo.blocks);
}
return false;
}
/**
* Return the opcode value of this bytecode.
*
* @return
*/
public abstract int getOpcode();
/**
* Return the top-level operands in this bytecode.
*
* @return
*/
public int[] getOperands() {
if(operands == null) {
return new int[0];
} else {
return operands;
}
}
/**
* Return the number of top-level operands in this bytecode
* @return
*/
public int numberOfOperands() {
if(operands == null) {
return 0;
} else {
return operands.length;
}
}
/**
* Return the ith top-level operand in this bytecode.
*
* @param i
* @return
*/
public int getOperand(int i) {
return operands[i];
}
/**
* Get the number of operand groups in this bytecode
*
* @return
*/
public int numberOfOperandGroups() {
if(operandGroups == null) {
return 0;
} else {
return operandGroups.length;
}
}
/**
* Get the ith operand group in this bytecode
*
* @param i
* @return
*/
public int[] getOperandGroup(int i) {
return operandGroups[i];
}
/**
* Determine the number of blocks contained in this bytecode.
*
* @return
*/
public int numberOfBlocks() {
if(blocks == null) {
return 0;
} else {
return blocks.length;
}
}
/**
* Get the ith block contained in this statement
*
* @param i
* @return
*/
public int getBlock(int i) {
return blocks[i];
}
/**
* Get the blocks contained in this statement
*
* @param i
* @return
*/
public int[] getBlocks() {
if(blocks == null) {
return new int[0];
} else {
return blocks;
}
}
/**
* ==================================================================
* Individual Bytecode Schemas
* ==================================================================
*/
public static final Schema[] schemas = new Schema[255];
static {
//
schemas[Bytecode.OPCODE_add] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.ADD);
}
};
schemas[Bytecode.OPCODE_aliasdecl] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.AliasDeclaration(operands[0]);
}
};
schemas[Bytecode.OPCODE_array] = new Schema(Operands.MANY){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.ARRAYCONSTRUCTOR);
}
};
schemas[Bytecode.OPCODE_arrayindex] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands,Bytecode.OperatorKind.ARRAYINDEX);
}
};
schemas[Bytecode.OPCODE_arraygen] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands,Bytecode.OperatorKind.ARRAYGENERATOR);
}
};
schemas[Bytecode.OPCODE_arraylength] = new Schema(Operands.ONE) {
@Override
public Bytecode construct(int opcode, int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.ARRAYLENGTH);
}
};
schemas[Bytecode.OPCODE_assert] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Assert(operands[0]);
}
};
schemas[Bytecode.OPCODE_assign] = new Schema(Operands.ZERO, OperandGroups.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Assign(groups[0],groups[1]);
}
};
schemas[Bytecode.OPCODE_assume] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Assume(operands[0]);
}
};
schemas[Bytecode.OPCODE_bitwiseinvert] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.BITWISEINVERT);
}
};
schemas[Bytecode.OPCODE_bitwiseor] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.BITWISEOR);
}
};
schemas[Bytecode.OPCODE_bitwisexor] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.BITWISEXOR);
}
};
schemas[Bytecode.OPCODE_bitwiseand] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.BITWISEAND);
}
};
schemas[Bytecode.OPCODE_block] = new Schema(Operands.MANY){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Block(operands);
}
};
schemas[Bytecode.OPCODE_break] = new Schema(Operands.ZERO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Break();
}
};
schemas[Bytecode.OPCODE_const] = new Schema(Operands.ZERO, Extras.CONSTANT){
@Override
public Bytecode construct(int opcode, int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Const((Constant) extras[0]);
}
};
schemas[Bytecode.OPCODE_continue] = new Schema(Operands.ZERO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Continue();
}
};
schemas[Bytecode.OPCODE_convert] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Convert(operands[0]);
}
};
schemas[Bytecode.OPCODE_debug] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Debug(operands[0]);
}
};
schemas[Bytecode.OPCODE_dereference] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.DEREFERENCE);
}
};
schemas[Bytecode.OPCODE_div] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.DIV);
}
};
schemas[Bytecode.OPCODE_dowhile] = new Schema(Operands.ONE, OperandGroups.TWO, Blocks.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
int body = blocks[0];
int condition = operands[0];
int[] invariants = groups[0];
int[] modified = groups[1];
return new Bytecode.DoWhile(body,condition,invariants,modified);
}
};
schemas[Bytecode.OPCODE_eq] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.EQ);
}
};
schemas[Bytecode.OPCODE_if] = new Schema(Operands.ONE, OperandGroups.ZERO, Blocks.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
int trueBranch = blocks[0];
return new Bytecode.If(operands[0], trueBranch);
}
};
schemas[Bytecode.OPCODE_ifelse] = new Schema(Operands.ONE, OperandGroups.ZERO, Blocks.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
int trueBranch = blocks[0];
int falseBranch = blocks[1];
return new Bytecode.If(operands[0], trueBranch, falseBranch);
}
};
schemas[Bytecode.OPCODE_fail] = new Schema(Operands.ZERO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Fail();
}
};
schemas[Bytecode.OPCODE_fieldload] = new Schema(Operands.ONE, Extras.STRING){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.FieldLoad(operands[0], (String) extras[0]);
}
};
schemas[Bytecode.OPCODE_gt] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.GT);
}
};
schemas[Bytecode.OPCODE_ge] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.GTEQ);
}
};
schemas[Bytecode.OPCODE_invoke] = new Schema(Operands.MANY, Extras.TYPE, Extras.NAME) {
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Invoke((Type.FunctionOrMethod) extras[0], operands, (NameID) extras[1]);
}
};
schemas[Bytecode.OPCODE_indirectinvoke] = new Schema(Operands.ONE, OperandGroups.ONE, Extras.TYPE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.IndirectInvoke((Type.FunctionOrMethod) extras[0], operands[0], groups[0]);
}
};
schemas[Bytecode.OPCODE_is] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.IS);
}
};
schemas[Bytecode.OPCODE_lambda] = new Schema(Operands.ONE, OperandGroups.TWO, Extras.TYPE) {
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
Type.FunctionOrMethod type = (Type.FunctionOrMethod) extras[0];
int body = operands[0];
int[] parameters = groups[0];
int[] environment = groups[1];
return new Bytecode.Lambda(type,body,parameters,environment);
}
};
schemas[Bytecode.OPCODE_lt] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.LT);
}
};
schemas[Bytecode.OPCODE_le] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.LTEQ);
}
};
schemas[Bytecode.OPCODE_logicalor] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.OR);
}
};
schemas[Bytecode.OPCODE_logicaland] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.AND);
}
};
schemas[Bytecode.OPCODE_logicalnot] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.NOT);
}
};
schemas[Bytecode.OPCODE_mul] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.MUL);
}
};
schemas[Bytecode.OPCODE_namedblock] = new Schema(Operands.ZERO, OperandGroups.ZERO, Blocks.ONE, Extras.STRING) {
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
String name = (String) extras[0];
return new Bytecode.NamedBlock(blocks[0],name);
}
};
schemas[Bytecode.OPCODE_ne] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.NEQ);
}
};
schemas[Bytecode.OPCODE_neg] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.NEG);
}
};
schemas[Bytecode.OPCODE_newobject] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands,Bytecode.OperatorKind.NEW);
}
};
schemas[Bytecode.OPCODE_record] = new Schema(Operands.MANY){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.RECORDCONSTRUCTOR);
}
};
schemas[Bytecode.OPCODE_rem] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.REM);
}
};
schemas[Bytecode.OPCODE_return] = new Schema(Operands.MANY){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Return(operands);
}
};
schemas[Bytecode.OPCODE_shl] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.LEFTSHIFT);
}
};
schemas[Bytecode.OPCODE_shr] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.RIGHTSHIFT);
}
};
schemas[Bytecode.OPCODE_skip] = new Schema(Operands.ZERO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Skip();
}
};
schemas[Bytecode.OPCODE_sub] = new Schema(Operands.TWO){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.Operator(operands, Bytecode.OperatorKind.SUB);
}
};
schemas[Bytecode.OPCODE_switch] = new Schema(Operands.ONE, OperandGroups.ZERO, Extras.SWITCH_ARRAY) {
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
Bytecode.Case[] cases = (Bytecode.Case[]) extras[0];
return new Bytecode.Switch(operands[0], cases);
}
};
schemas[Bytecode.OPCODE_vardecl] = new Schema(Operands.ZERO,Extras.STRING){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
String name = (String) extras[0];
return new Bytecode.VariableDeclaration(name);
}
};
schemas[Bytecode.OPCODE_vardeclinit] = new Schema(Operands.ONE,Extras.STRING){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
String name = (String) extras[0];
return new Bytecode.VariableDeclaration(name,operands[0]);
}
};
schemas[Bytecode.OPCODE_varcopy] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.VariableAccess(true,operands[0]);
}
};
schemas[Bytecode.OPCODE_varmove] = new Schema(Operands.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
return new Bytecode.VariableAccess(false,operands[0]);
}
};
schemas[Bytecode.OPCODE_while] = new Schema(Operands.ONE, OperandGroups.TWO, Blocks.ONE){
@Override
public Bytecode construct(int opcode,int[] operands, int[][] groups, int[] blocks, Object[] extras) {
int body = blocks[0];
int condition = operands[0];
int[] invariants = groups[0];
int[] modified = groups[1];
return new Bytecode.While(body,condition,invariants,modified);
}
};
// Quantifiers
schemas[Bytecode.OPCODE_some] = schemas[Bytecode.OPCODE_all] = new Schema(
Operands.ONE, OperandGroups.MANY) {
@Override
public Bytecode construct(int opcode, int[] operands, int[][] groups, int[] blocks, Object[] extras) {
int body = operands[0];
Bytecode.Range[] ranges = new Bytecode.Range[groups.length];
for (int i = 0; i != ranges.length; i = i + 1) {
int[] group = groups[i];
ranges[i] = new Bytecode.Range(group[0],group[1],group[2]);
}
Bytecode.QuantifierKind kind;
switch(opcode) {
case Bytecode.OPCODE_some:
kind = Bytecode.QuantifierKind.SOME;
break;
case Bytecode.OPCODE_all:
kind = Bytecode.QuantifierKind.ALL;
break;
default:
// deadcpde
throw new IllegalArgumentException();
}
return new Bytecode.Quantifier(kind, body, ranges);
}
};
}
}