/*******************************************************************************
* Copyright (c) 2009-2016 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* * Ferry Rietveld - f.rietveld@hva.nl - HvA
* * Paul Klint - Paul.Klint@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.objectweb.asm.Type;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.rascalmpl.value.IBool;
import org.rascalmpl.value.IInteger;
import org.rascalmpl.value.IList;
import org.rascalmpl.value.IMap;
import org.rascalmpl.value.ISet;
import org.rascalmpl.value.IString;
import org.rascalmpl.value.ITuple;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.IValueFactory;
public class BytecodeGenerator implements Opcodes {
// constant references to types used in emitting method calls and field references
private static final Type BOOLEAN_TYPE = Type.BOOLEAN_TYPE;
private static final Type OBJECT_A_TYPE = Type.getType(Object[].class);
private static final Type IVALUE_TYPE = Type.getType(IValue.class);
private static final String FRAME_NAME = Type.getInternalName(Frame.class);
private static final String FUNCTION_NAME = Type.getInternalName(Function.class);
private static final Type FUNCTION_TYPE = Type.getType(Function.class);
private static final Type TYPE_TYPE = Type.getType(org.rascalmpl.value.type.Type.class);
private static final String INIT_NAME = "<init>";
private static final Type INT_TYPE = Type.INT_TYPE;
private static final Type VOID_TYPE = Type.VOID_TYPE;
private static final Type FRAME_TYPE = Type.getType(Frame.class);
private static final Type OBJECT_TYPE = Type.getType(Object.class);
// Locations of the variables in a compiled RVM function.
// Common local variables
public static final int THIS = 0; // Current class (generated for the top level Rascal module)
public static final int CF = 1; // Current frame
public static final int SP = 2; // RVM stack pointer: int sp
public static final int ACCU = 3; // RVM accumulator: Object accu
public static final int STACK = 4; // RVM stack: Object stack[]
// Local variables in coroutines
public static final int LPRECONDITION = 5; // Boolean variable used in guard code
public static final int TMP1 = 5; // Temp variable outside Guard code
public static final int LCOROUTINE = 6; // Local coroutine instance in guard code
public static final int TMP2 = 6; // Temp variable outside Guard code
public static final int EXCEPTION = 7;
// Only needed when function needed constant store or type store
public static final int CS = 8; // Constant store
public static final int TS = 9; // Type constant store
// Arguments of the RVM constructor
public static final int RVM_EXEC = 1;
public static final int RVM_REX = 2;
byte[] endCode = null;
private ClassWriter cw = null;
private MethodVisitor mv = null;
private String className = null;
private String packageName = null;
private String fullClassName = null;
private String[] funcArray = null; // List of compiler-generated function names
// Administration per function
private HashMap<String, Label> labelMap = new HashMap<String, Label>();
private Set<String> catchTargetLabels = new HashSet<String>();
private Map<String, ExceptionLine> catchTargets = new HashMap<String, ExceptionLine>();
private Label[] hotEntryLabels = null; // entry labels for coroutines
private Label exitLabel = null; // special case for labels without code
// TODO: peephole optimizer now removes them; can disappear?
Function[] functionStore;
OverloadedFunction[] overloadedStore;
Map<String, Integer> functionMap;
Map<String, Integer> constructorMap;
Map<String, Integer> resolver;
private Label getNamedLabel(String targetLabel) {
Label lb = labelMap.get(targetLabel);
if (lb == null) {
lb = new Label();
labelMap.put(targetLabel, lb);
}
return lb;
}
public BytecodeGenerator(Function[] functionStore, OverloadedFunction[] overloadedStore,
Map<String, Integer> functionMap, Map<String, Integer> constructorMap, Map<String, Integer> resolver) {
this.functionStore = functionStore;
this.overloadedStore = overloadedStore;
this.functionMap = functionMap;
this.resolver = resolver;
this.constructorMap = constructorMap;
}
//Function currentFunction;
public void buildClass(String packageName, String className, boolean debug) {
emitClass(packageName,className);
for (Function f : functionStore) {
emitMethod(f, debug);
}
// All functions are created create int based dispatcher
if(functionMap.size() > 0){
emitDynDispatch(functionMap.size());
for (Map.Entry<String, Integer> e : functionMap.entrySet()) {
String fname = e.getKey();
emitDynCaLL(fname, e.getValue());
}
emitDynFinalize();
}
OverloadedFunction[] overloadedStoreV2 = new OverloadedFunction[overloadedStore.length];
emitConstructor(overloadedStoreV2);
}
public String finalName() {
return fullClassName;
}
private void emitIntValue(int value) {
switch (value) {
case 0:
mv.visitInsn(ICONST_0);
return;
case 1:
mv.visitInsn(ICONST_1);
return;
case 2:
mv.visitInsn(ICONST_2);
return;
case 3:
mv.visitInsn(ICONST_3);
return;
case 4:
mv.visitInsn(ICONST_4);
return;
case 5:
mv.visitInsn(ICONST_5);
return;
}
if (value >= -128 && value <= 127)
mv.visitIntInsn(BIPUSH, value); // 8 bit
else if (value >= -32768 && value <= 32767)
mv.visitIntInsn(SIPUSH, value); // 16 bit
else
mv.visitLdcInsn(new Integer(value)); // REST
}
/*
* Generate the constructor method for the generated class
*/
public void emitConstructor(OverloadedFunction[] overloadedStore) {
mv = cw.visitMethod(ACC_PUBLIC, INIT_NAME,
Type.getMethodDescriptor(VOID_TYPE, Type.getType(RVMExecutable.class), Type.getType(RascalExecutionContext.class)),
null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, RVM_EXEC);
mv.visitVarInsn(ALOAD, RVM_REX);
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(RVMonJVM.class), INIT_NAME,
Type.getMethodDescriptor(VOID_TYPE, Type.getType(RVMExecutable.class), Type.getType(RascalExecutionContext.class)),false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
/*
* Generate the complete class
*/
public void emitClass(String pName, String cName) {
this.className = cName;
this.packageName = pName;
this.fullClassName = packageName.replace('.', '/') + "/" + className;
cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, fullClassName, null, Type.getInternalName(RVMonJVM.class), null);
}
/*
* Dump the code of the generated class for debugging purposes
*/
public void dumpClass() {
if (endCode == null) {
finalizeCode();
}
try {
FileOutputStream fos = new FileOutputStream("/tmp/Class.jvm");
fos.write(endCode);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Generate a method for one RVM function
*/
public void emitMethod(Function f, boolean debug) {
labelMap.clear(); // New set of labels.
catchTargetLabels.clear();
catchTargets.clear();
// Create method TODO: make it private
mv = cw.visitMethod(ACC_PUBLIC, rvm2jvmName(f.getName()), Type.getMethodDescriptor(OBJECT_TYPE, FRAME_TYPE), null, null);
mv.visitCode();
emitExceptionTable(f.fromLabels, f.toLabels, f.fromSPsCorrected, f.types, f.handlerLabels);
/*
* Fetch sp, stack from current frame and assign to local variable
*/
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(GETFIELD, FRAME_NAME, "sp", Type.INT_TYPE.getDescriptor());
mv.visitVarInsn(ISTORE, SP);
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(GETFIELD, FRAME_NAME, "stack", Type.getDescriptor(Object[].class));
mv.visitVarInsn(ASTORE, STACK);
mv.visitInsn(ACONST_NULL); // TODO: Is this necessary?
mv.visitVarInsn(ASTORE, ACCU);
/*
* Fetch constant store from current frame and (when present) assign to local variable
*/
if (f.constantStore.length != 0) {
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(GETFIELD, FRAME_NAME, "function", Type.getDescriptor(Function.class));
mv.visitFieldInsn(GETFIELD, FUNCTION_NAME, "constantStore", Type.getDescriptor(IValue[].class) );
mv.visitVarInsn(ASTORE, CS);
}
/*
* Fetch type store from current frame and (when present) assign to local variable
*/
if (f.typeConstantStore.length != 0) {
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(GETFIELD, FRAME_NAME, "function", Type.getDescriptor(Function.class));
mv.visitFieldInsn(GETFIELD, FUNCTION_NAME, "typeConstantStore", Type.getDescriptor(org.rascalmpl.value.type.Type[].class));
mv.visitVarInsn(ASTORE, TS);
}
/*
* Handle coroutine
*/
if (f.continuationPoints != 0) {
hotEntryLabels = new Label[f.continuationPoints + 1]; // Add entry 0
exitLabel = new Label();
for (int i = 0; i < hotEntryLabels.length; i++)
hotEntryLabels[i] = new Label();
mv.visitCode();
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(GETFIELD, FRAME_NAME, "hotEntryPoint", Type.INT_TYPE.getDescriptor());
mv.visitTableSwitchInsn(0, hotEntryLabels.length - 1, exitLabel, hotEntryLabels);
mv.visitLabel(hotEntryLabels[0]); // Start at 'address' 0
} else {
exitLabel = null;
}
f.codeblock.genByteCode(this, debug);
if (exitLabel != null) {
mv.visitLabel(exitLabel);
emitPanicReturn();
}
mv.visitMaxs(0, 0);
mv.visitEnd();
}
public void emitHotEntryJumpTable(int continuationPoints, boolean debug) {
hotEntryLabels = new Label[continuationPoints + 1]; // Add default 0 entry point.
}
public byte[] finalizeCode() {
if (endCode == null) {
cw.visitEnd();
endCode = cw.toByteArray();
}
return endCode;
}
/************************************************************************************************/
/* Utilities for instruction emitters */
/************************************************************************************************/
private void emitValueFactory(){
mv.visitVarInsn(ALOAD, THIS);
mv.visitFieldInsn(GETFIELD, fullClassName, "vf", Type.getType(IValueFactory.class).getDescriptor());
}
private void emitRex(){
mv.visitVarInsn(ALOAD, THIS); // rex
mv.visitFieldInsn(GETFIELD, fullClassName, "rex", Type.getType(RascalExecutionContext.class).getDescriptor());
}
public void emitIncSP(int n){
mv.visitIincInsn(SP, n);
}
public void emitReturnValue2ACCU(){
mv.visitVarInsn(ALOAD, THIS);
mv.visitFieldInsn(GETFIELD, fullClassName, "returnValue", OBJECT_TYPE.getDescriptor());
mv.visitVarInsn(ASTORE, ACCU);
}
private void emitReturnNONE(){
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "NONE", Type.getType(IString.class).getDescriptor());
mv.visitInsn(ARETURN);
}
public void emitJMP(String targetLabel) {
Label lb = getNamedLabel(targetLabel);
mv.visitJumpInsn(GOTO, lb);
}
private void emitIntFromTopOfStack(){
emitObjectFromTopOfStack();
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Integer.class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Integer.class), "intValue", Type.getMethodDescriptor(INT_TYPE), false);
}
private void emitIntFromAccu(){
mv.visitVarInsn(ALOAD, ACCU); // ((Integer) accu).intValue()
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Integer.class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Integer.class), "intValue", Type.getMethodDescriptor(INT_TYPE), false);
}
private void emitObjectFromTopOfStack(){
mv.visitVarInsn(ALOAD, STACK);
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
}
public void emitInlineLoadInt(int nval, boolean debug) {
emitIntValue(nval);
mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", Type.getMethodDescriptor(Type.getType(Integer.class), INT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU);
}
/********************************************************************************************/
/* Utitities for calling FrameObservers */
/********************************************************************************************/
public void emitInlineFrameUpdateSrc(int srcIndex){
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF);
emitIntValue(srcIndex);
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RVMonJVM.class), "frameUpdateSrc", Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE, INT_TYPE), false);
}
public void emitInlineFrameObserve(int srcIndex){
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF);
emitIntValue(srcIndex);
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RVMonJVM.class), "frameObserve", Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE, INT_TYPE), false);
}
public void emitInlineFrameEnter(int srcIndex){
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF);
emitIntValue(srcIndex);
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RVMonJVM.class), "frameEnter", Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE, INT_TYPE), false);
}
public void emitInlineFrameLeave(int srcIndex){
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF);
mv.visitVarInsn(ALOAD, THIS);
mv.visitFieldInsn(GETFIELD, fullClassName, "returnValue", OBJECT_TYPE.getDescriptor());
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RVMonJVM.class), "frameLeave", Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE, IVALUE_TYPE), false);
}
/************************************************************************************************/
/* Emitters for various instructions */
/************************************************************************************************/
public void emitJMPTRUEorFALSE(boolean tf, String targetLabel, boolean debug) {
Label target = getNamedLabel(targetLabel);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IBool.class), "getValue", Type.getMethodDescriptor(BOOLEAN_TYPE),true);
if (tf)
mv.visitJumpInsn(IFNE, target);
else
mv.visitJumpInsn(IFEQ, target);
}
public void emitLabel(String targetLabel) {
Label lb = getNamedLabel(targetLabel);
mv.visitLabel(lb);
ExceptionLine el = catchTargets.get(targetLabel);
if (el != null) {
emitCatchLabelEpilogue(el.type, el.newsp);
}
}
// AddInt: accu = ((Integer) stack[--sp]) + ((Integer) accu)
public void emitInlineAddInt(){
emitIntFromTopOfStack(); // left int
emitIntFromAccu(); // right int
mv.visitInsn(IADD); // left + right
mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", Type.getMethodDescriptor(Type.getType(Integer.class), INT_TYPE), false);
mv.visitVarInsn(ASTORE, ACCU);
}
// SubtractInt: accu = ((Integer) stack[--sp]) - ((Integer) accu)
public void emitInlineSubtractInt(){
emitIntFromTopOfStack(); // left int
emitIntFromAccu(); // right int
mv.visitInsn(ISUB); // left - right
mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", Type.getMethodDescriptor(Type.getType(Integer.class), INT_TYPE), false);
mv.visitVarInsn(ASTORE, ACCU);
}
// SubscriptArray: accu = ((Object[]) stack[--sp])[((Integer) accu)];
public void emitInlineSubscriptArray(){
emitObjectFromTopOfStack();
mv.visitTypeInsn(CHECKCAST, Type.getDescriptor(Object[].class));
emitIntFromAccu();
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
// SubscriptList: accu = ((IList) stack[--sp]).get((Integer) accu);
public void emitInlineSubscriptList(){
emitObjectFromTopOfStack();
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IList.class));
emitIntFromAccu();
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IList.class), "get", Type.getMethodDescriptor(IVALUE_TYPE, INT_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
// LessInt: accu = vf.bool(((Integer) stack[--sp]) < ((Integer) accu));
public void emitInlineLessInt(){
emitIntFromTopOfStack(); // left int
emitIntFromAccu(); // right int
Label l1 = new Label();
mv.visitJumpInsn(IF_ICMPGE, l1);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "Rascal_TRUE", Type.getDescriptor(IBool.class));
Label l2 = new Label();
mv.visitJumpInsn(GOTO, l2);
mv.visitLabel(l1);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "Rascal_FALSE", Type.getDescriptor(IBool.class));
mv.visitLabel(l2);
mv.visitVarInsn(ASTORE, ACCU);
}
// GreaterEqualInt: accu = vf.bool(((Integer) stack[--sp]) >= ((Integer) accu));
public void emitInlineGreaterEqualInt(){
emitIntFromTopOfStack(); // left int
emitIntFromAccu(); // right int
Label l1 = new Label();
mv.visitJumpInsn(IF_ICMPLT, l1);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "Rascal_TRUE", Type.getDescriptor(IBool.class));
Label l2 = new Label();
mv.visitJumpInsn(GOTO, l2);
mv.visitLabel(l1);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "Rascal_FALSE", Type.getDescriptor(IBool.class));
mv.visitLabel(l2);
mv.visitVarInsn(ASTORE, ACCU);
}
// AndBool: accu = ((IBool) stack[--sp]).and((IBool) accu);
public void emitInlineAndBool(){
emitObjectFromTopOfStack();
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IBool.class));
mv.visitVarInsn(ALOAD, ACCU);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IBool.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IBool.class), "and", Type.getMethodDescriptor(Type.getType(IBool.class), Type.getType(IBool.class)), true);
mv.visitVarInsn(ASTORE, ACCU);
}
// SubType: accu = vf.bool(((Type) stack[--sp]).isSubtypeOf((Type) accu));
public void emitInlineSubType(){
emitValueFactory();
emitObjectFromTopOfStack();
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(org.rascalmpl.value.type.Type.class));
mv.visitVarInsn(ALOAD, ACCU); // right
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(org.rascalmpl.value.type.Type.class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(org.rascalmpl.value.type.Type.class), "isSubtypeOf", Type.getMethodDescriptor(BOOLEAN_TYPE, TYPE_TYPE), false);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
// LoadLocRef: accu = new Reference(stack, pos);
public void emitInlineLoadLocRef(int pos){
mv.visitTypeInsn(NEW, Type.getInternalName(Reference.class));
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(pos);
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Reference.class), INIT_NAME, Type.getMethodDescriptor(VOID_TYPE, OBJECT_A_TYPE, INT_TYPE), false);
mv.visitVarInsn(ASTORE, ACCU);
}
// PushLocRef: stack[sp++] = new Reference(stack, pos);
public void emitInlinePushLocRef(int pos){
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitIincInsn(SP, 1);
mv.visitTypeInsn(NEW, Type.getInternalName(Reference.class));
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(pos);
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Reference.class), INIT_NAME, Type.getMethodDescriptor(VOID_TYPE, OBJECT_A_TYPE, INT_TYPE), false);
mv.visitInsn(AASTORE);
}
// LoadLocDeref:
// Reference ref = (Reference) stack[pos];
// accu = ref.stack[ref.pos];
public void emitInlineLoadLocDeref(int pos){
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(pos);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Reference.class));
mv.visitVarInsn(ASTORE, TMP1);
mv.visitVarInsn(ALOAD, TMP1);
mv.visitFieldInsn(GETFIELD, Type.getInternalName(Reference.class), "stack", Type.getDescriptor(Object[].class));
mv.visitVarInsn(ALOAD, TMP1);
mv.visitFieldInsn(GETFIELD, Type.getInternalName(Reference.class), "pos", Type.INT_TYPE.getDescriptor());
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
// PushLocDeref:
// Reference ref = (Reference) stack[pos];
// stack[sp++] = ref.stack[ref.pos];
public void emitInlinePushLocDeref(int pos){
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(pos);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Reference.class));
mv.visitVarInsn(ASTORE, TMP1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitIincInsn(SP, 1);
mv.visitVarInsn(ALOAD, TMP1);
mv.visitFieldInsn(GETFIELD, Type.getInternalName(Reference.class), "stack", Type.getDescriptor(Object[].class));
mv.visitVarInsn(ALOAD, TMP1);
mv.visitFieldInsn(GETFIELD, Type.getInternalName(Reference.class), "pos", Type.INT_TYPE.getDescriptor());
mv.visitInsn(AALOAD);
mv.visitInsn(AASTORE);
}
// StoreLocDeref:
// Reference ref = (Reference) stack[pos];
// ref.stack[ref.pos] = accu;
public void emitInlineStoreLocDeref(int pos){
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(pos);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Reference.class));
mv.visitVarInsn(ASTORE, TMP1);
mv.visitVarInsn(ALOAD, TMP1);
mv.visitFieldInsn(GETFIELD, Type.getInternalName(Reference.class), "stack", Type.getDescriptor(Object[].class));
mv.visitVarInsn(ALOAD, TMP1);
mv.visitFieldInsn(GETFIELD, Type.getInternalName(Reference.class), "pos", Type.INT_TYPE.getDescriptor());
mv.visitVarInsn(ALOAD, ACCU);
mv.visitInsn(AASTORE);
}
public void emitInlineExhaust(boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, CF);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "exhaustHelper", Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE),false);
mv.visitInsn(ARETURN);
}
public void emitInlineReturn(int wReturn, boolean debug) {
if(wReturn != 0){
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitFieldInsn(PUTFIELD, fullClassName, "returnValue", OBJECT_TYPE.getDescriptor());
}
emitReturnNONE();
}
public void emitInlineCoReturn(int wReturn, boolean debug) {
mv.visitVarInsn(ALOAD, THIS);
if (wReturn == 0) {
mv.visitVarInsn(ALOAD, CF);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "coreturn0Helper",
Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE),false);
} else {
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, CF);
emitIntValue(wReturn);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "coreturn1Helper",
Type.getMethodDescriptor(VOID_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE),false);
}
emitReturnNONE();
}
public void emitInlineVisit(boolean direction, boolean progress, boolean fixedpoint, boolean rebuild, boolean debug) {
Label returnLabel = new Label();
Label continueLabel = new Label();
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
emitIntValue(direction ? 1 : 0);
emitIntValue(progress ? 1 : 0);
emitIntValue(fixedpoint ? 1 : 0);
emitIntValue(rebuild ? 1 : 0);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "VISIT", Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, BOOLEAN_TYPE, BOOLEAN_TYPE, BOOLEAN_TYPE, BOOLEAN_TYPE),false);
mv.visitInsn(DUP);
mv.visitJumpInsn(IFLE, returnLabel);
mv.visitVarInsn(ISTORE, SP);
mv.visitJumpInsn(GOTO, continueLabel);
mv.visitLabel(returnLabel);
mv.visitInsn(INEG);
mv.visitVarInsn(ISTORE, SP);
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
emitInlineReturn(1, debug);
mv.visitLabel(continueLabel);
}
public void emitInlineCheckMemo(boolean debug) {
Label returnLabel = new Label();
Label continueLabel = new Label();
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, CF);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "CHECKMEMO", Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE),false);
mv.visitInsn(DUP); // [..., sp, sp]
mv.visitJumpInsn(IFLE, returnLabel);
// Here sp > 0
mv.visitVarInsn(ISTORE, SP); // sp = sp - 1
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
mv.visitJumpInsn(GOTO, continueLabel);
mv.visitLabel(returnLabel); // Here; sp <= 0
mv.visitInsn(INEG);
mv.visitVarInsn(ISTORE, SP); // sp = -sp
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU); // accu = stack[sp - 1]
emitInlineReturn(1, debug);
mv.visitLabel(continueLabel);
}
public void emitInlineFailreturn() {
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "FAILRETURN", Type.getType(IString.class).getDescriptor());
mv.visitInsn(ARETURN);
}
public void emitDynDispatch(int numberOfFunctions) {
funcArray = new String[numberOfFunctions];
}
public void emitDynCaLL(String fname, Integer value) {
funcArray[value] = fname;
}
public void emitDynFinalize() {
int nrFuncs = funcArray.length;
Label[] caseLabels = new Label[nrFuncs];
for (int i = 0; i < nrFuncs; i++) {
caseLabels[i] = new Label();
}
Label defaultlabel = new Label();
mv = cw.visitMethod(ACC_PUBLIC, "dynRun", Type.getMethodDescriptor(OBJECT_TYPE, INT_TYPE, FRAME_TYPE), null, null);
mv.visitCode();
// Case switch on int at loc 1 (java stack)
mv.visitVarInsn(ILOAD, 1); // TODO: NAME!
mv.visitTableSwitchInsn(0, nrFuncs - 1, defaultlabel, caseLabels);
for (int i = 0; i < nrFuncs; i++) {
mv.visitLabel(caseLabels[i]);
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, 2); // TODO: NAME! BEWARE: CF in second argument differs from generated functions.
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, rvm2jvmName(funcArray[i]), Type.getMethodDescriptor(OBJECT_TYPE, FRAME_TYPE),false);
mv.visitInsn(ARETURN);
}
mv.visitLabel(defaultlabel);
// Function exit
emitValueFactory();
mv.visitInsn(ICONST_0);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE),true);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
public void emitInlineGuard(int hotEntryPoint, boolean dcode) {
mv.visitVarInsn(ALOAD, CF); // cf.hotEntryPoint = hotEntryPoint
emitIntValue(hotEntryPoint);
mv.visitFieldInsn(PUTFIELD, FRAME_NAME, "hotEntryPoint", Type.INT_TYPE.getDescriptor());
mv.visitInsn(ACONST_NULL); // coroutine = null
mv.visitVarInsn(ASTORE, LCOROUTINE);
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "guardHelper", Type.getMethodDescriptor(BOOLEAN_TYPE, OBJECT_TYPE), false);
mv.visitVarInsn(ISTORE, LPRECONDITION); // precondition = guardHelper(accu)
mv.visitVarInsn(ALOAD, CF); // if(cf != cccf) goto l0
mv.visitVarInsn(ALOAD, THIS);
mv.visitFieldInsn(GETFIELD, fullClassName, "cccf", FRAME_TYPE.getDescriptor());
Label l0 = new Label();
mv.visitJumpInsn(IF_ACMPNE, l0);
// Here: cf == cff
mv.visitVarInsn(ILOAD, LPRECONDITION); // if(!precondition) goto l1
Label l1 = new Label();
mv.visitJumpInsn(IFEQ, l1);
// Here: cf == cff && precondition
mv.visitTypeInsn(NEW, Type.getInternalName(Coroutine.class));
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, THIS);
mv.visitFieldInsn(GETFIELD, fullClassName, "cccf", FRAME_TYPE.getDescriptor());
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Coroutine.class), INIT_NAME,
Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE),false);
mv.visitVarInsn(ASTORE, LCOROUTINE);
mv.visitVarInsn(ALOAD, LCOROUTINE);
mv.visitInsn(ICONST_1);
mv.visitFieldInsn(PUTFIELD, Type.getInternalName(Coroutine.class), "isInitialized", BOOLEAN_TYPE.getDescriptor());
mv.visitVarInsn(ALOAD, LCOROUTINE);
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(PUTFIELD, Type.getInternalName(Coroutine.class), "entryFrame", FRAME_TYPE.getDescriptor());
mv.visitVarInsn(ALOAD, LCOROUTINE);
mv.visitVarInsn(ALOAD, CF);
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Coroutine.class), "suspend",
Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE),false);
mv.visitLabel(l1); // Here cf != cff && !precondition
mv.visitVarInsn(ALOAD, THIS); // cccf = null
mv.visitInsn(ACONST_NULL);
mv.visitFieldInsn(PUTFIELD, fullClassName, "cccf", Type.getType(Frame.class).getDescriptor());
mv.visitVarInsn(ALOAD, CF); // cf.sp = sp
mv.visitVarInsn(ILOAD, SP);
mv.visitFieldInsn(PUTFIELD, FRAME_NAME, "sp", Type.INT_TYPE.getDescriptor());
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ILOAD, LPRECONDITION);
Label l2 = new Label();
mv.visitJumpInsn(IFEQ, l2); // if(!precondition) goto l2
mv.visitVarInsn(ALOAD, LCOROUTINE);
Label l3 = new Label();
mv.visitJumpInsn(GOTO, l3);
mv.visitLabel(l2); // Here: !precondition
mv.visitFieldInsn(GETSTATIC, fullClassName, "exhausted", Type.getType(Coroutine.class).getDescriptor());
mv.visitLabel(l3);
mv.visitFieldInsn(PUTFIELD, fullClassName, "returnValue", OBJECT_TYPE.getDescriptor());
emitReturnNONE();
mv.visitLabel(l0); // Here: cf != cccf
mv.visitVarInsn(ILOAD, LPRECONDITION);
Label l4 = new Label();
mv.visitJumpInsn(IFNE, l4); // if(precondition) goto l4;
mv.visitVarInsn(ALOAD, THIS);
mv.visitFieldInsn(GETSTATIC, fullClassName, "Rascal_FALSE", Type.getDescriptor(IBool.class));
mv.visitFieldInsn(PUTFIELD, fullClassName, "returnValue", OBJECT_TYPE.getDescriptor());
mv.visitVarInsn(ALOAD, CF);
mv.visitVarInsn(ILOAD, SP); // cf.sp = sp
mv.visitFieldInsn(PUTFIELD, FRAME_NAME, "sp", Type.INT_TYPE.getDescriptor());
emitReturnNONE();
mv.visitLabel(l4); // Here: precondition == true
mv.visitLabel(hotEntryLabels[hotEntryPoint]);
}
public void emitInlineLoadLocN(int pos, boolean debug) {
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(pos);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
public void emitInlinePushLocN(int pos, boolean debug) {
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitIincInsn(SP, 1);
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(pos);
mv.visitInsn(AALOAD);
mv.visitInsn(AASTORE);
}
// Experimemtal local copy of constantStore and typeConstantStore probably needed in final version.
public void emitInlineLoadConOrType(int n, boolean conOrType, boolean debug) {
if (conOrType) {
mv.visitVarInsn(ALOAD, CS);
} else {
mv.visitVarInsn(ALOAD, TS);
}
emitIntValue(n);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
public void emitInlinePushConOrType(int n, boolean conOrType, boolean debug) {
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitIincInsn(SP, 1);
if (conOrType) {
mv.visitVarInsn(ALOAD, CS);
} else {
mv.visitVarInsn(ALOAD, TS);
}
emitIntValue(n);
mv.visitInsn(AALOAD);
mv.visitInsn(AASTORE);
}
public void emitInlinePop(boolean debug) {
mv.visitIincInsn(SP, -1);
}
public void emitInlineStoreLoc(int loc, boolean debug) {
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(loc);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitInsn(AASTORE);
}
public void emitInlineTypeSwitch(IList labels, boolean dcode) {
Label[] switchTable;
int nrLabels = labels.length();
switchTable = new Label[nrLabels];
int lcount = 0;
for (IValue vlabel : labels) {
String label = ((IString) vlabel).getValue();
switchTable[lcount++] = getNamedLabel(label);
}
if (exitLabel == null)
exitLabel = new Label();
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "typeSwitchHelper", Type.getMethodDescriptor(INT_TYPE, OBJECT_TYPE), false);
mv.visitTableSwitchInsn(0, nrLabels - 1, exitLabel, switchTable);
}
public void emitInlineYield(int arity, int hotEntryPoint, boolean debug) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
if (arity > 0) {
emitIntValue(arity);
emitIntValue(hotEntryPoint);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "yield1Helper", Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE, INT_TYPE),false);
} else {
emitIntValue(hotEntryPoint);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "yield0Helper", Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE),false);
}
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "YIELD", Type.getType(IString.class).getDescriptor());
mv.visitInsn(ARETURN);
mv.visitLabel(hotEntryLabels[hotEntryPoint]);
}
public void emitPanicReturn() {
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "PANIC", Type.getType(IString.class).getDescriptor());
mv.visitInsn(ARETURN);
}
public void emitEntryLabel(int continuationPoint) {
mv.visitLabel(hotEntryLabels[continuationPoint]);
}
public void emitOptimizedCall(String fuid, int functionIndex, int arity, int continuationPoint, boolean debug){
switch(fuid){
case "Library/MAKE_SUBJECT":
emitInlineCallMAKE_SUBJECT(continuationPoint);
return;
case "Library/GET_SUBJECT_LIST":
emitInlineCallGET_SUBJECT_LIST(continuationPoint);
return;
case "Library/GET_SUBJECT_CURSOR":
emitInlineCallGET_SUBJECT_CURSOR(continuationPoint);
return;
default:
emitInlineCall(functionIndex, arity, continuationPoint, debug);
}
}
public void emitInlineCallMAKE_SUBJECT(int continuationPoint){
emitEntryLabel(continuationPoint);
emitIntValue(2);
mv.visitTypeInsn(ANEWARRAY, Type.getInternalName(Object.class));
mv.visitInsn(DUP);
mv.visitVarInsn(ASTORE, ACCU); // accu = new Object[2];
mv.visitInsn(DUP);
emitIntValue(1);
emitObjectFromTopOfStack();
mv.visitInsn(AASTORE); // subject[1] = stack[--sp] == cursor
emitIntValue(0);
emitObjectFromTopOfStack();
mv.visitInsn(AASTORE); // subject[0] = stack[--sp] = subject
}
public void emitInlineCallGET_SUBJECT_LIST(int continuationPoint){
emitEntryLabel(continuationPoint);
emitObjectFromTopOfStack();
mv.visitTypeInsn(CHECKCAST, Type.getDescriptor(Object[].class));
emitIntValue(0);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
public void emitInlineCallGET_SUBJECT_CURSOR(int continuationPoint){
emitEntryLabel(continuationPoint);
emitObjectFromTopOfStack();
mv.visitTypeInsn(CHECKCAST, Type.getDescriptor(Object[].class));
emitIntValue(1);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
public void emitInlineCall(int functionIndex, int arity, int continuationPoint, boolean debug) {
Label l0 = new Label();
emitEntryLabel(continuationPoint);
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, CF);
emitIntValue(functionIndex);
emitIntValue(arity);
emitIntValue(continuationPoint);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "callHelper", Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitInsn(DUP);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "YIELD", Type.getType(IString.class).getDescriptor());
mv.visitJumpInsn(IF_ACMPNE, l0);
mv.visitInsn(ARETURN);
mv.visitLabel(l0); // result callHelper != "YIELD"
mv.visitInsn(POP);
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(GETFIELD, FRAME_NAME, "sp", Type.INT_TYPE.getDescriptor());
mv.visitVarInsn(ISTORE, SP);
emitReturnValue2ACCU();
}
public void emitInlineCreateDyn(int arity, boolean debug){
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(arity); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "jvmCREATEDYN", Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // _A
mv.visitIincInsn(SP, -arity-1);
}
public void emitInlineCalldyn(int arity, int continuationPoint, boolean debug) {
Label l0 = new Label();
emitEntryLabel(continuationPoint);
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, CF);
emitIntValue(arity);
emitIntValue(continuationPoint);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "calldynHelper",
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitInsn(DUP);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RVMonJVM.class), "YIELD", Type.getType(IString.class).getDescriptor());
mv.visitJumpInsn(IF_ACMPNE, l0);
mv.visitInsn(ARETURN);
mv.visitLabel(l0); // result callDynHelper != "YIELD"
mv.visitInsn(POP);
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(GETFIELD, FRAME_NAME, "sp", Type.INT_TYPE.getDescriptor());
mv.visitVarInsn(ISTORE, SP);
emitReturnValue2ACCU();
}
/********************************************************************************************************************/
/* CallMuPrim / PushCallMuPrim */
/* */
/* Emits an inline version of CallMuPrim[012N] or PushCallMuPrim[012N] instruction and uses a direct call to */
/* the static enum execute method. In some cases, the muprim is special cased */
/********************************************************************************************************************/
// CallMuPrim0
public void emitInlineCallMuPrim0(MuPrimitive muprim, boolean debug) {
emitInlineCallMuPrim0General(muprim, debug);
}
private void emitInlineCallMuPrim0General(MuPrimitive muprim, boolean debug) {
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(MuPrimitive.class), muprim.name(),
Type.getDescriptor(MuPrimitive.class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MuPrimitive.class), "execute0", Type.getMethodDescriptor(OBJECT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // accu = callMuPrim0()
}
// PushCallMuPrim0
public void emitInlinePushCallMuPrim0(MuPrimitive muprim, boolean debug){
emitInlinePushCallMuPrim0General(muprim, debug);
}
private void emitInlinePushCallMuPrim0General(MuPrimitive muprim, boolean debug) {
mv.visitVarInsn(ALOAD, STACK); // stack
mv.visitVarInsn(ILOAD, SP); // sp
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(MuPrimitive.class), muprim.name(),
Type.getDescriptor(MuPrimitive.class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MuPrimitive.class), "execute0", Type.getMethodDescriptor(OBJECT_TYPE),false);
mv.visitInsn(AASTORE); // stack[sp] = callMuPrim0()
mv.visitIincInsn(SP, 1); // sp += 1
}
// CallMuPrim1
public void emitInlineCallMuPrim1(MuPrimitive muprim, boolean debug) {
switch(muprim.name()){
case "iterator_hasNext":
emit_iterator_hasNext(); return;
case "iterator_next":
emit_iterator_next(); return;
case "is_defined":
emit_is_defined(); return;
case "is_bool":
emit_is_predicate("isBool"); return;
case "is_datetime":
emit_is_predicate("isDateTime"); return;
case "is_int":
emit_is_predicate("isInteger"); return;
case "is_list":
emit_is_predicate("isList"); return;
case "is_lrel":
emit_is_predicate("isListRelation"); return;
case "is_loc":
emit_is_predicate("isSourceLocation"); return;
case "is_map":
emit_is_predicate("isMap"); return;
case "is_node":
emit_is_predicate("isNode"); return;
case "is_num":
emit_is_predicate("isNum"); return;
case "is_real":
emit_is_predicate("isReal"); return;
case "is_rat":
emit_is_predicate("isRational"); return;
case "is_rel":
emit_is_predicate("isRelation"); return;
case "is_set":
emit_is_predicate("isSet"); return;
case "is_str":
emit_is_predicate("isString"); return;
case "is_tuple":
emit_is_predicate("isTuple"); return;
case "mint":
emit_mint(); return;
}
emitInlineCallMuPrim1General(muprim, debug);
}
private void emitInlineCallMuPrim1General(MuPrimitive muprim, boolean debug) {
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(MuPrimitive.class), muprim.name(),
Type.getDescriptor(MuPrimitive.class));
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MuPrimitive.class), "execute1", Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // accu = callMuPrim1(arg_1)
}
private void emit_is_predicate(String predicate){
emitValueFactory();
mv.visitVarInsn(ALOAD, ACCU);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IValue.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValue.class), "getType", Type.getMethodDescriptor(TYPE_TYPE), true);
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(org.rascalmpl.value.type.Type.class), predicate, Type.getMethodDescriptor(BOOLEAN_TYPE), false);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
private void emit_is_defined(){
emitValueFactory();
mv.visitVarInsn(ALOAD, ACCU);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Reference.class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Reference.class), "isDefined", Type.getMethodDescriptor(BOOLEAN_TYPE), false);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
private void emit_iterator_hasNext(){
emitValueFactory();
mv.visitVarInsn(ALOAD, ACCU);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Iterator.class), "hasNext", Type.getMethodDescriptor(BOOLEAN_TYPE), true);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
private void emit_iterator_next(){
mv.visitVarInsn(ALOAD, ACCU);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Iterator.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Iterator.class), "next", Type.getMethodDescriptor(OBJECT_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
private void emit_mint(){
mv.visitVarInsn(ALOAD, ACCU);
mv.visitTypeInsn(INSTANCEOF, Type.getInternalName(IInteger.class));
Label l1 = new Label();
mv.visitJumpInsn(IFEQ, l1);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IInteger.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IInteger.class), "intValue", Type.getMethodDescriptor(INT_TYPE), true);
mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", Type.getMethodDescriptor(Type.getType(Integer.class), INT_TYPE), false);
mv.visitVarInsn(ASTORE, ACCU);
mv.visitLabel(l1);
}
// PushCallMuPrim1
public void emitInlinePushCallMuPrim1(MuPrimitive muprim, boolean debug) {
emitInlinePushCallMuPrim1General(muprim, debug);
}
private void emitInlinePushCallMuPrim1General(MuPrimitive muprim, boolean debug) {
mv.visitVarInsn(ALOAD, STACK); // stack
mv.visitVarInsn(ILOAD, SP); // sp
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(MuPrimitive.class), muprim.name(),
Type.getDescriptor(MuPrimitive.class));
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MuPrimitive.class), "execute1", Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE),false);
mv.visitInsn(AASTORE); // stack[sp] = callMuPrim1(arg_1)
mv.visitIincInsn(SP, 1); // sp += 1
}
// CallMuPrim2
public void emitInlineCallMuPrim2(MuPrimitive muprim, boolean debug) {
switch(muprim.name()){
case "equal_mint_mint":
emitComparisonMinMint(IF_ICMPNE); return;
case "greater_equal_mint_mint":
emitComparisonMinMint(IF_ICMPLT); return;
case "greater_mint_mint":
emitComparisonMinMint(IF_ICMPLE); return;
case "less_equal_mint_mint":
emitComparisonMinMint(IF_ICMPGT); return;
case "less_mint_mint":
emitComparisonMinMint(IF_ICMPGE); return;
case "not_equal_mint_mint":
emitComparisonMinMint(IF_ICMPEQ); return;
case "size_array":
emit_size_array(); return;
case "size_list":
emit_size(Type.getInternalName(IList.class)); return;
case "size_set":
emit_size(Type.getInternalName(ISet.class)); return;
case "size_map":
emit_size(Type.getInternalName(IMap.class)); return;
case "size_str":
emit_size(Type.getInternalName(IString.class)); return;
case "size_tuple":
emit_size(Type.getInternalName(ITuple.class)); return;
case "subscript_array_mint":
emitInlineCallMuPrim2_subscript_array_mint(debug);
return;
case "subscript_list_mint":
emitInlineCallMuPrim2_subscript_list_mint(debug);
return;
}
emitInlineCallMuPrim2General(muprim, debug);
}
private void emitInlineCallMuPrim2General(MuPrimitive muprim, boolean debug) {
mv.visitIincInsn(SP, -1); // sp -= 1
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(MuPrimitive.class), muprim.name(),
Type.getDescriptor(MuPrimitive.class));
mv.visitVarInsn(ALOAD, STACK); // arg_2
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MuPrimitive.class), "execute2", Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // accu = callMuPrim2(arg_2, arg_1)
}
// Special cases
private void emitComparisonMinMint(int if_op){
emitValueFactory();
emitIntFromTopOfStack(); // arg_2
emitIntFromAccu(); // arg_1
Label l1 = new Label();
mv.visitJumpInsn(if_op, l1);
mv.visitInsn(ICONST_1);
Label l2 = new Label();
mv.visitJumpInsn(GOTO, l2);
mv.visitLabel(l1);
mv.visitInsn(ICONST_0);
mv.visitLabel(l2);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
private void emit_size_array(){
mv.visitVarInsn(ALOAD, ACCU);
mv.visitTypeInsn(CHECKCAST, Type.getDescriptor(Object[].class));
mv.visitInsn(ARRAYLENGTH);
mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", Type.getMethodDescriptor(Type.getType(Integer.class), INT_TYPE), false);
mv.visitVarInsn(ASTORE, ACCU);
}
private void emit_size(String type){
mv.visitVarInsn(ALOAD, ACCU);
mv.visitTypeInsn(CHECKCAST, type);
mv.visitMethodInsn(INVOKEINTERFACE, type, "length", Type.getMethodDescriptor(INT_TYPE), true);
mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", Type.getMethodDescriptor(Type.getType(Integer.class), INT_TYPE), false);
mv.visitVarInsn(ASTORE, ACCU);
}
// accu = ((Object[]) stack[--sp])[((int) arg_1)];
private void emitInlineCallMuPrim2_subscript_array_mint(boolean debug){
emitObjectFromTopOfStack();
mv.visitTypeInsn(CHECKCAST, Type.getDescriptor(Object[].class));
mv.visitVarInsn(ALOAD, ACCU);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Integer.class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Integer.class), "intValue", Type.getMethodDescriptor(INT_TYPE), false);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
private void emitInlineCallMuPrim2_subscript_list_mint(boolean debug){
emitObjectFromTopOfStack();
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IList.class));
emitIntFromAccu();
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IList.class), "get", Type.getMethodDescriptor(IVALUE_TYPE, INT_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
// PushCallMuPrim2
public void emitInlinePushCallMuPrim2(MuPrimitive muprim, boolean debug) {
switch(muprim.name()){
case "subscript_array_mint":
emitInlinePushCallMuPrim2_subscript_array_mint(debug);
return;
}
emitInlinePushCallMuPrim2General(muprim, debug);
}
private void emitInlinePushCallMuPrim2General(MuPrimitive muprim, boolean debug) {
mv.visitIincInsn(SP, -1); // sp -= 1
mv.visitVarInsn(ALOAD, STACK); // stack
mv.visitVarInsn(ILOAD, SP); // sp
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(MuPrimitive.class), muprim.name(),
Type.getDescriptor(MuPrimitive.class));
mv.visitVarInsn(ALOAD, STACK); // arg_2
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MuPrimitive.class), "execute2", Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE),false);
mv.visitInsn(AASTORE); // stack[sp] = callMuPrim2(arg_2, arg_1)
mv.visitIincInsn(SP, 1); // sp++
}
// Special cases
// stack[sp++] = ((Object[]) stack[sp - 1])[((int) accu)];
private void emitInlinePushCallMuPrim2_subscript_array_mint(boolean debug){
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(ICONST_M1);
mv.visitInsn(IADD);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(CHECKCAST, Type.getDescriptor(Object[].class));
emitIntFromAccu();
mv.visitInsn(AALOAD);
mv.visitInsn(AASTORE);
mv.visitIincInsn(SP, 1);
}
// CallMuPrimN
public void emitInlineCallMuPrimN(MuPrimitive muprim, int arity, boolean debug) {
emitInlineCallMuPrimNGeneral(muprim, arity, debug);
}
private void emitInlineCallMuPrimNGeneral(MuPrimitive muprim, int arity, boolean debug) {
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(MuPrimitive.class), muprim.name(),
Type.getDescriptor(MuPrimitive.class));
mv.visitVarInsn(ALOAD, STACK); // stack
mv.visitVarInsn(ILOAD, SP); // sp
emitIntValue(arity); // arity
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MuPrimitive.class), "executeN", Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE),false);
// sp = callMuPrimN(stack, sp, arity)
mv.visitInsn(ICONST_M1);
mv.visitInsn(IADD); // sp--
mv.visitVarInsn(ISTORE, SP); // sp = callMuPrimN(stack, sp, arity) - 1
mv.visitVarInsn(ALOAD, STACK); // stack
mv.visitVarInsn(ILOAD, SP); // sp
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU); // accu = stack[--sp];
}
// PushCallMuPrimN
public void emitInlinePushCallMuPrimN(MuPrimitive muprim, int arity, boolean debug) {
emitInlinePushCallMuPrimNGeneral(muprim, arity, debug);
}
private void emitInlinePushCallMuPrimNGeneral(MuPrimitive muprim, int arity, boolean debug) {
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(MuPrimitive.class), muprim.name(),
Type.getDescriptor(MuPrimitive.class));
mv.visitVarInsn(ALOAD, STACK); // stack
mv.visitVarInsn(ILOAD, SP); // sp
emitIntValue(arity); // arity
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MuPrimitive.class), "executeN", Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitVarInsn(ISTORE, SP); // sp = callMuPrimN(stach, sp, arity)
}
/********************************************************************************************************************/
/* CallPrim / PushCallPrim */
/* */
/* Emits an inline version of CallPrim[012N] or PushCallPrim[012N] instruction and uses a direct call to */
/* the static enum execute method. In some cases, the muprim is special cased */
/********************************************************************************************************************/
// CallPrim0
public void emitInlineCallPrim0(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlineCallPrim0General(prim, srcIndex, debug);
}
private void emitInlineCallPrim0General(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlineFrameObserve(srcIndex);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RascalPrimitive.class), prim.name(),
Type.getDescriptor(RascalPrimitive.class));
mv.visitVarInsn(ALOAD, CF); // currentFrame
emitRex();
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RascalPrimitive.class), "execute0",
Type.getMethodDescriptor(OBJECT_TYPE, FRAME_TYPE, Type.getType(RascalExecutionContext.class)),false);
mv.visitVarInsn(ASTORE, ACCU); // accu = callPrim0()
}
// PushCallPrim0
public void emitInlinePushCallPrim0(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlinePushCallPrim0General(prim, srcIndex, debug);
}
private void emitInlinePushCallPrim0General(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlineFrameObserve(srcIndex);
mv.visitVarInsn(ALOAD, STACK); // stack
mv.visitVarInsn(ILOAD, SP); // sp
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RascalPrimitive.class), prim.name(),
Type.getDescriptor(RascalPrimitive.class));
mv.visitVarInsn(ALOAD, CF); // currentFrame
emitRex();
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RascalPrimitive.class), "execute0",
Type.getMethodDescriptor(OBJECT_TYPE, FRAME_TYPE, Type.getType(RascalExecutionContext.class)),false);
mv.visitInsn(AASTORE); // stack[sp] callPrim0()
mv.visitIincInsn(SP, 1); // sp += 1
}
// CallPrim1
public void emitInlineCallPrim1(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlineCallPrim1General(prim, srcIndex, debug);
}
private void emitInlineCallPrim1General(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlineFrameObserve(srcIndex);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RascalPrimitive.class), prim.name(),
Type.getDescriptor(RascalPrimitive.class));
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitVarInsn(ALOAD, CF); // currentFrame
emitRex();
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RascalPrimitive.class), "execute1",
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, FRAME_TYPE, Type.getType(RascalExecutionContext.class)),false);
mv.visitVarInsn(ASTORE, ACCU); // accu = callPrim1(arg_1)
}
// PushCallPrim1
public void emitInlinePushCallPrim1(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlinePushCallPrim1General(prim, srcIndex, debug);
}
private void emitInlinePushCallPrim1General(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlineFrameObserve(srcIndex);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RascalPrimitive.class), prim.name(),
Type.getDescriptor(RascalPrimitive.class));
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitVarInsn(ALOAD, CF); // currentFrame
emitRex();
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RascalPrimitive.class), "execute1",
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, FRAME_TYPE, Type.getType(RascalExecutionContext.class)),false);
mv.visitInsn(AASTORE); // stack[sp++] = callPrim1(arg_1)
mv.visitIincInsn(SP, 1);
}
// CallPrim2
public void emitInlineCallPrim2(RascalPrimitive prim, int srcIndex, boolean debug) {
switch(prim.name()){
case "subtype_value_type":
emitInlineCallPrim2_subtype_value_type(srcIndex);
return;
case "subtype_value_value":
emitInlineCallPrim2_subtype_value_value(srcIndex);
return;
}
emitInlineCallPrim2General(prim, srcIndex, debug);
}
private void emitInlineCallPrim2General(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlineFrameObserve(srcIndex);
mv.visitIincInsn(SP, -1);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RascalPrimitive.class), prim.name(),
Type.getDescriptor(RascalPrimitive.class));
mv.visitVarInsn(ALOAD, STACK); // arg_2
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitVarInsn(ALOAD, CF); // currentFrame
emitRex();
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RascalPrimitive.class), "execute2",
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE, FRAME_TYPE, Type.getType(RascalExecutionContext.class)),false);
mv.visitVarInsn(ASTORE, ACCU); // accu = CallPrim2(arg_2, arg_1)
}
private void emitInlineCallPrim2_subtype_value_type(int srcIndex){
emitInlineFrameObserve(srcIndex);
emitValueFactory();
emitObjectFromTopOfStack(); // arg_2
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IValue.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValue.class), "getType", Type.getMethodDescriptor(TYPE_TYPE), true);
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(org.rascalmpl.value.type.Type.class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(org.rascalmpl.value.type.Type.class), "isSubtypeOf", Type.getMethodDescriptor(BOOLEAN_TYPE, TYPE_TYPE), false);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
private void emitInlineCallPrim2_subtype_value_value(int srcIndex){
emitInlineFrameObserve(srcIndex);
emitValueFactory();
emitObjectFromTopOfStack(); // arg_2
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IValue.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValue.class), "getType", Type.getMethodDescriptor(TYPE_TYPE), true);
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IValue.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValue.class), "getType", Type.getMethodDescriptor(TYPE_TYPE), true);
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(org.rascalmpl.value.type.Type.class), "isSubtypeOf", Type.getMethodDescriptor(BOOLEAN_TYPE, TYPE_TYPE), false);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE), true);
mv.visitVarInsn(ASTORE, ACCU);
}
// PushCallPrim2
public void emitInlinePushCallPrim2(RascalPrimitive prim, int srcIndex, boolean debug) {
switch(prim.name()){
case "subtype_value_type":
emitInlinePushCallPrim2_subtype_value_type(srcIndex);
return;
case "subtype_value_value":
emitInlinePushCallPrim2_subtype_value_value(srcIndex);
return;
}
emitInlinePushCallPrim2General(prim, srcIndex, debug);
}
private void emitInlinePushCallPrim2General(RascalPrimitive prim, int srcIndex, boolean debug) {
emitInlineFrameObserve(srcIndex);
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RascalPrimitive.class), prim.name(),
Type.getDescriptor(RascalPrimitive.class));
mv.visitVarInsn(ALOAD, STACK); // arg_2
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitVarInsn(ALOAD, CF); // currentFrame
emitRex();
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RascalPrimitive.class), "execute2",
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE, FRAME_TYPE, Type.getType(RascalExecutionContext.class)), false);
mv.visitInsn(AASTORE);
mv.visitIincInsn(SP, 1);
}
private void emitInlinePushCallPrim2_subtype_value_type(int srcIndex){
emitInlineFrameObserve(srcIndex);
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
emitValueFactory();
mv.visitVarInsn(ALOAD, STACK); // arg_2
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IValue.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValue.class), "getType", Type.getMethodDescriptor(TYPE_TYPE), true);
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(org.rascalmpl.value.type.Type.class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(org.rascalmpl.value.type.Type.class), "isSubtypeOf", Type.getMethodDescriptor(BOOLEAN_TYPE, TYPE_TYPE), false);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE), true);
mv.visitInsn(AASTORE);
mv.visitIincInsn(SP, 1);
}
private void emitInlinePushCallPrim2_subtype_value_value(int srcIndex){
emitInlineFrameObserve(srcIndex);
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
emitValueFactory();
mv.visitVarInsn(ALOAD, STACK); // arg_2
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IValue.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValue.class), "getType", Type.getMethodDescriptor(TYPE_TYPE), true);
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(IValue.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValue.class), "getType", Type.getMethodDescriptor(TYPE_TYPE), true);
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(org.rascalmpl.value.type.Type.class), "isSubtypeOf", Type.getMethodDescriptor(BOOLEAN_TYPE, TYPE_TYPE), false);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValueFactory.class), "bool", Type.getMethodDescriptor(Type.getType(IBool.class), BOOLEAN_TYPE), true);
mv.visitInsn(AASTORE);
mv.visitIincInsn(SP, 1);
}
// CallPrimN
public void emitInlineCallPrimN(RascalPrimitive prim, int arity, int srcIndex, boolean debug) {
emitInlineCallPrimNGeneral(prim, arity, srcIndex, debug);
}
private void emitInlineCallPrimNGeneral(RascalPrimitive prim, int arity, int srcIndex, boolean debug) {
emitInlineFrameObserve(srcIndex);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RascalPrimitive.class), prim.name(),
Type.getDescriptor(RascalPrimitive.class));
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
emitIntValue(arity);
mv.visitVarInsn(ALOAD, CF);
emitRex();
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RascalPrimitive.class), "executeN",
Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE, FRAME_TYPE, Type.getType(RascalExecutionContext.class)),false);
mv.visitInsn(ICONST_M1);
mv.visitInsn(IADD); // sp--
mv.visitVarInsn(ISTORE, SP); // sp = callPrimN(stack, sp, arity, cf, rex) - 1
mv.visitVarInsn(ALOAD, STACK); // stack
mv.visitVarInsn(ILOAD, SP); // sp
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU); // accu = stack[--sp];
}
// PushCallPrimN
public void emitInlinePushCallPrimN(RascalPrimitive prim, int arity, int srcIndex, boolean debug) {
emitInlinePushCallPrimNGeneral(prim, arity, srcIndex, debug);
}
private void emitInlinePushCallPrimNGeneral(RascalPrimitive prim, int arity, int srcIndex, boolean debug) {
emitInlineFrameObserve(srcIndex);
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(RascalPrimitive.class), prim.name(),
Type.getDescriptor(RascalPrimitive.class));
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
emitIntValue(arity);
mv.visitVarInsn(ALOAD, CF);
emitRex();
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(RascalPrimitive.class), "executeN",
Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE, FRAME_TYPE, Type.getType(RascalExecutionContext.class)),false);
mv.visitVarInsn(ISTORE, SP);
}
// End of CallMuPrim[012N] / PushCallMuPrim[012N]
public void emitInlineLoadBool(boolean b, boolean debug) {
if (b) {
mv.visitFieldInsn(GETSTATIC, fullClassName, "Rascal_TRUE", Type.getDescriptor(IBool.class));
} else {
mv.visitFieldInsn(GETSTATIC, fullClassName, "Rascal_FALSE", Type.getDescriptor(IBool.class));
}
mv.visitVarInsn(ASTORE, ACCU); // accu = bool;
}
/*
* emitOptimizedOcall emits a call to a full ocall implementation unless:
* 1: There is only one function => emit direct call (DONE)
* 2: There is only a constructor => call constructor (DONE)
*/
public void emitOptimizedOcall(String fuid, int overloadedFunctionIndex, int arity, int srcIndex, boolean dcode) {
OverloadedFunction of = overloadedStore[overloadedFunctionIndex];
int[] functions = of.getFunctions();
if (functions.length == 1) {
int[] ctors = of.getConstructors();
if (ctors.length == 0) {
Function fu = functionStore[functions[0]];
if (of.getScopeFun().equals("")) {
emitOcallSingle(rvm2jvmName(fu.getName()), functions[0], arity, srcIndex);
} else {
// Nested function needs link to containing frame
// TODO srcIndex
emitCallWithArgsSSFII_A("jvmOCALL", overloadedFunctionIndex, arity, dcode);
mv.visitIincInsn(SP, -arity);
emitReturnValue2ACCU();
}
} else {
// Has a constructor.
// TODO srcIndex
emitCallWithArgsSSFII_A("jvmOCALL", overloadedFunctionIndex, arity, dcode);
mv.visitIincInsn(SP, -arity);
emitReturnValue2ACCU();
}
} else {
if(functions.length == 0 && of.getConstructors().length == 1){
// Specialize for single constructor
// TODO srcIndex
emitCallWithArgsSSFII_A("jvmOCALLSingleConstructor", overloadedFunctionIndex, arity, dcode);
} else {
// TODO srcIndex
emitCallWithArgsSSFII_A("jvmOCALL", overloadedFunctionIndex, arity, dcode);
}
mv.visitIincInsn(SP, -arity);
emitReturnValue2ACCU();
}
}
private void emitOcallSingle(String funName, int fun, int arity, int srcIndex) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF);
mv.visitVarInsn(ALOAD, THIS);
mv.visitFieldInsn(GETFIELD, fullClassName, "functionStore", Type.getDescriptor(Function[].class));
emitIntValue(fun);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ALOAD, CF);
emitIntValue(arity);
mv.visitVarInsn(ILOAD, SP);
emitInlineFrameEnter(srcIndex);
mv.visitMethodInsn(
INVOKEVIRTUAL,
FRAME_NAME,
"getFrame",
Type.getMethodDescriptor(FRAME_TYPE, FUNCTION_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, funName, Type.getMethodDescriptor(OBJECT_TYPE, FRAME_TYPE),false);
mv.visitInsn(POP);
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(GETFIELD, FRAME_NAME, "sp", INT_TYPE.getDescriptor());
mv.visitVarInsn(ISTORE, SP);
emitInlineFrameLeave(srcIndex);
emitReturnValue2ACCU();
}
public void emitInlineSwitch(IMap caseLabels, String caseDefault, boolean concrete, boolean debug) {
Map<Integer, String> jumpBlock = new TreeMap<Integer, String>(); // This map is sorted on its keys.
int nrLabels = caseLabels.size();
Label[] switchTable = new Label[nrLabels];
int[] intTable = new int[nrLabels];
for (IValue vlabel : caseLabels) {
jumpBlock.put(((IInteger) vlabel).intValue(), ((IString) caseLabels.get(vlabel)).getValue());
}
nrLabels = 0;
for (Map.Entry<Integer, String> entry : jumpBlock.entrySet()) {
intTable[nrLabels] = entry.getKey();
switchTable[nrLabels++] = getNamedLabel(entry.getValue());
}
Label trampolineLabel = getNamedLabel(caseDefault + "_trampoline");
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, ACCU);
if (concrete)
mv.visitInsn(ICONST_1);
else
mv.visitInsn(ICONST_0);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "switchHelper", Type.getMethodDescriptor(INT_TYPE, OBJECT_TYPE, BOOLEAN_TYPE),false);
mv.visitLookupSwitchInsn(trampolineLabel, intTable, switchTable);
emitLabel(caseDefault + "_trampoline");
emitJMP(caseDefault);
}
private void emitExceptionTable(String[] fromLabels, String[] toLabels, int[] fromSp, int[] types, String[] handlerLabels) {
//System.err.println("emitExceptionTable " + toLabels + " " + fromSp + " " + types + " " + handlerLabels);;
int len = handlerLabels.length;
for (int i = 0; i < len; i++) {
if(fromLabels[i].startsWith("FINALLY") && toLabels[i].startsWith("FINALLY")){ // Finally clauses are expanded inline by Rascal compiler and can be ignored here
// System.err.println("*** Skip in " + currentFunction.getName() + ": " + fromLabels[i] + " to " + toLabels[i] + " handled by " + handlerLabels[i]);
continue;
}
String toLab = toLabels[i]; // TRY_TO_L
toLab = toLab.substring(toLab.lastIndexOf("_"), toLab.length());
Label fromLabel = getNamedLabel(fromLabels[i]);
Label toLabel = getNamedLabel(toLabels[i]);
Label handlerLabel = getNamedLabel(handlerLabels[i]);
catchTargetLabels.add(handlerLabels[i]);
catchTargets.put(handlerLabels[i], new ExceptionLine(handlerLabels[i], fromSp[i], types[i]));
//System.err.println("*** Add in " + currentFunction.getName() + ": " + fromLabels[i] + " to " + toLabels[i] + " handled by " + handlerLabels[i] );
mv.visitTryCatchBlock(fromLabel, toLabel, handlerLabel, Type.getInternalName(Thrown.class));
}
}
public void emitCatchLabelEpilogue(int type, int newsp) {
// --- Code implements.
// catch(Thrown e) {
// sp = newsp ;
// stack[sp++] = e ;
// if ( ! e.value.getType().isSubtypeOf(cf.function.typeConstantStore[type]) )
// throw e ;
// }
// .....
Label noReThrow = new Label();
mv.visitVarInsn(ASTORE, EXCEPTION);
emitIntValue(newsp);
mv.visitVarInsn(ISTORE, SP);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitIincInsn(SP, 1);
mv.visitVarInsn(ALOAD, EXCEPTION);
mv.visitInsn(AASTORE);
mv.visitVarInsn(ALOAD, EXCEPTION);
mv.visitFieldInsn(GETFIELD, Type.getInternalName(Thrown.class), "value", Type.getDescriptor(IValue.class));
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValue.class), "getType", Type.getMethodDescriptor(TYPE_TYPE),true);
mv.visitVarInsn(ALOAD, CF);
mv.visitFieldInsn(GETFIELD, FRAME_NAME, "function", Type.getDescriptor(Function.class));
mv.visitFieldInsn(GETFIELD, FUNCTION_NAME, "typeConstantStore", Type.getDescriptor(org.rascalmpl.value.type.Type[].class));
emitIntValue(type);
mv.visitInsn(AALOAD);
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(org.rascalmpl.value.type.Type.class), "isSubtypeOf", Type.getMethodDescriptor(BOOLEAN_TYPE, TYPE_TYPE),false);
mv.visitJumpInsn(IFNE, noReThrow);
mv.visitVarInsn(ALOAD, EXCEPTION);
mv.visitInsn(ATHROW);
mv.visitLabel(noReThrow);
}
public void emitInlineThrow(boolean debug) {
mv.visitVarInsn(ALOAD, CF);
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ILOAD, SP);
mv.visitFieldInsn(PUTFIELD, FRAME_NAME, "sp", Type.INT_TYPE.getDescriptor());
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "thrownHelper",
Type.getMethodDescriptor(Type.getType(Thrown.class), FRAME_TYPE, OBJECT_A_TYPE, INT_TYPE),false);
mv.visitInsn(ATHROW);
}
private class ExceptionLine {
@SuppressWarnings("unused")
String catchLabel;
int newsp;
int type;
public ExceptionLine(String lbl, int sp, int type) {
this.catchLabel = lbl;
this.newsp = sp;
this.type = type;
}
}
public void emitInlineResetLoc(int position, boolean debug) {
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(position);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(AASTORE);
}
public void emitInlineResetLocs(int positions, IValue constantValues, boolean debug) {
IList il = (IList) constantValues;
for (IValue v : il) {
int stackPos = ((IInteger) v).intValue();
mv.visitVarInsn(ALOAD, STACK);
emitIntValue(stackPos);
}
mv.visitInsn(ACONST_NULL);
for (int i = 1; i < il.length(); i++) {
mv.visitInsn(DUP_X2);
mv.visitInsn(AASTORE);
}
mv.visitInsn(AASTORE);
}
public void emitInlineResetVar(int what, int pos, boolean debug) {
mv.visitVarInsn(ALOAD, THIS);
emitIntValue(what);
emitIntValue(pos);
mv.visitVarInsn(ALOAD, CF);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "jvmRESETVAR", Type.getMethodDescriptor(VOID_TYPE, INT_TYPE, INT_TYPE, FRAME_TYPE),false);
}
// TODO: compare with performance of insnCHECKARGTYPEANDCOPY
public void emitInlineCheckArgTypeAndCopy(int pos1, int type, int pos2, boolean debug) {
Label l1 = new Label();
Label l5 = new Label();
mv.visitVarInsn(ALOAD, STACK);
/* sourceLoc */
emitIntValue(pos1);
mv.visitInsn(AALOAD);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(IValue.class), "getType", Type.getMethodDescriptor(TYPE_TYPE),true);
mv.visitVarInsn(ALOAD, TS);
/* type */
emitIntValue(type);
mv.visitInsn(AALOAD);
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(org.rascalmpl.value.type.Type.class), "isSubtypeOf", Type.getMethodDescriptor(BOOLEAN_TYPE, TYPE_TYPE),false);
mv.visitJumpInsn(IFEQ, l1);
mv.visitVarInsn(ALOAD, STACK);
/* toloc */
emitIntValue(pos2);
mv.visitVarInsn(ALOAD, STACK);
/* sourceLoc */
emitIntValue(pos1);
mv.visitInsn(AALOAD);
mv.visitInsn(AASTORE);
mv.visitFieldInsn(GETSTATIC, fullClassName, "Rascal_TRUE", Type.getDescriptor(IBool.class));
mv.visitVarInsn(ASTORE, ACCU);
mv.visitJumpInsn(GOTO, l5);
mv.visitLabel(l1);
mv.visitFieldInsn(GETSTATIC, fullClassName, "Rascal_FALSE", Type.getDescriptor(IBool.class));
mv.visitVarInsn(ASTORE, ACCU);
mv.visitLabel(l5);
}
public void emitInlinePushEmptyKwMap(boolean debug) {
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitTypeInsn(NEW, Type.getInternalName(java.util.HashMap.class));
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(java.util.HashMap.class), INIT_NAME, Type.getMethodDescriptor(VOID_TYPE), false);
mv.visitInsn(AASTORE);
mv.visitIincInsn(SP, 1);
}
// TODO: eliminate call
public void emitInlineValueSubtype(int type, boolean debug) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, TS);
emitIntValue(type);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, "VALUESUBTYPE", Type.getMethodDescriptor(OBJECT_TYPE, TYPE_TYPE, OBJECT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU);
}
public void emitInlinePopAccu(boolean debug) {
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
public void emitInlinePushAccu(boolean debug) {
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitInsn(AASTORE);
mv.visitIincInsn(SP, 1);
}
/********************************************************************************************/
/* Utilities */
/********************************************************************************************/
/*
* Map RVM function names to valid JVM method names.
* The characeters not allowed in JVM method names are (according to 4.2.2. Unqualified Names): . ; [ / < >
*/
private String rvm2jvmName(String s) {
char[] b = s.toCharArray();
boolean modified = false;
for (int i = 0; i < b.length; i++) {
switch (b[i]) {
case '.': b[i] = '!'; modified = true; break;
case ';': b[i] = ':'; modified = true; break;
case '[': b[i] = '('; modified = true; break;
case ']': b[i] = ')'; modified = true; break; // added for symmetry
case '/': b[i] = '\\'; modified = true; break;
case '<': b[i] = '{'; modified = true; break;
case '>': b[i] = '}'; modified = true; break;
}
}
return modified ? new String(b) : s;
}
/********************************************************************************************/
/* Emit calls with various parameter combinations */
/* S: STACK */
/* SS: STACK followed by stack pointer SP */
/* F: CF, current frame */
/* I: int */
/* P: value pushed on the stack */
/* A: ACCU */
/* */
/* emitVoidCallWithArgs* calls a void function */
/* emitCallWithArgs*_A calls a non-void function and leaves result in ACCU */
/* emitCallWithArgs*_S calls a non-void function and leaves result on the STACK */
/********************************************************************************************/
public void emitCallWithArgsA_A(String fname) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, ACCU); // arg_1 from accu
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU);
}
public void emitCallWithArgsPA_A(String fname) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitIincInsn(SP, -1); // sp--
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD); // P: arg_2
mv.visitVarInsn(ALOAD, ACCU); // A: arg_1 from accu
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // _A
}
public void emitCallWithArgsSSI_S(String fname, int i, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
emitIntValue(i); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitVarInsn(ISTORE, SP); // _S
}
public void emitCallWithArgsSI_A(String fname, int i, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
emitIntValue(i); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_A_TYPE, INT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // _A
}
public void emitCallWithArgsSSII_S(String fname, int i, int j, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
emitIntValue(i); // I
emitIntValue(j); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitVarInsn(ISTORE, SP); // _S
}
public void emitCallWithArgsSSII_A(String fname, int i, int j, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
emitIntValue(i); // I
emitIntValue(j); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitVarInsn(ISTORE, SP);
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
public void emitCallWithArgsSSFI_S(String fname, int i, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(i); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE),false);
mv.visitVarInsn(ISTORE, SP); // _S
}
public void emitCallWithArgsFI_A(String fname, int i, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(i); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, FRAME_TYPE, INT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // _A
}
public void emitCallWithArgsSSFI_A(String fname, int i, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(i); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // _A
}
public void emitCallWithArgsSFI_A(String fname, int i, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(i); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_A_TYPE, FRAME_TYPE, INT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // _A
}
public void emitCallWithArgsSSFIII_A(String fname, int i, int j, int k, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(i); // I
emitIntValue(j); // I
emitIntValue(k); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // _A
}
public void emitVoidCallWithArgsSSI_S(String fname, int i, boolean dbg) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
emitIntValue(i); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(VOID_TYPE, OBJECT_A_TYPE, INT_TYPE, INT_TYPE),false);
}
public void emitCallWithArgsSSFII_S(String fname, int i, int j, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(i); // I
emitIntValue(j); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitVarInsn(ISTORE, SP); // _S
}
public void emitCallWithArgsSSFII_A(String fname, int i, int j, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(i); // I
emitIntValue(j); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // _A
}
public void emitCallWithArgsFII_A(String fname, int i, int j, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(i); // I
emitIntValue(j); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU); // _A
}
public void emitVoidCallWithArgsFIIA(String fname, int what, int pos, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(what); // I
emitIntValue(pos); // I
mv.visitVarInsn(ALOAD, ACCU); // A
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE, OBJECT_TYPE),false);
}
public void emitCallWithArgsSSFIIIII_S(String fname, int methodName, int className, int parameterTypes, int keywordTypes, int reflect, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(methodName); // I
emitIntValue(className); // I
emitIntValue(parameterTypes); // I
emitIntValue(keywordTypes); // I
emitIntValue(reflect); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE, INT_TYPE, INT_TYPE, INT_TYPE),false);
mv.visitVarInsn(ISTORE, SP); // _S
}
public void emitVoidCallWithArgsSFIA(String fname, int pos, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(pos); // I
mv.visitVarInsn(ALOAD, ACCU); // A
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(VOID_TYPE, OBJECT_A_TYPE, FRAME_TYPE, INT_TYPE, OBJECT_TYPE),false);
}
public void emitVoidCallWithArgsFIA(String fname, int pos, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(pos); // I
mv.visitVarInsn(ALOAD, ACCU); // A
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE, INT_TYPE, OBJECT_TYPE),false);
}
public void emitVoidCallWithArgsFII(String fname, int scope, int pos, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF); // F
emitIntValue(scope); // I
emitIntValue(pos); // I
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(VOID_TYPE, FRAME_TYPE, INT_TYPE, INT_TYPE),false);
}
public void emitCallWithArgsSSF_S(String fname, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
mv.visitVarInsn(ALOAD, CF); // F
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE),false);
mv.visitVarInsn(ISTORE, SP); // _S
}
public void emitCallWithArgsSSF_A(String fname, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, STACK); // S
mv.visitVarInsn(ILOAD, SP); // S
mv.visitVarInsn(ALOAD, CF); // F
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(INT_TYPE, OBJECT_A_TYPE, INT_TYPE, FRAME_TYPE),false);
mv.visitVarInsn(ISTORE, SP);
mv.visitIincInsn(SP, -1);
mv.visitVarInsn(ALOAD, STACK);
mv.visitVarInsn(ILOAD, SP);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, ACCU);
}
public void emitCallWithArgsFA_A(String fname, boolean dcode) {
mv.visitVarInsn(ALOAD, THIS);
mv.visitVarInsn(ALOAD, CF); // F
mv.visitVarInsn(ALOAD, ACCU); // A
mv.visitMethodInsn(INVOKEVIRTUAL, fullClassName, fname, Type.getMethodDescriptor(OBJECT_TYPE, FRAME_TYPE, OBJECT_TYPE),false);
mv.visitVarInsn(ASTORE, ACCU);
}
// Debug calls for tracing the execution of RVM instructions
// Output resembles outbut of the debugRVM flag so traces can be compared.
private final int MAXLEN = 80;
public String abbrev(String sval){
if(sval.length() > MAXLEN){
sval = sval.substring(0, MAXLEN) + " ...";
}
return sval;
}
public void emitDebugCall(String ins) {
mv.visitLdcInsn(ins);
mv.visitVarInsn(ALOAD, CF);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitMethodInsn(INVOKESTATIC, fullClassName, "debugINSTRUCTION", Type.getMethodDescriptor(VOID_TYPE, Type.getType(String.class), FRAME_TYPE, INT_TYPE, OBJECT_TYPE),false);
}
public void emitDebugCall1(String ins, int arg1) {
mv.visitLdcInsn(ins);
mv.visitLdcInsn(arg1);
mv.visitVarInsn(ALOAD, CF);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitMethodInsn(INVOKESTATIC, fullClassName, "debugINSTRUCTION1", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class), INT_TYPE, FRAME_TYPE, INT_TYPE, OBJECT_TYPE),false);
}
public void emitDebugCall2(String ins, String arg1, int arg2) {
mv.visitLdcInsn(ins);
mv.visitLdcInsn(abbrev(arg1));
mv.visitLdcInsn(arg2);
mv.visitVarInsn(ALOAD, CF);
mv.visitVarInsn(ILOAD, SP);
mv.visitVarInsn(ALOAD, ACCU);
mv.visitMethodInsn(INVOKESTATIC, fullClassName, "debugINSTRUCTION2", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class), Type.getType(String.class), INT_TYPE, FRAME_TYPE, INT_TYPE, OBJECT_TYPE),false);
}
}