reduce number of memory allocation in object binary operators

This commit is contained in:
Daniel Kang 2019-01-13 14:24:39 -08:00
parent d581cb24e4
commit ca128af33b
8 changed files with 193 additions and 58 deletions

View file

@ -29,6 +29,9 @@ func (o *Array) BinaryOp(op token.Token, rhs Object) (Object, error) {
if rhs, ok := rhs.(*Array); ok {
switch op {
case token.Add:
if len(rhs.Value) == 0 {
return o, nil
}
return &Array{Value: append(o.Value, rhs.Value...)}, nil
}
}

View file

@ -14,7 +14,7 @@ func builtinString(args ...Object) (Object, error) {
case *String:
return arg, nil
case *Undefined:
return undefined, nil
return UndefinedValue, nil
default:
return &String{Value: arg.String()}, nil
}
@ -44,7 +44,7 @@ func builtinInt(args ...Object) (Object, error) {
}
}
return undefined, nil
return UndefinedValue, nil
}
func builtinFloat(args ...Object) (Object, error) {
@ -64,7 +64,7 @@ func builtinFloat(args ...Object) (Object, error) {
}
}
return undefined, nil
return UndefinedValue, nil
}
func builtinBool(args ...Object) (Object, error) {
@ -100,5 +100,5 @@ func builtinChar(args ...Object) (Object, error) {
}
}
return undefined, nil
return UndefinedValue, nil
}

View file

@ -24,40 +24,96 @@ func (o *Float) BinaryOp(op token.Token, rhs Object) (Object, error) {
case *Float:
switch op {
case token.Add:
return &Float{o.Value + rhs.Value}, nil
r := o.Value + rhs.Value
if r == o.Value {
return o, nil
}
return &Float{Value: r}, nil
case token.Sub:
return &Float{o.Value - rhs.Value}, nil
r := o.Value - rhs.Value
if r == o.Value {
return o, nil
}
return &Float{Value: r}, nil
case token.Mul:
return &Float{o.Value * rhs.Value}, nil
r := o.Value * rhs.Value
if r == o.Value {
return o, nil
}
return &Float{Value: r}, nil
case token.Quo:
return &Float{o.Value / rhs.Value}, nil
r := o.Value / rhs.Value
if r == o.Value {
return o, nil
}
return &Float{Value: r}, nil
case token.Less:
return &Bool{o.Value < rhs.Value}, nil
if o.Value < rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.Greater:
return &Bool{o.Value > rhs.Value}, nil
if o.Value > rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.LessEq:
return &Bool{o.Value <= rhs.Value}, nil
if o.Value <= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.GreaterEq:
return &Bool{o.Value >= rhs.Value}, nil
if o.Value >= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
}
case *Int:
switch op {
case token.Add:
return &Float{o.Value + float64(rhs.Value)}, nil
r := o.Value + float64(rhs.Value)
if r == o.Value {
return o, nil
}
return &Float{Value: r}, nil
case token.Sub:
return &Float{o.Value - float64(rhs.Value)}, nil
r := o.Value - float64(rhs.Value)
if r == o.Value {
return o, nil
}
return &Float{Value: r}, nil
case token.Mul:
return &Float{o.Value * float64(rhs.Value)}, nil
r := o.Value * float64(rhs.Value)
if r == o.Value {
return o, nil
}
return &Float{Value: r}, nil
case token.Quo:
return &Float{o.Value / float64(rhs.Value)}, nil
r := o.Value / float64(rhs.Value)
if r == o.Value {
return o, nil
}
return &Float{Value: r}, nil
case token.Less:
return &Bool{o.Value < float64(rhs.Value)}, nil
if o.Value < float64(rhs.Value) {
return TrueValue, nil
}
return FalseValue, nil
case token.Greater:
return &Bool{o.Value > float64(rhs.Value)}, nil
if o.Value > float64(rhs.Value) {
return TrueValue, nil
}
return FalseValue, nil
case token.LessEq:
return &Bool{o.Value <= float64(rhs.Value)}, nil
if o.Value <= float64(rhs.Value) {
return TrueValue, nil
}
return FalseValue, nil
case token.GreaterEq:
return &Bool{o.Value >= float64(rhs.Value)}, nil
if o.Value >= float64(rhs.Value) {
return TrueValue, nil
}
return FalseValue, nil
}
}

View file

