about summary refs log tree commit diff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/lang/vm/exec.go91
-rw-r--r--pkg/lang/vm/mem/cell.go2
-rw-r--r--pkg/lang/vm/mem/mem.go4
-rw-r--r--pkg/lang/vm/mem/mem_test.go2
-rw-r--r--pkg/lang/vm/utils.go4
-rw-r--r--pkg/lang/vm/value/cells.go48
-rw-r--r--pkg/lang/vm/value/value.go35
7 files changed, 138 insertions, 48 deletions
diff --git a/pkg/lang/vm/exec.go b/pkg/lang/vm/exec.go
index a64751a..8cdcdcc 100644
--- a/pkg/lang/vm/exec.go
+++ b/pkg/lang/vm/exec.go
@@ -120,7 +120,11 @@ func (vm *VM) execGetGlobal(name string) error {
 		return ErrNoSuchGlobal{GlobalName: name}
 	}
 
-	v = v.Clone(vm.memory)
+	v, err = v.Clone(vm.memory)
+	if err != nil {
+		return err
+	}
+
 	vm.stack.Push(v)
 	return nil
 }
@@ -150,7 +154,10 @@ func (vm *VM) execGetLocal(offset int) error {
 		return err
 	}
 
-	v := local.Clone(vm.memory)
+	v, err := local.Clone(vm.memory)
+	if err != nil {
+		return err
+	}
 
 	vm.stack.Push(v)
 	return nil
@@ -167,7 +174,9 @@ func (vm *VM) execSetLocal(offset int) error {
 		return err
 	}
 
-	local.Drop(vm.memory)
+	if err := local.Drop(vm.memory); err != nil {
+		return err
+	}
 
 	stackIndex := vm.stack.LocalToStackIndex(offset)
 	return vm.stack.Set(stackIndex, new)
@@ -211,10 +220,17 @@ func (vm *VM) execGetMember(name string) error {
 		objCell := cell.(value.ObjectCell)
 		member, ok := objCell.Get()[name]
 		if ok {
-			member = member.Clone(vm.memory)
+			member, err = member.Clone(vm.memory)
+			if err != nil {
+				return err
+			}
 
 			vm.stack.Push(member)
-			parent.Drop(vm.memory)
+
+			if err := parent.Drop(vm.memory); err != nil {
+				return err
+			}
+
 			return nil
 		}
 	}
@@ -250,7 +266,11 @@ func (vm *VM) execGetMember(name string) error {
 			// method = method.Clone(vm.memory) will only be necessary when we support methods with environments.
 
 			vm.stack.Push(method)
-			parent.Drop(vm.memory)
+
+			if err := parent.Drop(vm.memory); err != nil {
+				return err
+			}
+
 			return nil
 		}
 	}
@@ -303,7 +323,9 @@ func (vm *VM) execGetMember(name string) error {
 	val := value.NewFunction(code.Pos{}, 0).WithData(member)
 	vm.stack.Push(val)
 
-	parent.Drop(vm.memory)
+	if err := parent.Drop(vm.memory); err != nil {
+		return err
+	}
 
 	return nil
 }
@@ -342,7 +364,9 @@ func (vm *VM) execSetMember(name string) error {
 		return err
 	}
 
-	parent.Drop(vm.memory)
+	if err := parent.Drop(vm.memory); err != nil {
+		return err
+	}
 	// v was moved, no need to drop it.
 
 	return nil
@@ -365,7 +389,11 @@ func (vm *VM) execGetEnv(envIndex int) error {
 	if outletCell != nil {
 		// Outlet is not null, so value escaped.
 		outlet := outletCell.(value.OutletCell).Get()
-		val := outlet.Clone(vm.memory)
+		val, err := outlet.Clone(vm.memory)
+		if err != nil {
+			return err
+		}
+
 		vm.stack.Push(val)
 		return nil
 	}
@@ -377,7 +405,11 @@ func (vm *VM) execGetEnv(envIndex int) error {
 		return err
 	}
 
-	val = val.Clone(vm.memory)
+	val, err = val.Clone(vm.memory)
+	if err != nil {
+		return err
+	}
+
 	vm.stack.Push(val)
 
 	return nil
@@ -404,7 +436,10 @@ func (vm *VM) execSetEnv(envIndex int) error {
 	if outletCell != nil {
 		// Outlet is not null, so value escaped.
 		outlet := outletCell.(value.OutletCell).Get()
-		outlet.Drop(vm.memory)
+		if err := outlet.Drop(vm.memory); err != nil {
+			return err
+		}
+
 		vm.memory.Set(outletPtr, value.OutletCell(new))
 		return nil
 	}
@@ -415,7 +450,9 @@ func (vm *VM) execSetEnv(envIndex int) error {
 		return err
 	}
 
-	old.Drop(vm.memory)
+	if err := old.Drop(vm.memory); err != nil {
+		return err
+	}
 
 	return vm.stack.Set(stackIndex, new)
 }
@@ -583,8 +620,13 @@ func (vm *VM) execGenericBinaryOperation(op code.Op, fns typesToBinaryOperation)
 		return err
 	}
 
