github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/core/wavm/gas/gas.go (about)

     1  // Copyright 2019 The go-vnt Authors
     2  // This file is part of the go-vnt library.
     3  //
     4  // The go-vnt library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-vnt library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package gas
    18  
    19  import (
    20  	"sort"
    21  
    22  	"github.com/vntchain/go-vnt/common"
    23  	"github.com/vntchain/go-vnt/core/wavm/internal/stack"
    24  	"github.com/vntchain/go-vnt/core/wavm/utils"
    25  	"github.com/vntchain/vnt-wasm/disasm"
    26  	"github.com/vntchain/vnt-wasm/wasm"
    27  	ops "github.com/vntchain/vnt-wasm/wasm/operators"
    28  )
    29  
    30  type BlockEntry struct {
    31  	/// Index of the first instruction (aka `Opcode`) in the block.
    32  	starPos int
    33  	/// Sum of costs of all instructions until end of the block.
    34  	cost  uint64
    35  	index []int
    36  }
    37  
    38  type BlockEntrys []*BlockEntry
    39  
    40  func (block BlockEntrys) Len() int           { return len(block) }
    41  func (block BlockEntrys) Less(i, j int) bool { return block[i].starPos-block[j].starPos < 0 }
    42  func (block BlockEntrys) Swap(i, j int)      { block[i], block[j] = block[j], block[i] }
    43  
    44  type Counter struct {
    45  	/// All blocks in the order of theirs start position.
    46  	blocks BlockEntrys
    47  
    48  	// Stack of blocks. Each element is an index to a `self.blocks` vector.
    49  	stack *stack.Stack
    50  }
    51  
    52  func NewCounter() *Counter {
    53  	return &Counter{
    54  		blocks: BlockEntrys{},
    55  		stack:  &stack.Stack{},
    56  	}
    57  }
    58  
    59  func (counter *Counter) Begin(cursor int) {
    60  	blockIdx := len(counter.blocks)
    61  	counter.blocks = append(counter.blocks, &BlockEntry{
    62  		starPos: cursor,
    63  		cost:    1,
    64  		index:   []int{},
    65  	})
    66  	counter.stack.Push(uint64(blockIdx))
    67  }
    68  
    69  func (counter *Counter) Finalize() {
    70  	counter.stack.Pop()
    71  }
    72  
    73  func (counter *Counter) Increment(value uint64, index int) {
    74  	// var top uint64
    75  	// if counter.stack.Len() == 0 {
    76  	// 	top = 0
    77  	// } else {
    78  	// 	top = counter.stack.Top()
    79  	// }
    80  	top := counter.stack.Top()
    81  
    82  	topBlock := counter.blocks[top]
    83  	topBlock.cost = topBlock.cost + value
    84  	topBlock.index = append(topBlock.index, index)
    85  }
    86  
    87  func InjectCounter(disassembly []disasm.Instr, module *wasm.Module, rule Gas) []disasm.Instr {
    88  	_, _, gasIndex := utils.GetIndex(module)
    89  	if gasIndex == -1 {
    90  		return disassembly
    91  	}
    92  	counter := NewCounter()
    93  	counter.Begin(0)
    94  	for i, instr := range disassembly {
    95  		switch instr.Op.Code {
    96  		case ops.Block, ops.Loop, ops.If:
    97  			//instruction_cost = rules.process(instruction)?;
    98  			// instrCost := 1 //instr的gas消耗规则
    99  			// counter.Increment(uint32(instrCost), i)
   100  
   101  			// Begin new block. The cost of the following opcodes until `End` or `Else` will
   102  			// be included into this block.
   103  			counter.Begin(i + 1)
   104  		case ops.Br, ops.BrIf, ops.BrTable:
   105  			counter.Finalize()
   106  			// instrCost := 1 //instr的gas消耗规则
   107  			// counter.Increment(uint32(instrCost), i)
   108  			counter.Begin(i + 1)
   109  		case ops.End:
   110  			counter.Finalize()
   111  		case ops.Else:
   112  			counter.Finalize()
   113  			counter.Begin(i + 1)
   114  		default:
   115  			instrCost := rule.GasCost(instr.Op.Code)
   116  			counter.Increment(instrCost, i)
   117  		}
   118  	}
   119  
   120  	for _, v := range counter.blocks {
   121  		if len(v.index) > 0 {
   122  			v.starPos = v.index[0]
   123  		}
   124  	}
   125  	sort.Sort(counter.blocks)
   126  	offset := 0
   127  	for _, v := range counter.blocks {
   128  		pos := v.starPos + offset
   129  		constOp, _ := ops.New(ops.I64Const)
   130  		constInstr := disasm.Instr{Op: constOp, Immediates: []interface{}{int64(v.cost)}}
   131  		callOp, _ := ops.New(ops.Call)
   132  		callInstr := disasm.Instr{Op: callOp, Immediates: []interface{}{uint32(gasIndex)}}
   133  		//disassembly=append(disassembly[0:pos],)
   134  		res := common.Insert(disassembly, pos, []disasm.Instr{callInstr})
   135  		disassembly = res.([]disasm.Instr)
   136  		res = common.Insert(disassembly, pos, []disasm.Instr{constInstr})
   137  		disassembly = res.([]disasm.Instr)
   138  		offset += 2
   139  	}
   140  	return disassembly
   141  }