github.com/ontio/ontology@v1.14.4/vm/neovm/value_stack.go (about) 1 /* 2 * Copyright (C) 2018 The ontology Authors 3 * This file is part of The ontology library. 4 * 5 * The ontology is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Lesser General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * The ontology is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with The ontology. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 package neovm 20 21 import ( 22 "fmt" 23 24 "github.com/ontio/ontology/vm/neovm/errors" 25 "github.com/ontio/ontology/vm/neovm/types" 26 ) 27 28 const initialStackCap = 64 // to avoid reallocation 29 30 type ValueStack struct { 31 data []types.VmValue 32 limit int64 33 } 34 35 func NewValueStack(limit int64) *ValueStack { 36 return &ValueStack{ 37 data: make([]types.VmValue, 0, initialStackCap), 38 limit: limit, 39 } 40 } 41 42 func (self *ValueStack) Count() int { 43 return len(self.data) 44 } 45 46 func (self *ValueStack) Insert(index int64, t types.VmValue) error { 47 l := int64(len(self.data)) 48 if l >= self.limit { 49 return errors.ERR_OVER_LIMIT_STACK 50 } 51 if index > l || index < 0 { 52 return errors.ERR_INDEX_OUT_OF_BOUND 53 } 54 index = l - index 55 self.data = append(self.data, t) 56 copy(self.data[index+1:], self.data[index:]) 57 self.data[index] = t 58 return nil 59 } 60 61 func (self *ValueStack) Peek(index int64) (value types.VmValue, err error) { 62 l := int64(len(self.data)) 63 if index >= l || index < 0 { 64 err = errors.ERR_INDEX_OUT_OF_BOUND 65 return 66 } 67 index = l - index 68 value = self.data[index-1] 69 return 70 } 71 72 func (self *ValueStack) Remove(index int64) (value types.VmValue, err error) { 73 l := int64(len(self.data)) 74 if index >= l || index < 0 { 75 err = errors.ERR_INDEX_OUT_OF_BOUND 76 return 77 } 78 index = l - index 79 value = self.data[index-1] 80 self.data = append(self.data[:index-1], self.data[index:]...) 81 return 82 } 83 84 func (self *ValueStack) Set(index int, t types.VmValue) error { 85 l := len(self.data) 86 if index >= l || index < 0 { 87 return errors.ERR_INDEX_OUT_OF_BOUND 88 } 89 self.data[index] = t 90 return nil 91 } 92 93 func (self *ValueStack) Push(t types.VmValue) error { 94 if int64(len(self.data)) >= self.limit { 95 return errors.ERR_OVER_STACK_LEN 96 } 97 self.data = append(self.data, t) 98 return nil 99 } 100 101 func (self *ValueStack) PushMany(vals ...types.VmValue) error { 102 if int64(len(self.data)+len(vals)) > self.limit { 103 return errors.ERR_OVER_STACK_LEN 104 } 105 self.data = append(self.data, vals...) 106 return nil 107 } 108 109 func (self *ValueStack) PushAsArray(vals []types.VmValue) error { 110 111 if int64(len(self.data)+1) > self.limit { 112 return errors.ERR_OVER_STACK_LEN 113 } 114 arrayValue := types.NewArrayValue() 115 for _, val := range vals { 116 err := arrayValue.Append(val) 117 if err != nil { 118 return err 119 } 120 } 121 v := types.VmValueFromArrayVal(arrayValue) 122 self.data = append(self.data, v) 123 return nil 124 } 125 126 func (self *ValueStack) Pop() (value types.VmValue, err error) { 127 length := len(self.data) 128 if length == 0 { 129 err = errors.ERR_INDEX_OUT_OF_BOUND 130 return 131 } 132 value = self.data[length-1] 133 self.data = self.data[:length-1] 134 return 135 } 136 137 func (self *ValueStack) PopPair() (left, right types.VmValue, err error) { 138 right, err = self.Pop() 139 if err != nil { 140 return 141 } 142 left, err = self.Pop() 143 return 144 } 145 146 func (self *ValueStack) PopTriple() (left, middle, right types.VmValue, err error) { 147 middle, right, err = self.PopPair() 148 if err != nil { 149 return 150 } 151 left, err = self.Pop() 152 return 153 } 154 155 func (self *ValueStack) Swap(i, j int64) error { 156 l := int64(len(self.data)) 157 if i >= l || i < 0 { 158 return errors.ERR_INDEX_OUT_OF_BOUND 159 } 160 if j >= l || j < 0 { 161 return errors.ERR_INDEX_OUT_OF_BOUND 162 } 163 if i == j { 164 return nil 165 } 166 self.data[l-i-1], self.data[l-j-1] = self.data[l-j-1], self.data[l-i-1] 167 168 return nil 169 } 170 171 func (self *ValueStack) CopyTo(stack *ValueStack) error { 172 if int64(len(self.data)+len(stack.data)) > stack.limit { 173 return errors.ERR_OVER_STACK_LEN 174 } 175 stack.data = append(stack.data, self.data...) 176 return nil 177 } 178 179 func (self *ValueStack) Dump() string { 180 data := fmt.Sprintf("stack[%d]:\n", len(self.data)) 181 for i, item := range self.data { 182 i = len(self.data) - i 183 res := item.Dump() 184 data += fmt.Sprintf("%d:\t%s\n", i, res) 185 } 186 return data 187 }