@ -23,35 +23,91 @@ func (o *Int) BinaryOp(op token.Token, rhs Object) (Object, error) {
case *Int:
switch op {
case token.Add:
return &Int{o.Value + rhs.Value}, nil
r := o.Value + rhs.Value
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.Sub:
return &Int{o.Value - rhs.Value}, nil
r := o.Value - rhs.Value
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.Mul:
return &Int{o.Value * rhs.Value}, nil
r := o.Value * rhs.Value
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.Quo:
return &Int{o.Value / rhs.Value}, nil
r := o.Value / rhs.Value
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.Rem:
return &Int{o.Value % rhs.Value}, nil
r := o.Value % rhs.Value
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.And:
return &Int{o.Value & rhs.Value}, nil
r := o.Value & rhs.Value
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.Or:
return &Int{o.Value | rhs.Value}, nil
r := o.Value | rhs.Value
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.Xor:
return &Int{o.Value ^ rhs.Value}, nil
r := o.Value ^ rhs.Value
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.AndNot:
return &Int{o.Value &^ rhs.Value}, nil
r := o.Value &^ rhs.Value
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.Shl:
return &Int{o.Value << uint(rhs.Value)}, nil
r := o.Value << uint64(rhs.Value)
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.Shr:
return &Int{o.Value >> uint(rhs.Value)}, nil
r := o.Value >> uint64(rhs.Value)
if r == o.Value {
return o, nil
}
return &Int{Value: r}, nil
case token.Less:
return &Bool{o.Value < rhs.Value}, nil
if o.Value < rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.Greater:
return &Bool{o.Value > rhs.Value}, nil
if o.Value > rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.LessEq:
return &Bool{o.Value <= rhs.Value}, nil
if o.Value <= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.GreaterEq:
return &Bool{o.Value >= rhs.Value}, nil
if o.Value >= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
}
case *Float:
switch op {
@ -64,13 +120,25 @@ func (o *Int) BinaryOp(op token.Token, rhs Object) (Object, error) {
case token.Quo:
return &Float{float64(o.Value) / rhs.Value}, nil
case token.Less:
return &Bool{float64(o.Value) < rhs.Value}, nil
if float64(o.Value) < rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.Greater:
return &Bool{float64(o.Value) > rhs.Value}, nil
if float64(o.Value) > rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.LessEq:
return &Bool{float64(o.Value) <= rhs.Value}, nil
if float64(o.Value) <= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.GreaterEq:
return &Bool{float64(o.Value) >= rhs.Value}, nil
if float64(o.Value) >= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
}
}

7
objects/objects.go Normal file
View file

@ -0,0 +1,7 @@
package objects
var (
TrueValue Object = &Bool{Value: true}
FalseValue Object = &Bool{Value: false}
UndefinedValue Object = &Undefined{}
)

View file

@ -23,6 +23,9 @@ func (o *String) BinaryOp(op token.Token, rhs Object) (Object, error) {
case *String:
switch op {
case token.Add:
if rhs.Value == "" {
return o, nil
}
return &String{Value: o.Value + rhs.Value}, nil
}
case *Char:

View file

@ -2,8 +2,6 @@ package objects
import "github.com/d5/tengo/compiler/token"
var undefined = &Undefined{}
type Undefined struct{}
func (o Undefined) TypeName() string {

View file

@ -15,9 +15,9 @@ const (
)
var (
trueObj objects.Object = &objects.Bool{Value: true}
falseObj objects.Object = &objects.Bool{Value: false}
undefinedObj objects.Object = &objects.Undefined{}
truePtr = &objects.TrueValue
falsePtr = &objects.FalseValue
undefinedPtr = &objects.UndefinedValue
builtinFuncs []objects.Object
)
@ -83,7 +83,7 @@ func (v *VM) Run() error {
}
case compiler.OpNull:
if err := v.push(&undefinedObj); err != nil {
if err := v.push(undefinedPtr); err != nil {
return err
}
case compiler.OpAdd:
@ -223,11 +223,11 @@ func (v *VM) Run() error {
left := v.pop()
if (*right).Equals(*left) {
if err := v.push(&trueObj); err != nil {
if err := v.push(truePtr); err != nil {
return err
}
} else {
if err := v.push(&falseObj); err != nil {
if err := v.push(falsePtr); err != nil {
return err
}
}
@ -236,11 +236,11 @@ func (v *VM) Run() error {
left := v.pop()
if (*right).Equals(*left) {
if err := v.push(&falseObj); err != nil {
if err := v.push(falsePtr); err != nil {
return err
}
} else {
if err := v.push(&trueObj); err != nil {
if err := v.push(truePtr); err != nil {
return err
}
}
@ -271,22 +271,22 @@ func (v *VM) Run() error {
case compiler.OpPop:
_ = v.pop()
case compiler.OpTrue:
if err := v.push(&trueObj); err != nil {
if err := v.push(truePtr); err != nil {
return err
}
case compiler.OpFalse:
if err := v.push(&falseObj); err != nil {
if err := v.push(falsePtr); err != nil {
return err
}
case compiler.OpLNot:
operand := v.pop()
if (*operand).IsFalsy() {
if err := v.push(&trueObj); err != nil {
if err := v.push(truePtr); err != nil {
return err
}
} else {
if err := v.push(&falseObj); err != nil {
if err := v.push(falsePtr); err != nil {
return err
}
}
@ -528,7 +528,7 @@ func (v *VM) Run() error {
v.sp = frame.basePointer - 1
if err := v.push(&undefinedObj); err != nil {
if err := v.push(undefinedPtr); err != nil {
return err
}
@ -672,11 +672,11 @@ func (v *VM) Run() error {
iterator := v.pop()
b := (*iterator).(objects.Iterator).Next()
if b {
if err := v.push(&trueObj); err != nil {
if err := v.push(truePtr); err != nil {
return err
}
} else {
if err := v.push(&falseObj); err != nil {
if err := v.push(falsePtr); err != nil {
return err
}
}
@ -783,7 +783,7 @@ func (v *VM) executeArrayIndex(arr *objects.Array, index int64) error {
}
func (v *VM) executeMapIndex(map_ *objects.Map, key string) error {
var res = undefinedObj
var res = objects.UndefinedValue
val, ok := map_.Value[key]
if ok {
res = val
@ -974,7 +974,7 @@ func (v *VM) callCallable(callable objects.Callable, numArgs int) error {
// nil return -> undefined
if res == nil {
res = undefinedObj
res = objects.UndefinedValue
}
return v.push(&res)