Skip to content

Commit

Permalink
add ldstr support (neo-project#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
lightszero authored and Erik Zhang committed May 14, 2017
1 parent de2fe31 commit f68c336
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 55 deletions.
76 changes: 74 additions & 2 deletions src/AntShares.Compiler.MSIL/Conv_Common.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace AntShares.Compiler.MSIL
using System;
using System.Numerics;

namespace AntShares.Compiler.MSIL
{
/// <summary>
/// 从ILCode 向小蚁 VM 转换的转换器
Expand Down Expand Up @@ -28,6 +31,41 @@ private AntsCode _Insert1(AntShares.VM.OpCode code, string comment, AntsMethod t
return _code;
}

private AntsCode _InsertPush(byte[] data, string comment, AntsMethod to)
{
if (data.Length == 0) return _Insert1(VM.OpCode.PUSH0, comment, to);
if (data.Length <= 75) return _Insert1((VM.OpCode)data.Length, comment, to, data);
byte prefixLen;
VM.OpCode code;
if (data.Length <= byte.MaxValue)
{
prefixLen = sizeof(byte);
code = VM.OpCode.PUSHDATA1;
}
else if (data.Length <= ushort.MaxValue)
{
prefixLen = sizeof(ushort);
code = VM.OpCode.PUSHDATA2;
}
else
{
prefixLen = sizeof(uint);
code = VM.OpCode.PUSHDATA4;
}
byte[] bytes = new byte[data.Length + prefixLen];
Buffer.BlockCopy(BitConverter.GetBytes(data.Length), 0, bytes, 0, prefixLen);
Buffer.BlockCopy(data, 0, bytes, prefixLen, data.Length);
return _Insert1(code, comment, to, bytes);
}

private AntsCode _InsertPush(int i, string comment, AntsMethod to)
{
if (i == 0) return _Insert1(VM.OpCode.PUSH0, comment, to);
if (i == -1) return _Insert1(VM.OpCode.PUSHM1, comment, to);
if (i > 0 && i <= 16) return _Insert1((VM.OpCode)(byte)i + 0x50, comment, to);
return _InsertPush(((BigInteger)i).ToByteArray(), comment, to);
}

private AntsCode _Convert1by1(AntShares.VM.OpCode code, OpCode src, AntsMethod to, byte[] data = null)
{
AntsCode _code = new AntsCode();
Expand Down Expand Up @@ -56,6 +94,40 @@ private AntsCode _Convert1by1(AntShares.VM.OpCode code, OpCode src, AntsMethod t
return _code;
}

private AntsCode _ConvertPush(byte[] data, OpCode src, AntsMethod to)
{
if (data.Length == 0) return _Convert1by1(VM.OpCode.PUSH0, src, to);
if (data.Length <= 75) return _Convert1by1((VM.OpCode)data.Length, src, to, data);
byte prefixLen;
VM.OpCode code;
if (data.Length <= byte.MaxValue)
{
prefixLen = sizeof(byte);
code = VM.OpCode.PUSHDATA1;
}
else if (data.Length <= ushort.MaxValue)
{
prefixLen = sizeof(ushort);
code = VM.OpCode.PUSHDATA2;
}
else
{
prefixLen = sizeof(uint);
code = VM.OpCode.PUSHDATA4;
}
byte[] bytes = new byte[data.Length + prefixLen];
Buffer.BlockCopy(BitConverter.GetBytes(data.Length), 0, bytes, 0, prefixLen);
Buffer.BlockCopy(data, 0, bytes, prefixLen, data.Length);
return _Convert1by1(code, src, to, bytes);
}

private AntsCode _ConvertPush(int i, OpCode src, AntsMethod to)
{
if (i == 0) return _Convert1by1(VM.OpCode.PUSH0, src, to);
if (i == -1) return _Convert1by1(VM.OpCode.PUSHM1, src, to);
if (i > 0 && i <= 16) return _Convert1by1((VM.OpCode)(byte)i + 0x50, src, to);
return _ConvertPush(((BigInteger)i).ToByteArray(), src, to);
}

private void _insertBeginCode(ILMethod from, AntsMethod to)
{
Expand All @@ -67,7 +139,7 @@ private void _insertBeginCode(ILMethod from, AntsMethod to)
foreach (var src in from.body_Variables)
{
to.body_Variables.Add(new ILParam(src.name, src.type));
_Insert1(AntShares.VM.OpCode.PUSHDATA1, "body_Variables init", to, int2Pushdata1bytes(0));
_InsertPush(0, "body_Variables init", to);
}
}

Expand Down
46 changes: 27 additions & 19 deletions src/AntShares.Compiler.MSIL/Conv_Multi.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Text;

namespace AntShares.Compiler.MSIL
{
Expand All @@ -21,7 +22,7 @@ private void _ConvertStLoc(OpCode src, AntsMethod to, int pos)

//_Convert1by1(AntShares.VM.ScriptOp.OP_DUP, src, to);
//push n
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, null, to, int2Pushdata1bytes(pos));
_ConvertPush(pos, null, to);
//d-n-1
_Convert1by1(AntShares.VM.OpCode.SUB, null, to);
_Convert1by1(AntShares.VM.OpCode.DEC, null, to);
Expand Down Expand Up @@ -49,7 +50,7 @@ private void _ConvertLdLoc(OpCode src, AntsMethod to, int pos)
c.debugline = 0;
}
//push n
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, null, to, int2Pushdata1bytes(pos));
_ConvertPush(pos, null, to);
//d-n-1
_Convert1by1(AntShares.VM.OpCode.SUB, null, to);
_Convert1by1(AntShares.VM.OpCode.DEC, null, to);
Expand All @@ -75,7 +76,7 @@ private void _ConvertLdArg(OpCode src, AntsMethod to, int pos)
c.debugline = 0;
}
//push n
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, null, to, int2Pushdata1bytes(pos));//翻转取参数顺序
_ConvertPush(pos, null, to);//翻转取参数顺序
//_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, null, to, int2Pushdata1bytes(to.paramtypes.Count - 1 - pos));
//d+n
_Convert1by1(AntShares.VM.OpCode.ADD, null, to);
Expand Down Expand Up @@ -254,54 +255,60 @@ private int _ConvertCall(OpCode src, AntsMethod to)
_Convert1by1(VM.OpCode.NOP, src, to);
if (pcount <= 1)
{
}
}
else if (pcount == 2)
{
_Insert1(VM.OpCode.SWAP, "swap 2 param", to);
}
}
else if(pcount==3)
{
_Insert1(VM.OpCode.PUSHDATA1, "swap 0 and 2 param", to, int2Pushdata1bytes(2));
_InsertPush(2, "swap 0 and 2 param", to);
_Insert1(VM.OpCode.XSWAP, "", to);
}
else
{
for (var i = 0; i < pcount / 2; i++)
{
int saveto = (pcount - 1 - i);
_Insert1(VM.OpCode.PUSHDATA1, "load" + saveto, to, int2Pushdata1bytes(saveto));
_InsertPush(saveto, "load" + saveto, to);
_Insert1(VM.OpCode.PICK, "", to);

_Insert1(VM.OpCode.PUSHDATA1, "load" + i + 1, to, int2Pushdata1bytes(i + 1));
_InsertPush(i + 1, "load" + i + 1, to);
_Insert1(VM.OpCode.PICK, "", to);


_Insert1(VM.OpCode.PUSHDATA1, "save to" + saveto + 2, to, int2Pushdata1bytes(saveto + 2));
_InsertPush(saveto + 2, "save to" + saveto + 2, to);
_Insert1(VM.OpCode.XSWAP, "", to);
_Insert1(VM.OpCode.DROP, "", to);

_Insert1(VM.OpCode.PUSHDATA1, "save to" + i + 1, to, int2Pushdata1bytes(i + 1));
_InsertPush(i + 1, "save to" + i + 1, to);
_Insert1(VM.OpCode.XSWAP, "", to);
_Insert1(VM.OpCode.DROP, "", to);

}
}

