diff options
-rw-r--r-- | core/vm/sqlvm/errors/errors.go | 2 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/functions.go | 11 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions.go | 36 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions_test.go | 4 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/jumptable.go | 3 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/opcodes.go | 5 |
6 files changed, 59 insertions, 2 deletions
diff --git a/core/vm/sqlvm/errors/errors.go b/core/vm/sqlvm/errors/errors.go index b6c3909af..e69993300 100644 --- a/core/vm/sqlvm/errors/errors.go +++ b/core/vm/sqlvm/errors/errors.go @@ -123,6 +123,7 @@ const ( ErrorCodeDataLengthNotMatch ErrorCodeMultipleEscapeByte ErrorCodePendingEscapeByte + ErrorCodeNoSuchFunction ) var errorCodeMap = [...]string{ @@ -157,6 +158,7 @@ var errorCodeMap = [...]string{ ErrorCodeDataLengthNotMatch: "data length not match", ErrorCodeMultipleEscapeByte: "multiple escape byte", ErrorCodePendingEscapeByte: "pending escape byte", + ErrorCodeNoSuchFunction: "no such function", } func (c ErrorCode) Error() string { diff --git a/core/vm/sqlvm/runtime/functions.go b/core/vm/sqlvm/runtime/functions.go new file mode 100644 index 000000000..798f5a573 --- /dev/null +++ b/core/vm/sqlvm/runtime/functions.go @@ -0,0 +1,11 @@ +package runtime + +import ( + "github.com/dexon-foundation/dexon/core/vm/sqlvm/common" +) + +type fn func(*common.Context, []*Operand, uint64) (*Operand, error) + +var ( + fnTable = map[string]fn{} +) diff --git a/core/vm/sqlvm/runtime/instructions.go b/core/vm/sqlvm/runtime/instructions.go index 5cd622180..cd034955a 100644 --- a/core/vm/sqlvm/runtime/instructions.go +++ b/core/vm/sqlvm/runtime/instructions.go @@ -1830,3 +1830,39 @@ func (t Tuple) neg(ctx *common.Context, meta []ast.DataType) (t2 Tuple, err erro } return } + +func opFunc(ctx *common.Context, ops, registers []*Operand, output uint) (err error) { + if len(ops) < 2 { + err = se.ErrorCodeInvalidOperandNum + return + } + + var ( + op, funcID = ops[0], ops[1] + op2 *Operand + length uint64 + ) + + if op.IsImmediate { + length, err = ast.DecimalToUint64(op.Data[0][0].Value) + if err != nil { + return + } + } else { + length = uint64(len(op.Data)) + } + + fn, ok := fnTable[string(funcID.Data[0][0].Bytes)] + if !ok { + err = se.ErrorCodeNoSuchFunction + return + } + + result, err = fnTable[id](ctx, ops[2:], length) + if err != nil { + return + } + + registers[output] = op2 + return +} diff --git a/core/vm/sqlvm/runtime/instructions_test.go b/core/vm/sqlvm/runtime/instructions_test.go index c071045e6..a399ad557 100644 --- a/core/vm/sqlvm/runtime/instructions_test.go +++ b/core/vm/sqlvm/runtime/instructions_test.go @@ -210,7 +210,7 @@ type opLoadTestCase struct { func (s *opLoadSuite) SetupTest() { s.ctx = &common.Context{} - s.ctx.Storage = s.newStorage() + s.ctx.Storage = newStorage() targetTableRef := schema.TableRef(1) s.headHash = s.ctx.Storage.GetRowPathHash(targetTableRef, uint64(123456)) s.address = dexCommon.HexToAddress("0x6655") @@ -374,7 +374,7 @@ func newFieldsOperand(fields []uint8) *Operand { return o } -func (s *opLoadSuite) newStorage() *common.Storage { +func newStorage() *common.Storage { db := ethdb.NewMemDatabase() state, _ := state.New(dexCommon.Hash{}, state.NewDatabase(db)) storage := common.NewStorage(state) diff --git a/core/vm/sqlvm/runtime/jumptable.go b/core/vm/sqlvm/runtime/jumptable.go index ef1fc8841..2930520a1 100644 --- a/core/vm/sqlvm/runtime/jumptable.go +++ b/core/vm/sqlvm/runtime/jumptable.go @@ -31,6 +31,9 @@ var jumpTable = [256]OpFunction{ CUT: opCut, RANGE: opRange, + // 0x50 + FUNC: opFunc, + // 0x60 LOAD: opLoad, } diff --git a/core/vm/sqlvm/runtime/opcodes.go b/core/vm/sqlvm/runtime/opcodes.go index 5a0e5dd95..e65565670 100644 --- a/core/vm/sqlvm/runtime/opcodes.go +++ b/core/vm/sqlvm/runtime/opcodes.go @@ -51,6 +51,11 @@ const ( RANGE ) +// 0x50 range - function ops +const ( + FUNC = iota + 0x50 +) + // 0x60 range - storage ops const ( INSERT = iota + 0x60 |