Skip to content

Commit

Permalink
alloc string
Browse files Browse the repository at this point in the history
  • Loading branch information
ltzmaxwell committed Jan 23, 2025
1 parent c9b5329 commit df30fed
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 47 deletions.
3 changes: 3 additions & 0 deletions gnovm/pkg/gnolang/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,12 @@ func (alloc *Allocator) Allocate(size int64) {
return
}

// if alloc on throwaway still exceeds memory,
// means GC does not work, panic.
if alloc.throwAway {
if alloc.bytes > alloc.maxBytes {
debug2.Println2("---exceed memory size............")
panic("exceed memory size")
}
}

Expand Down
1 change: 1 addition & 0 deletions gnovm/pkg/gnolang/op_assign.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func (m *Machine) doOpAssign() {

func (m *Machine) doOpAddAssign() {
s := m.PopStmt().(*AssignStmt)
debug2.Println2("doOpAddAssign, s: ", s)
rv := m.PopValue() // only one.
lv := m.PopAsPointer(s.Lhs[0])
if debug {
Expand Down
2 changes: 2 additions & 0 deletions gnovm/pkg/gnolang/op_binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,11 +685,13 @@ func isGeq(lv, rv *TypedValue) bool {

// for doOpAdd and doOpAddAssign.
func addAssign(alloc *Allocator, lv, rv *TypedValue) {
debug2.Println2("addAssign, lv: ", lv)
// set the result in lv.
// NOTE this block is replicated in op_assign.go
switch baseOf(lv.T) {
case StringType, UntypedStringType:
lv.V = alloc.NewString(lv.GetString() + rv.GetString())
lv.SetNeedsValueAllocation(true)
case IntType:
lv.SetInt(lv.GetInt() + rv.GetInt())
case Int8Type:
Expand Down
2 changes: 1 addition & 1 deletion gnovm/pkg/gnolang/op_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ EXEC_SWITCH:
if debug {
debug.Printf("EXEC: %v\n", s)
}
debug2.Printf2("EXEC: %v\n", s)
debug2.Printf2("EXEC: %v, type of s: %v \n", s, reflect.TypeOf(s))
switch cs := s.(type) {
case *AssignStmt:
switch cs.Op {
Expand Down
93 changes: 56 additions & 37 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
findGotoLoopDefines(ctx, bn)
findLoopUses1(ctx, bn)
findLoopUses2(ctx, bn)
findBlockAlloc(store, ctx, bn)
findBlockAllocation(store, ctx, bn)
}
return n
}
Expand Down Expand Up @@ -1019,8 +1019,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node {
cx := evalConst(store, last, n)
// built-in functions must be called.
if !cx.IsUndefined() &&
cx.T.Kind() == FuncKind &&
ftype != TRANS_CALL_FUNC {
cx.T.Kind() == FuncKind &&
ftype != TRANS_CALL_FUNC {
panic(fmt.Sprintf(
"use of builtin %s not in function call",
n.Name))
Expand Down Expand Up @@ -1837,8 +1837,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node {
// Case 1: If receiver is pointer type but n.X is
// not:
if rcvr != nil &&
rcvr.Kind() == PointerKind &&
nxt2.Kind() != PointerKind {
rcvr.Kind() == PointerKind &&
nxt2.Kind() != PointerKind {
// Go spec: "If x is addressable and &x's
// method set contains m, x.m() is shorthand
// for (&x).m()"
Expand Down Expand Up @@ -1870,8 +1870,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node {
))
}
} else if len(tr) > 0 &&
tr[len(tr)-1].IsDerefType() &&
nxt2.Kind() != PointerKind {
tr[len(tr)-1].IsDerefType() &&
nxt2.Kind() != PointerKind {
// Case 2: If tr[0] is deref type, but xt
// is not pointer type, replace n.X with
// &RefExpr{X: n.X}.
Expand Down Expand Up @@ -2385,13 +2385,13 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node {

// defineOrDecl merges the code logic from op define (:=) and declare (var/const).
func defineOrDecl(
store Store,
bn BlockNode,
n Node,
isConst bool,
nameExprs []NameExpr,
typeExpr Expr,
valueExprs []Expr,
store Store,
bn BlockNode,
n Node,
isConst bool,
nameExprs []NameExpr,
typeExpr Expr,
valueExprs []Expr,
) {
numNames := len(nameExprs)
numVals := len(valueExprs)
Expand Down Expand Up @@ -2425,15 +2425,15 @@ func defineOrDecl(
// parseAssignFromExprList parses assignment to multiple variables from a list of expressions.
// This function will alter the value of sts, tvs.
func parseAssignFromExprList(
store Store,
bn BlockNode,
n Node,
sts []Type,
tvs []TypedValue,
isConst bool,
nameExprs []NameExpr,
typeExpr Expr,
valueExprs []Expr,
store Store,
bn BlockNode,
n Node,
sts []Type,
tvs []TypedValue,
isConst bool,
nameExprs []NameExpr,
typeExpr Expr,
valueExprs []Expr,
) {
numNames := len(nameExprs)

Expand Down Expand Up @@ -2484,7 +2484,7 @@ func parseAssignFromExprList(
if len(valueExprs) > 0 {
vx := valueExprs[i]
if cx, ok := vx.(*ConstExpr); ok &&
!cx.TypedValue.IsUndefined() {
!cx.TypedValue.IsUndefined() {
if isConst {
// const _ = <const_expr>: static block should contain value
tvs[i] = cx.TypedValue
Expand Down Expand Up @@ -2512,14 +2512,14 @@ func parseAssignFromExprList(
// - a, b := n.(T)
// - a, b := n[i], where n is a map
func parseMultipleAssignFromOneExpr(
store Store,
bn BlockNode,
n Node,
sts []Type,
tvs []TypedValue,
nameExprs []NameExpr,
typeExpr Expr,
valueExpr Expr,
store Store,
bn BlockNode,
n Node,
sts []Type,
tvs []TypedValue,
nameExprs []NameExpr,
typeExpr Expr,
valueExpr Expr,
) {
var tuple *tupleType
numNames := len(nameExprs)
Expand Down Expand Up @@ -2853,7 +2853,7 @@ func findLoopUses1(ctx BlockNode, bn BlockNode) {
})
}

func findBlockAlloc(store Store, ctx BlockNode, bn BlockNode) {
func findBlockAllocation(store Store, ctx BlockNode, bn BlockNode) {
// create stack of BlockNodes.
var stack []BlockNode = make([]BlockNode, 0, 32)
var last BlockNode = ctx
Expand All @@ -2867,6 +2867,9 @@ func findBlockAlloc(store Store, ctx BlockNode, bn BlockNode) {
debug.Printf("findBlockAlloc %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage)
}
debug2.Printf2("findBlockAlloc %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage)
debug2.Println2("last: ", last)
debug2.Println2("last...BlockNames: ", last.GetBlockNames())
debug2.Println2("last...Externs: ", last.GetExternNames())

switch stage {
// ----------------------------------------
Expand All @@ -2889,7 +2892,7 @@ func findBlockAlloc(store Store, ctx BlockNode, bn BlockNode) {
// set alloc annotation
for i, rx := range n.Rhs {
debug2.Printf2("n.Rhs[%d] is %v, type of rx: %v \n", i, rx, reflect.TypeOf(rx))
switch rx.(type) {
switch rxx := rx.(type) {
case *NameExpr:
rt := evalStaticTypeOf(store, last, nx)
debug2.Println2("===rt: ", rt, reflect.TypeOf(rt))
Expand All @@ -2898,6 +2901,21 @@ func findBlockAlloc(store Store, ctx BlockNode, bn BlockNode) {
// value copy, alloc
nx.Alloc = true
}
case *ConstExpr:
if bx, ok := rxx.Source.(*BinaryExpr); ok {
debug2.Println2("BinaryExpr: ", bx)
if bx.Op == ADD {
lt := evalStaticTypeOf(store, last, bx.Left)
rt := evalStaticTypeOf(store, last, bx.Right)
debug2.Printf2("lt: %v, rt: %v: \n", lt, rt)
_, ok1 := lt.(PrimitiveType)
_, ok2 := rt.(PrimitiveType)
// s := "hello" + "world"
if ok1 && lt.Kind() == StringKind && ok2 && rt.Kind() == StringKind {
nx.Alloc = true
}
}
}
case *CompositeLitExpr, *FuncLitExpr: // TODO: more ...
nx.Alloc = true
}
Expand Down Expand Up @@ -3449,7 +3467,7 @@ func findContinuableNode(last BlockNode, store Store) {
}

func findBranchLabel(last BlockNode, label Name) (
bn BlockNode, depth uint8, bodyIdx int,
bn BlockNode, depth uint8, bodyIdx int,
) {
for {
switch cbn := last.(type) {
Expand Down Expand Up @@ -3489,7 +3507,7 @@ func findBranchLabel(last BlockNode, label Name) (
}

func findGotoLabel(last BlockNode, label Name) (
bn BlockNode, depth uint8, bodyIdx int,
bn BlockNode, depth uint8, bodyIdx int,
) {
for {
switch cbn := last.(type) {
Expand Down Expand Up @@ -3733,7 +3751,7 @@ func isNamedConversion(xt, t Type) bool {
// covert right to the type of left if one side is unnamed type and the other side is not

if t.IsNamed() && !xt.IsNamed() ||
!t.IsNamed() && xt.IsNamed() {
!t.IsNamed() && xt.IsNamed() {
return true
}
}
Expand Down Expand Up @@ -4851,6 +4869,7 @@ func isLocallyDefined(bn BlockNode, n Name) bool {
func isLocallyDefined2(bn BlockNode, n Name) bool {
debug2.Println2("isLocallyDefined2, n: ", n)
_, isLocal := bn.GetLocalIndex(n)
debug2.Println2("isLocal: ", isLocal)
return isLocal
}

Expand Down
16 changes: 8 additions & 8 deletions gnovm/tests/files/alloc1.gno
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ func main() {
}

// Output:
// MemStats 1: Allocator{maxBytes:10000000000, bytes:1944}
// MemStats 1: Allocator{maxBytes:9223372036854775807, bytes:1944}
// &(struct{("foo" string)} main.Foo)
// MemStats 2: Allocator{maxBytes:10000000000, bytes:6019}
// MemStats before GC1: Allocator{maxBytes:10000000000, bytes:7518}
// MemStats after GC1: Allocator{maxBytes:10000000000, bytes:2424}
// MemStats 2: Allocator{maxBytes:9223372036854775807, bytes:6027}
// MemStats before GC1: Allocator{maxBytes:9223372036854775807, bytes:7534}
// MemStats after GC1: Allocator{maxBytes:9223372036854775807, bytes:2720}
// func lit
// MemStats before GC2: Allocator{maxBytes:10000000000, bytes:5443}
// MemStats after GC2: Allocator{maxBytes:10000000000, bytes:2424}
// MemStats before GC3: Allocator{maxBytes:10000000000, bytes:3923}
// MemStats after GC3: Allocator{maxBytes:10000000000, bytes:2424}
// MemStats before GC2: Allocator{maxBytes:9223372036854775807, bytes:5747}
// MemStats after GC2: Allocator{maxBytes:9223372036854775807, bytes:2888}
// MemStats before GC3: Allocator{maxBytes:9223372036854775807, bytes:4395}
// MemStats after GC3: Allocator{maxBytes:9223372036854775807, bytes:2888}
3 changes: 2 additions & 1 deletion gnovm/tests/files/alloc_amino.gno
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import "runtime"
type Foo struct{ name string }

var f = Foo{name: "foo"}
var m = map[string]Foo{"a": f}

func main() {
println(f) // here should alloc amino for f
println(f, m) // here should alloc amino for f
runtime.GC()
}
14 changes: 14 additions & 0 deletions gnovm/tests/files/alloc_string.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// MAXALLOC: 25000
// max total allocation of 100 mb.

package main

import "runtime"

var s = "hello"

func main() {
s += "world" // new string
s += "!!!" // new string
runtime.GC()
}
12 changes: 12 additions & 0 deletions gnovm/tests/files/alloc_string2.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// MAXALLOC: 25000
// max total allocation of 100 mb.

package main

import "runtime"

func main() {
var s = "hello"
s += "world"
runtime.GC()
}
11 changes: 11 additions & 0 deletions gnovm/tests/files/alloc_string3.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// MAXALLOC: 25000
// max total allocation of 100 mb.

package main

import "runtime"

func main() {
s := "hello" + "world" // const
runtime.GC()
}
11 changes: 11 additions & 0 deletions gnovm/tests/files/alloc_string4.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// MAXALLOC: 25000
// max total allocation of 100 mb.

package main

import "runtime"

func main() {
s := "hello"
runtime.GC()
}

0 comments on commit df30fed

Please sign in to comment.