Draft_1 for compile assembly to a machine code

This commit is contained in:
romanman 2014-05-25 21:39:47 +03:00
parent dbbfe450e5
commit e5f4515cb1
7 changed files with 171 additions and 27 deletions

View File

@ -31,7 +31,7 @@ public class ToolBar extends JFrame {
public ToolBar() throws HeadlessException {
introLogger.info("");
introLogger.info("♢ EthereumJ [v0.5.1] ");
introLogger.info("♢ EthereumJ [v0.5.1] by RomanJ");
introLogger.info("♢ Code by Roman Mandeleil, (c) 2014.");
introLogger.info("♢ Contribution: Nick Savers ");
introLogger.info("♢ Based on a design by Vitalik Buterin.");

View File

@ -1,6 +1,15 @@
package org.ethereum.serpent;
import org.antlr.v4.runtime.tree.ParseTree;
import org.ethereum.util.ByteUtil;
import org.ethereum.vm.OpCode;
import org.spongycastle.util.BigIntegers;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
/**
* www.ethereumJ.com
@ -20,4 +29,93 @@ public class SerpentCompiler {
return result;
}
public static String compileAssemblyToMachine(String code){
StringBuffer assemblyCode = new StringBuffer();
String[] lexaArr = code.split("\\s+");
List<String> lexaList = new ArrayList<String>();
Collections.addAll(lexaList, lexaArr);
// Encode push_n numbers
for (int i = 0; i < lexaList.size(); ++i){
String lexa = lexaList.get(i);
if (OpCode.contains(lexa) ||
lexa.contains("REF_") ||
lexa.contains("LABEL_")) continue;
int bytesNum = ByteUtil.numBytes( lexa );
String num = lexaList.remove(i);
BigInteger bNum = new BigInteger(num);
byte[] bytes = BigIntegers.asUnsignedByteArray(bNum);
if (bytes.length == 0)bytes = new byte[]{0};
for (int j = bytes.length; j > 0 ; --j){
lexaList.add(i, (bytes[j-1] & 0xFF) +"");
}
lexaList.add(i, "PUSH" + bytesNum);
i = i + bytesNum;
}
// calc label pos & remove labels
HashMap<String, Integer> labels = new HashMap<String, Integer>();
for (int i = 0; i < lexaList.size(); ++i){
String lexa = lexaList.get(i);
if (!lexa.contains("LABEL_")) continue;
String label = lexaList.remove(i);
String labelNum = label.split("LABEL_")[1];
labels.put(labelNum, i);
++i;
}
// encode all ref occurrence
for (int i = 0; i < lexaList.size(); ++i){
String lexa = lexaList.get(i);
if (!lexa.contains("REF_")) continue;
String ref = lexaList.remove(i);
String labelNum = ref.split("REF_")[1];
Integer pos = labels.get(labelNum);
int bytesNum = ByteUtil.numBytes( pos.toString() );
lexaList.add(i, pos.toString());
for (int j = 0; j < (4 - bytesNum) ; ++j)
lexaList.add(i, "0");
lexaList.add(i, "PUSH4");
++i;
}
for (String lexa : lexaList){
if (OpCode.contains(lexa))
assemblyCode.append( OpCode.byteVal(lexa) );
else{
assemblyCode.append( lexa );
}
assemblyCode.append(" ");
}
return assemblyCode.toString();
}
}

View File

@ -170,6 +170,8 @@ public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
@Override
public String visitInt_val(@NotNull SerpentParser.Int_valContext ctx) {
// todo: (!!!) ensure that not encode value more than 32 bytes (!!!)
if (ctx.OP_NOT() != null)
return visitExpression(ctx.expression()) + " NOT";

View File

@ -82,4 +82,28 @@ public class ByteUtil {
return 0;
return new BigInteger(1, b).intValue();
}
/**
* Calculate the number of bytes need
* to encode the number
*
* @param val - number
* @return number of min bytes used to encode the number
*/
public static int numBytes(String val){
BigInteger bInt = new BigInteger(val);
int bytes = 0;
while(!bInt.equals(BigInteger.ZERO)){
bInt = bInt.shiftRight(8);
++bytes;
}
if (bytes == 0) ++bytes;
return bytes;
}
}

View File

@ -1,14 +1,13 @@
package org.ethereum.vm;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
/**
* Instruction set for the Ethereum Virtual Machine
*/
public enum OpCode {
/**
/**
* Stop and Arithmetic Operations
*/
@ -136,9 +135,13 @@ public enum OpCode {
private byte opcode;
private static final Map<Byte, OpCode> intToTypeMap = new HashMap<Byte, OpCode>();
private static final Map<String, Byte> stringToByteMap = new HashMap<String, Byte>();
static {
for (OpCode type : OpCode.values()) {
intToTypeMap.put(type.opcode, type);
stringToByteMap.put(type.name(), type.opcode);
}
}
@ -148,12 +151,21 @@ public enum OpCode {
public static OpCode fromInt(int i) {
OpCode type = intToTypeMap.get(i);
if (type == null)
if (type == null)
return OpCode.STOP;
return type;
}
public int asInt() {
return opcode;
}
}
public static boolean contains(String code){
return stringToByteMap.containsKey(code.trim());
}
public static byte byteVal(String code){
return stringToByteMap.get(code);
}
}

View File

@ -1,8 +1,4 @@
#***
# Starting to gather some properties the system going to support
#***
client.name=EthereumJ [v0.5.1] by RomanJ
# if the system will work as a server also
# accept for incoming connections [true/false]

View File

@ -1,6 +1,7 @@
package org.ethereum.serpent;
import org.antlr.v4.runtime.tree.ParseTree;
import org.ethereum.util.ByteUtil;
import org.junit.Assert;
import org.junit.Test;
@ -1211,23 +1212,34 @@ public class SerpentCompileTest {
Assert.assertEquals(expected, result);
}
/*
*
a = msg.datasize
b = msg.sender
c = msg.value
d = tx.gasprice
e = tx.origin
f = tx.gas
g = contract.balance
h = block.prevhash
i = block.coinbase
j = block.timestamp
k = block.number
l = block.difficulty
m = block.gaslimit
*/
@Test // compile to machine code 1
public void test42(){
String code = "x = 256 \n" +
"while x > 1: \n" +
" if (x % 2) == 0: \n" +
" x = x / 2 \n" +
" else: \n " +
" x = 3 * x + 1 \n" ;
String expected = "97 1 0 96 0 84 96 1 96 0 83 11 12 13 99 0 0 0 53 89 96 0 96 2 96 0 83 6 12 13 99 0 0 0 39 89 96 2 96 0 83 4 96 0 84 99 0 0 0 51 88 96 1 96 0 83 96 3 2 1 96 0 84 99 0 0 0 6 88";
String asmResult = SerpentCompiler.compile(code);
String machineCode = SerpentCompiler.compileAssemblyToMachine(asmResult);
Assert.assertEquals(expected, machineCode.trim());
}
@Test // todo delete this one
public void testFoo(){
System.out.println(ByteUtil.numBytes("65536"));
}
/**
*