if (calltype == 1)
{
{
var c = _Convert1by1(AntShares.VM.OpCode.CALL, null, to, new byte[] { 5, 0 });
c.needfix = true;
c.srcfunc = src.tokenMethod;
return 0;
}
return 0;
}
else if (calltype == 2)
{
_Convert1by1(callcode, null, to);
return 0;
}
}
else if (calltype == 3)
{
_Convert1by1(AntShares.VM.OpCode.SYSCALL, null, to, str2Pushdata1bytes(callname));
var bytes = Encoding.UTF8.GetBytes(callname);
if (bytes.Length > 252) throw new Exception("string is to long");
byte[] outbytes = new byte[bytes.Length + 1];
outbytes[0] = (byte)bytes.Length;
Array.Copy(bytes, 0, outbytes, 1, bytes.Length);
//bytes.Prepend 函数在 dotnet framework 4.6 编译不过
_Convert1by1(AntShares.VM.OpCode.SYSCALL, null, to, outbytes);
return 0;
}
return 0;
Expand All @@ -311,16 +318,17 @@ private int _ConvertNewArr(ILMethod method, OpCode src, AntsMethod to)
{
var code = to.body_Codes.Last().Value;
//we need a number
if (code.code != AntShares.VM.OpCode.PUSHDATA1)
if (code.code > AntShares.VM.OpCode.PUSH16)
{
this.logger.Log("_ConvertNewArr::not support var lens for array.");
return 0;
}
var number = pushdata1bytes2int(code.bytes);
var number = getNumber(code);

//移除上一条指令
to.body_Codes.Remove(code.addr);
this.addr--;
if (code.bytes != null)
this.addr -= code.bytes.Length;

var type = src.tokenType;
Expand All @@ -337,14 +345,14 @@ private int _ConvertNewArr(ILMethod method, OpCode src, AntsMethod to)
{//這是在初始化數組

var data = method.body_Codes[n2].tokenUnknown as byte[];
this._Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, toPushdata1bytes(data));
this._ConvertPush(data, src, to);

return 3;

}
else
{
this._Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, toPushdata1bytes(new byte[number]));
this._ConvertPush(new byte[number], src, to);
}
}