-	x.Drop(vm.memory)
-	y.Drop(vm.memory)
+	if err := x.Drop(vm.memory); err != nil {
+		return err
+	}
+
+	if err := y.Drop(vm.memory); err != nil {
+		return err
+	}
 
 	vm.stack.Push(res)
 	return nil
@@ -735,8 +777,13 @@ func (vm *VM) execEq() error {
 	}
 
 	result := func(res bool) error {
-		x.Drop(vm.memory)
-		y.Drop(vm.memory)
+		if err := x.Drop(vm.memory); err != nil {
+			return err
+		}
+
+		if err := y.Drop(vm.memory); err != nil {
+			return err
+		}
 
 		vm.stack.Push(value.NewBool(res))
 		return nil
@@ -812,7 +859,12 @@ func (vm *VM) execIndex() error {
 			if err != nil {
 				return err
 			}
-			val = val.Clone(vm.memory)
+
+			val, err = val.Clone(vm.memory)
+			if err != nil {
+				return err
+			}
+
 			vm.stack.Push(val)
 		default:
 			return ErrInvalidOperandTypes{
@@ -1027,7 +1079,10 @@ func (vm *VM) execTempArrLen() error {
 		}
 		res := value.NewInt(int64(len))
 		vm.stack.Push(res)
-		a.Drop(vm.memory)
+
+		if err := a.Drop(vm.memory); err != nil {
+			return err
+		}
 	default:
 		return ErrInvalidOperandTypes{
 			Op: code.OpTempArrLen,
diff --git a/pkg/lang/vm/mem/cell.go b/pkg/lang/vm/mem/cell.go
index 85d6c34..0a5e80c 100644
--- a/pkg/lang/vm/mem/cell.go
+++ b/pkg/lang/vm/mem/cell.go
@@ -49,6 +49,6 @@ type cell struct {
 }
 
 type CellData interface {
-	DropCell(Mem)
+	DropCell(Mem) error
 	MatchingCellKind() CellKind
 }
diff --git a/pkg/lang/vm/mem/mem.go b/pkg/lang/vm/mem/mem.go
index 99412ea..b590bcc 100644
--- a/pkg/lang/vm/mem/mem.go
+++ b/pkg/lang/vm/mem/mem.go
@@ -144,7 +144,9 @@ func (m *memImpl) Release(ptr Ptr) error {
 		c := m.cells[ptr].data
 
 		if c != nil {
-			c.DropCell(m)
+			if err := c.DropCell(m); err != nil {
+				return err
+			}
 		}
 
 		m.cells[ptr] = cell{}
diff --git a/pkg/lang/vm/mem/mem_test.go b/pkg/lang/vm/mem/mem_test.go
index f916e49..0c74093 100644
--- a/pkg/lang/vm/mem/mem_test.go
+++ b/pkg/lang/vm/mem/mem_test.go
@@ -208,7 +208,7 @@ func TestChainDrop(t *testing.T) {
 	assert.Equal(t, mem.CellKindArray, m.Kind(mem.Ptr(5)))
 	assert.Equal(t, mem.CellKindEmpty, m.Kind(mem.Ptr(6)))
 
-	val.Drop(m)
+	assert.NoError(t, val.Drop(m))
 
 	for _, ptr := range []mem.Ptr{1, 2, 3, 4, 5, 6} {
 		assert.Equal(t, mem.CellKindEmpty, m.Kind(ptr))
diff --git a/pkg/lang/vm/utils.go b/pkg/lang/vm/utils.go
index 975d31b..eddcc11 100644
--- a/pkg/lang/vm/utils.go
+++ b/pkg/lang/vm/utils.go
@@ -12,7 +12,9 @@ func (vm *VM) popAndDrop() (value.Value, error) {
 	if err != nil {
 		return value.Value{}, err
 	}
-	v.Drop(vm.memory)
+	if err := v.Drop(vm.memory); err != nil {
+		return value.Value{}, err
+	}
 	return v, nil
 }
 
diff --git a/pkg/lang/vm/value/cells.go b/pkg/lang/vm/value/cells.go
index 19ecfde..646f3c1 100644
--- a/pkg/lang/vm/value/cells.go
+++ b/pkg/lang/vm/value/cells.go
@@ -1,16 +1,21 @@
 package value
 
 import (
+	"fmt"
 	"jinx/pkg/lang/vm/code"
 	"jinx/pkg/lang/vm/mem"
 )
 
 type ArrayCell []Value
 
-func (a ArrayCell) DropCell(m mem.Mem) {
+func (a ArrayCell) DropCell(m mem.Mem) error {
 	for _, v := range a {
-		v.Drop(m)
+		if err := v.Drop(m); err != nil {
+			return err
+		}
 	}
+
+	return nil
 }
 
 func (a ArrayCell) MatchingCellKind() mem.CellKind {
@@ -23,7 +28,8 @@ func (a ArrayCell) Get() []Value {
 
 type StringCell string
 
-func (s StringCell) DropCell(m mem.Mem) {
+func (s StringCell) DropCell(m mem.Mem) error {
+	return nil
 }
 
 func (s StringCell) MatchingCellKind() mem.CellKind {
@@ -38,10 +44,14 @@ type ObjectCell struct {
 	Members map[string]Value
 }
 
-func (o ObjectCell) DropCell(m mem.Mem) {
+func (o ObjectCell) DropCell(m mem.Mem) error {
 	for _, v := range o.Members {
-		v.Drop(m)
+		if err := v.Drop(m); err != nil {
+			return err
+		}
 	}
+
+	return nil
 }
 
 func (o ObjectCell) MatchingCellKind() mem.CellKind {
@@ -54,17 +64,23 @@ func (o ObjectCell) Get() map[string]Value {
 
 type TypeCell Type
 
-func (t TypeCell) DropCell(m mem.Mem) {
+func (t TypeCell) DropCell(m mem.Mem) error {
 	typ := t.Get()
 	for _, f := range typ.Methods {
 		// Wrap data in a Value to drop it.
 		val := NewFunction(code.Pos{}, 0).WithData(f)
-		val.Drop(m)
+		if err := val.Drop(m); err != nil {
+			return err
+		}
 	}
 
 	for _, v := range typ.Statics {
-		v.Drop(m)
+		if err := v.Drop(m); err != nil {
+			return err
+		}
 	}
+
+	return nil
 }
 
 func (t TypeCell) MatchingCellKind() mem.CellKind {
@@ -77,8 +93,8 @@ func (t TypeCell) Get() Type {
 
 type OutletCell Value
 
-func (o OutletCell) DropCell(m mem.Mem) {
-	Value(o).Drop(m)
+func (o OutletCell) DropCell(m mem.Mem) error {
+	return Value(o).Drop(m)
 }
 
 func (o OutletCell) MatchingCellKind() mem.CellKind {
@@ -91,10 +107,14 @@ func (o OutletCell) Get() Value {
 
 type EnvCell Env
 
-func (e EnvCell) DropCell(m mem.Mem) {
+func (e EnvCell) DropCell(m mem.Mem) error {
 	for _, v := range e.references {
-		m.Release(v.outlet)
+		if err := m.Release(v.outlet); err != nil {
+			return err
+		}
 	}
+
+	return nil
 }
 
 func (e EnvCell) MatchingCellKind() mem.CellKind {
@@ -107,8 +127,8 @@ func (e EnvCell) Get() Env {
 
 type GlobalCell Value
 
-func (g GlobalCell) DropCell(m mem.Mem) {
-	panic("global cell cannot be dropped")
+func (g GlobalCell) DropCell(m mem.Mem) error {
+	return fmt.Errorf("global cell cannot be dropped")
 }
 
 func (g GlobalCell) MatchingCellKind() mem.CellKind {
diff --git a/pkg/lang/vm/value/value.go b/pkg/lang/vm/value/value.go
index cce2f5e..e2750f4 100644
--- a/pkg/lang/vm/value/value.go
+++ b/pkg/lang/vm/value/value.go
@@ -142,20 +142,28 @@ func (v Value) IsEmpty() bool {
 	return v == Value{}
 }
 
-func (v Value) Clone(m mem.Mem) Value {
+func (v Value) Clone(m mem.Mem) (Value, error) {
 	if v.t == StringType {
 		str := v.d.(StringData)
-		m.Retain(str.data)
+		if err := m.Retain(str.data); err != nil {
+			return Value{}, err
+		}
 	}
 
 	if v.t == ArrayType {
 		arr := v.d.(ArrayData)
-		m.Retain(arr.data)
+		if err := m.Retain(arr.data); err != nil {
+			return Value{}, err
+		}
 	}
 
 	if v.t == FunctionType {
 		fn := v.d.(FunctionData)
-		m.Retain(fn.env)
+		if !fn.env.IsNull() {
+			if err := m.Retain(fn.env); err != nil {
+				return Value{}, err
+			}
+		}
 	}
 
 	// If value has an outlet don't copy it into the clone,
@@ -163,28 +171,31 @@ func (v Value) Clone(m mem.Mem) Value {
 	// I don't know if this fixes the entire problem, but it seems to work.
 	v.outlet = mem.NullPtr
 
-	return v
+	return v, nil
 }
 
-func (v Value) Drop(m mem.Mem) {
+func (v Value) Drop(m mem.Mem) error {
 	// If value has an outlet, don't drop it and instead move it to the outlet.
 	if !v.outlet.IsNull() {
-		m.Set(v.outlet, OutletCell(v))
-		return
+		return m.Set(v.outlet, OutletCell(v))
 	}
 
 	if v.t == StringType {
 		str := v.d.(StringData)
-		m.Release(str.data)
+		return m.Release(str.data)
 	}
 
 	if v.t == ArrayType {
 		arr := v.d.(ArrayData)
-		m.Release(arr.data)
+		return m.Release(arr.data)
 	}
 
 	if v.t == FunctionType {
-		f := v.d.(FunctionData)
-		m.Release(f.env)
+		fn := v.d.(FunctionData)
+		if !fn.env.IsNull() {
+			return m.Release(fn.env)
+		}
 	}
+
+	return nil
 }