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 { if rhs, ok := rhs.(*Array); ok {
switch op { switch op {
case token.Add: case token.Add:
if len(rhs.Value) == 0 {
return o, nil
}
return &Array{Value: append(o.Value, rhs.Value...)}, nil return &Array{Value: append(o.Value, rhs.Value...)}, nil
} }
} }

View file

@ -14,7 +14,7 @@ func builtinString(args ...Object) (Object, error) {
case *String: case *String:
return arg, nil return arg, nil
case *Undefined: case *Undefined:
return undefined, nil return UndefinedValue, nil
default: default:
return &String{Value: arg.String()}, nil 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) { 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) { 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: case *Float:
switch op { switch op {
case token.Add: 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: 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: 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: 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: case token.Less:
return &Bool{o.Value < rhs.Value}, nil if o.Value < rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.Greater: case token.Greater:
return &Bool{o.Value > rhs.Value}, nil if o.Value > rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.LessEq: case token.LessEq:
return &Bool{o.Value <= rhs.Value}, nil if o.Value <= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.GreaterEq: case token.GreaterEq:
return &Bool{o.Value >= rhs.Value}, nil if o.Value >= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
} }
case *Int: case *Int:
switch op { switch op {
case token.Add: 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: 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: 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: 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: 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: 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: 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: 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: case *Int:
switch op { switch op {
case token.Add: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: case token.Less:
return &Bool{o.Value < rhs.Value}, nil if o.Value < rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.Greater: case token.Greater:
return &Bool{o.Value > rhs.Value}, nil if o.Value > rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.LessEq: case token.LessEq:
return &Bool{o.Value <= rhs.Value}, nil if o.Value <= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
case token.GreaterEq: case token.GreaterEq:
return &Bool{o.Value >= rhs.Value}, nil if o.Value >= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
} }
case *Float: case *Float:
switch op { switch op {
@ -64,13 +120,25 @@ func (o *Int) BinaryOp(op token.Token, rhs Object) (Object, error) {
case token.Quo: case token.Quo:
return &Float{float64(o.Value) / rhs.Value}, nil return &Float{float64(o.Value) / rhs.Value}, nil
case token.Less: 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: 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: 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: 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: case *String:
switch op { switch op {
case token.Add: case token.Add:
if rhs.Value == "" {
return o, nil
}
return &String{Value: o.Value + rhs.Value}, nil return &String{Value: o.Value + rhs.Value}, nil
} }
case *Char: case *Char:

View file

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

View file

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