Expand Down
70 changes: 37 additions & 33 deletions src/AntShares.Compiler.MSIL/Converter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace AntShares.Compiler.MSIL
{
Expand Down Expand Up @@ -248,27 +249,30 @@ private void ConvertMethod(ILMethod from, AntsMethod to)
// }
// return "";
//}
static byte[] str2Pushdata1bytes(string str)
static int getNumber(AntsCode code)
{
var bytes = System.Text.Encoding.UTF8.GetBytes(str);
if (bytes.Length > 252) throw new Exception("string is to long");
return toPushdata1bytes(bytes);
}
static byte[] int2Pushdata1bytes(int di)
{
var b = BitConverter.GetBytes(di);
return toPushdata1bytes(b);
}
static byte[] toPushdata1bytes(byte[] data)
{
var bytes = new byte[data.Length + 1];
bytes[0] = (byte)data.Length;
for (var i = 0; i < data.Length; i++)
{
bytes[i + 1] = data[i];
}
return bytes;

if (code.code <= VM.OpCode.PUSHBYTES75)
return (int)code.code;
else if (code.code == VM.OpCode.PUSH0) return 0;
else if (code.code == VM.OpCode.PUSH1) return 1;
else if (code.code == VM.OpCode.PUSH2) return 2;
else if (code.code == VM.OpCode.PUSH3) return 3;
else if (code.code == VM.OpCode.PUSH4) return 4;
else if (code.code == VM.OpCode.PUSH5) return 5;
else if (code.code == VM.OpCode.PUSH6) return 6;
else if (code.code == VM.OpCode.PUSH7) return 7;
else if (code.code == VM.OpCode.PUSH8) return 8;
else if (code.code == VM.OpCode.PUSH9) return 9;
else if (code.code == VM.OpCode.PUSH10) return 10;
else if (code.code == VM.OpCode.PUSH11) return 11;
else if (code.code == VM.OpCode.PUSH12) return 12;
else if (code.code == VM.OpCode.PUSH13) return 13;
else if (code.code == VM.OpCode.PUSH14) return 14;
else if (code.code == VM.OpCode.PUSH15) return 15;
else if (code.code == VM.OpCode.PUSH16) return 16;
else if (code.code == VM.OpCode.PUSHDATA1) return pushdata1bytes2int(code.bytes);
else
throw new Exception("not support getNumber From this:" + code.ToString());
}
static int pushdata1bytes2int(byte[] data)
{
Expand Down Expand Up @@ -310,39 +314,39 @@ private int ConvertCode(ILMethod method, OpCode src, AntsMethod to)
break;

case CodeEx.Ldc_I4:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(src.tokenI32));
case CodeEx.Ldc_I4_S:
_ConvertPush(src.tokenI32, src, to);
break;
case CodeEx.Ldc_I4_0:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(0));
_ConvertPush(0, src, to);
break;
case CodeEx.Ldc_I4_1:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(1));
_ConvertPush(1, src, to);
break;
case CodeEx.Ldc_I4_2:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(2));
_ConvertPush(2, src, to);
break;
case CodeEx.Ldc_I4_3:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(3));
_ConvertPush(3, src, to);
break;
case CodeEx.Ldc_I4_4:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(4));
_ConvertPush(4, src, to);
break;
case CodeEx.Ldc_I4_5:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(5));
_ConvertPush(5, src, to);
break;
case CodeEx.Ldc_I4_6:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(6));
_ConvertPush(6, src, to);
break;
case CodeEx.Ldc_I4_7:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(7));
_ConvertPush(7, src, to);
break;
case CodeEx.Ldc_I4_8:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(1));
_ConvertPush(8, src, to);
break;
case CodeEx.Ldc_I4_S:
_Convert1by1(AntShares.VM.OpCode.PUSHDATA1, src, to, int2Pushdata1bytes(src.tokenI32));
case CodeEx.Ldstr:
_ConvertPush(Encoding.UTF8.GetBytes(src.tokenStr), src, to);
break;

case CodeEx.Stloc_0:
_ConvertStLoc(src, to, 0);
break;
Expand Down
2 changes: 1 addition & 1 deletion src/AntShares.Compiler.MSIL/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"authors": [ "The Antshares team" ],
"copyright": "2016-2017 The Antshares team",
"title": "AntShares.Compiler.MSIL",
"version": "1.6.4",
"version": "1.6.4.1",
"buildOptions": {
"emitEntryPoint": true,
"platform": "anycpu"
Expand Down

0 comments on commit f68c336

Please sign in to comment.