Skip to content

Commit

Permalink
library optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
lunfardo314 committed May 12, 2024
1 parent 80a38fd commit 2231b4c
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 59 deletions.
46 changes: 24 additions & 22 deletions compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"unicode"
)

// TODO inline bytecode literal + 'eval' embedded function + $$ bytecode parameter

// funParsed is an interim representation of the source code
type funParsed struct {
Sym string
Expand Down Expand Up @@ -106,9 +108,9 @@ func parseExpression(s string) (*parsedExpression, error) {
if err != nil {
return nil, err
}
for _, call := range spl {
ff, err := parseExpression(call)
if err != nil {
var ff *parsedExpression
for _, _call := range spl {
if ff, err = parseExpression(_call); err != nil {
return nil, err
}
f.params = append(f.params, ff)
Expand Down Expand Up @@ -215,9 +217,9 @@ func (f *parsedExpression) bytecodeFromParsedExpression(lib *Library, w io.Write
return 0, err
}
// generate code for call parameters
var n int
for _, ff := range f.params {
n, err := ff.bytecodeFromParsedExpression(lib, w, localLib...)
if err != nil {
if n, err = ff.bytecodeFromParsedExpression(lib, w, localLib...); err != nil {
return 0, err
}
if n > numArgs {
Expand All @@ -232,6 +234,10 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
n, err := strconv.Atoi(sym)
itIsANumber := err == nil

var b, funCallPrefix []byte
var un uint64
var fi *funInfo

switch {
case itIsANumber:
if n < 0 || n >= 256 {
Expand All @@ -244,7 +250,7 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
return true, 0, nil
case strings.HasPrefix(sym, "$"):
// parameter reference function
n, err := strconv.Atoi(sym[1:])
n, err = strconv.Atoi(sym[1:])
if err != nil {
return false, 0, err
}
Expand All @@ -262,8 +268,7 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
return true, 0, nil
case strings.HasPrefix(sym, "0x"):
// it is hexadecimal constant
b, err := hex.DecodeString(sym[2:])
if err != nil {
if b, err = hex.DecodeString(sym[2:]); err != nil {
return false, 0, fmt.Errorf("%v: '%s'", err, sym)
}
if len(b) > 127 {
Expand All @@ -278,8 +283,7 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
return true, 0, nil
case strings.HasPrefix(sym, "x/"):
// it is an inline binary executable code
b, err := hex.DecodeString(sym[2:])
if err != nil {
if b, err = hex.DecodeString(sym[2:]); err != nil {
return false, 0, fmt.Errorf("%v: '%s'", err, sym)
}
// write the code as is
Expand All @@ -296,7 +300,7 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
if n < 0 || n > math.MaxUint16 {
return false, 0, fmt.Errorf("wrong u16 constant: '%s'", sym)
}
b := make([]byte, 2)
b = make([]byte, 2)
binary.BigEndian.PutUint16(b, uint16(n))
if _, err = w.Write([]byte{FirstByteDataMask | byte(2)}); err != nil {
return false, 0, err
Expand All @@ -314,7 +318,7 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
if n < 0 || n > math.MaxUint32 {
return false, 0, fmt.Errorf("wrong u32 constant: '%s'", sym)
}
b := make([]byte, 4)
b = make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(n))
if _, err = w.Write([]byte{FirstByteDataMask | byte(4)}); err != nil {
return false, 0, err
Expand All @@ -325,11 +329,10 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
return true, 0, nil
case strings.HasPrefix(sym, "u64/"):
// it is u16 constant big endian
un, err := strconv.ParseUint(strings.TrimPrefix(sym, "u64/"), 10, 64)
if err != nil {
if un, err = strconv.ParseUint(strings.TrimPrefix(sym, "u64/"), 10, 64); err != nil {
return false, 0, fmt.Errorf("%v: '%s'", err, sym)
}
b := make([]byte, 8)
b = make([]byte, 8)
binary.BigEndian.PutUint64(b, un)
if _, err = w.Write([]byte{FirstByteDataMask | byte(8)}); err != nil {
return false, 0, err
Expand All @@ -341,16 +344,14 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
case strings.HasPrefix(sym, "#"):
// function call prefix literal
funName := strings.TrimPrefix(sym, "#")
fi, err := lib.functionByName(funName)
if err != nil {
if fi, err = lib.functionByName(funName); err != nil {
return false, 0, err
}
numArgs := fi.NumParams
if numArgs < 0 {
numArgs = 0
}
funCallPrefix, err := fi.callPrefix(byte(numArgs))
if err != nil {
if funCallPrefix, err = fi.callPrefix(byte(numArgs)); err != nil {
return false, 0, err
}
if _, err = w.Write([]byte{FirstByteDataMask | byte(len(funCallPrefix))}); err != nil {
Expand All @@ -367,9 +368,9 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
if len(msgData) > 127 {
return false, 0, fmt.Errorf("fail message can't be longer than 127 bytes: '%s'", sym)
}
fi, err := lib.functionByName("fail")
fi, err = lib.functionByName("fail")
AssertNoError(err)
funCallPrefix, err := fi.callPrefix(1)
funCallPrefix, err = fi.callPrefix(1)
AssertNoError(err)
if _, err = w.Write(funCallPrefix); err != nil {
return false, 0, err
Expand All @@ -382,7 +383,6 @@ func parseLiteral(lib *Library, sym string, w io.Writer) (bool, int, error) {
}
return true, 0, nil
}
// TODO other types of literals
return false, 0, nil
}

Expand Down Expand Up @@ -509,6 +509,8 @@ func (lib *Library) expressionFromBytecode(bytecode []byte, localLib ...*LocalLi
if len(callPrefix) == 1 && arity < 0 {
return nil, nil, 0xff, fmt.Errorf("EasyFL: short embedded with vararg is not allowed")
}
Assert(arity >= 0, "EasyFL: arity >= 0")

ret := &Expression{
Args: make([]*Expression, 0),
EvalFunc: nil,
Expand Down
20 changes: 4 additions & 16 deletions embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,11 @@ func evalLen8(par *CallParams) []byte {
return ret
}

func evalLen16(par *CallParams) []byte {
func evalLen(par *CallParams) []byte {
data := par.Arg(0)
if len(data) > math.MaxUint16 {
par.TracePanic("len16:: size of the data > uint16: %s", Fmt(data))
}
var ret [2]byte
binary.BigEndian.PutUint16(ret[:], uint16(len(data)))
par.Trace("len16:: %s -> %s", Fmt(data), Fmt(ret[:]))
var ret [8]byte
binary.BigEndian.PutUint64(ret[:], uint64(len(data)))
par.Trace("len:: %s -> %s", Fmt(data), Fmt(ret[:]))
return ret[:]
}

Expand Down Expand Up @@ -250,15 +247,6 @@ func evalEqualUint(par *CallParams) []byte {
return nil
}

func mustArithmArgsOld(par *CallParams, bytesSize int, name string) ([]byte, []byte) {
a0 := par.Arg(0)
a1 := par.Arg(1)
if len(a0) != bytesSize || len(a1) != bytesSize {
par.TracePanic("%s:: %d-bytes size parameters expected", name, bytesSize)
}
return a0, a1
}

// lexicographical comparison of two slices of equal length
func evalLessThan(par *CallParams) []byte {
a0 := par.Arg(0)
Expand Down
26 changes: 14 additions & 12 deletions library.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ func (lib *Library) init() {
}

func (lib *Library) extendWithUtilityFunctions() {
lib.Extend("equiv", "or(and($0,$1), and(not($0),not($1)))")
{
lib.MustTrue("equiv(0x, 0x)")
lib.MustTrue("equiv(2, 100)")
lib.MustTrue("not(equiv(0x, 0))")
}
lib.Extend("false", "or")
lib.Extend("true", "and")
//lib.Extend("equiv", "or(and($0,$1), and(not($0),not($1)))")
//{
// lib.MustTrue("equiv(0x, 0x)")
// lib.MustTrue("equiv(2, 100)")
// lib.MustTrue("not(equiv(0x, 0))")
//}
lib.Extend("false", "0x")
lib.Extend("true", "0xff")

lib.Extend("require", "or($0,$1)")
{
Expand Down Expand Up @@ -161,9 +161,11 @@ func (lib *Library) embedBase() {
{
lib.MustEqual("repeat(1,5)", "0x0101010101")
}
// 'len8' returns length up until 255 (256 and more panics)
lib.EmbedShort("len8", 1, evalLen8)
lib.EmbedShort("len16", 1, evalLen16)
// 'len' returns length as uint64 (8 bytes big endian)
lib.EmbedShort("len", 1, evalLen)
{
lib.MustTrue("equal(len(nil), u64/0)")
}
lib.EmbedShort("not", 1, evalNot)
{
lib.MustEqual("not(1)", "0x")
Expand Down Expand Up @@ -296,7 +298,7 @@ func (lib *Library) embedBaseCrypto() {
lib.EmbedLong("blake2b", -1, evalBlake2b)
h := blake2b.Sum256([]byte{1})
{
lib.MustEqual("len8(blake2b(1))", "32")
lib.MustEqual("len(blake2b(1))", "u64/32")
lib.MustEqual("blake2b(1)", fmt.Sprintf("0x%s", hex.EncodeToString(h[:])))
}
}
Expand Down
18 changes: 9 additions & 9 deletions library_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ func TestEval(t *testing.T) {
require.EqualValues(t, []byte{234, 123, 111, 111}, ret)
})
t.Run("7", func(t *testing.T) {
ret, err := lib.EvalFromSource(nil, "len8($1)", nil, []byte("123456789"))
ret, err := lib.EvalFromSource(nil, "len($1)", nil, []byte("123456789"))
require.NoError(t, err)
require.EqualValues(t, []byte{9}, ret)
require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 9}, ret)
})
t.Run("8", func(t *testing.T) {
ret, err := lib.EvalFromSource(nil, "concat(1,2,3,4,5)")
Expand All @@ -143,18 +143,18 @@ func TestEval(t *testing.T) {
})
t.Run("10", func(t *testing.T) {
tr := NewGlobalDataTracePrint(nil)
ret, err := lib.EvalFromSource(tr, "if(equal(len8($0),3), 0x01, 0x05)", []byte("abc"))
ret, err := lib.EvalFromSource(tr, "if(equal(len($0),u64/3), 0x01, 0x05)", []byte("abc"))
require.NoError(t, err)
require.EqualValues(t, []byte{1}, ret)
})
t.Run("11", func(t *testing.T) {
ret, err := lib.EvalFromSource(nil, "if(equal(len8($0),3), 0x01, 0x05)", []byte("abcdef"))
ret, err := lib.EvalFromSource(nil, "if(equal(len($0),u64/3), 0x01, 0x05)", []byte("abcdef"))
require.NoError(t, err)
require.EqualValues(t, []byte{5}, ret)
})
const longer = `
if(
not(equal(len8($0),5)), // comment 1
not(equal(len($0),u64/5)), // comment 1
0x01,
// comment without code
0x0506 // comment2
Expand Down Expand Up @@ -465,24 +465,24 @@ func TestTracing(t *testing.T) {
})
t.Run("no panic 5", func(t *testing.T) {
tr := NewGlobalDataLog(nil)
_, err := lib.EvalFromSource(tr, "equal(len8(slice(tail(0x0102030405,2),1,2)), 2)")
_, err := lib.EvalFromSource(tr, "equal(len(slice(tail(0x0102030405,2),1,2)), u64/2)")
require.NoError(t, err)
tr.PrintLog()
})
t.Run("no panic 6", func(t *testing.T) {
tr := NewGlobalDataLog(nil)
_, err := lib.EvalFromSource(tr, "equal(len16(slice(tail(0x0102030405,2),1,2)), u16/2)")
_, err := lib.EvalFromSource(tr, "equal(len(slice(tail(0x0102030405,2),1,2)), u64/2)")
require.NoError(t, err)
tr.PrintLog()
})
t.Run("no trace", func(t *testing.T) {
tr := NewGlobalDataNoTrace(nil)
_, err := lib.EvalFromSource(tr, "equal(len16(slice(tail(0x0102030405,2),1,2)), u16/2)")
_, err := lib.EvalFromSource(tr, "equal(len(slice(tail(0x0102030405,2),1,2)), u64/2)")
require.NoError(t, err)
})
t.Run("trace print", func(t *testing.T) {
tr := NewGlobalDataTracePrint(nil)
_, err := lib.EvalFromSource(tr, "equal(len16(slice(tail(0x0102030405,2),1,2)), u16/2)")
_, err := lib.EvalFromSource(tr, "equal(len(slice(tail(0x0102030405,2),1,2)), u64/2)")
require.NoError(t, err)
})
t.Run("trace if", func(t *testing.T) {
Expand Down

0 comments on commit 2231b4c

Please sign in to comment.