Skip to content

Commit

Permalink
save
Browse files Browse the repository at this point in the history
  • Loading branch information
petar-dambovaliev committed Nov 8, 2024
1 parent f62c8be commit ce6141c
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 230 deletions.
27 changes: 0 additions & 27 deletions gnovm/pkg/gnolang/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,33 +136,6 @@ func (s Stacktrace) String() string {
return builder.String()
}

func (s Stacktrace) StringDoubleSlash() string {
var builder strings.Builder

for i := 0; i < len(s.Calls); i++ {
if s.NumFramesElided > 0 && i == maxStacktraceSize/2 {
fmt.Fprintf(&builder, "...%d frame(s) elided...\\n", s.NumFramesElided)
}

call := s.Calls[i]
cx := call.Frame.Source.(*CallExpr)
switch {
case call.Frame.Func != nil && call.Frame.Func.IsNative():
fmt.Fprintf(&builder, "%s\\n", toExprTrace(cx))
fmt.Fprintf(&builder, " gonative:%s.%s\\n", call.Frame.Func.NativePkg, call.Frame.Func.NativeName)
case call.Frame.Func != nil:
fmt.Fprintf(&builder, "%s\\n", toExprTrace(cx))
fmt.Fprintf(&builder, " %s/%s:%d\\n", call.Frame.Func.PkgPath, call.Frame.Func.FileName, call.Stmt.GetLine())
case call.Frame.GoFunc != nil:
fmt.Fprintf(&builder, "%s\\n", toExprTrace(cx))
fmt.Fprintf(&builder, " gofunction:%s\\n", call.Frame.GoFunc.Value.Type())
default:
panic("StacktraceCall has a non-call Frame")
}
}
return builder.String()
}

func toExprTrace(ex Expr) string {
switch ex := ex.(type) {
case *CallExpr:
Expand Down
196 changes: 25 additions & 171 deletions gnovm/pkg/gnolang/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -827,65 +827,18 @@ func (m *Machine) RunFunc(fn Name) {
m.RunStatement(S(Call(Nx(fn))))
}

func (m *Machine) resume() {
defer func() {
if r := recover(); r != nil {
switch r := r.(type) {
case UnhandledPanicError:
panic(fmt.Sprintf("Machine.RunMain() panic: %s\nStacktrace: %s\n",
r.Error(), m.ExceptionsStacktrace()))
default:
panicStmt := m.makePanicFromRec(r)

m.PushStmt(panicStmt)
m.PushOp(OpExec)

m.resume()
return
}
}
}()

m.Run()
}

func (m *Machine) makePanicFromRec(r any) *PanicStmt {
var s strings.Builder

s.WriteString(`"`)
s.WriteString(`Machine.RunMain() panic: `)
s.WriteString(fmt.Sprintf(`%v`, r))
s.WriteString("\\n")
s.WriteString(`Machine State:`)
s.WriteString(m.StringDoubleSlash())
s.WriteString("\\n")
s.WriteString(`Stacktrace: `)
s.WriteString(m.Stacktrace().StringDoubleSlash())
s.WriteString("\\n")
s.WriteString(`"`)

panicStmt := &PanicStmt{
Exception: &BasicLitExpr{Value: s.String(), Kind: STRING},
}

return panicStmt
}

func (m *Machine) RunMain() {
defer func() {
if r := recover(); r != nil {
r := recover()

if r != nil {
switch r := r.(type) {
case UnhandledPanicError:
fmt.Printf("Machine.RunMain() panic: %s\nStacktrace: %s\n",
r.Error(), m.ExceptionsStacktrace())
default:
panicStmt := m.makePanicFromRec(r)

m.PushStmt(panicStmt)
m.PushOp(OpExec)

m.resume()
return
fmt.Printf("Machine.RunMain() panic: %v\nMachine State:%s\nStacktrace: %s\n",
r, m.String(), m.Stacktrace())
}
panic(r)
}
Expand Down Expand Up @@ -1329,6 +1282,26 @@ const (
// main run loop.

func (m *Machine) Run() {
defer func() {
r := recover()

if r != nil {
switch r := r.(type) {
case *Exception:
panicStmt := &PanicStmt{
Exception: &BasicLitExpr{Value: `"` + r.Sprint(m) + `"`, Kind: STRING},

Check failure

Code scanning / CodeQL

Potentially unsafe quoting Critical

If this
JSON value
contains a double quote, it could break out of the enclosing quotes.
}

m.PushStmt(panicStmt)
m.PushOp(OpExec)

m.Run()
default:
panic(r)
}
}
}()

for {
if m.Debugger.enabled {
m.Debug()
Expand Down Expand Up @@ -2406,122 +2379,3 @@ func (m *Machine) ExceptionsStacktrace() string {

return builder.String()
}

func (m *Machine) StringDoubleSlash() string {
// Calculate some reasonable total length to avoid reallocation
// Assuming an average length of 32 characters per string
var (
vsLength = m.NumValues * 32
ssLength = len(m.Stmts) * 32
xsLength = len(m.Exprs) * 32
bsLength = 1024
obsLength = len(m.Blocks) * 32
fsLength = len(m.Frames) * 32
exceptionsLength = len(m.Exceptions)

totalLength = vsLength + ssLength + xsLength + bsLength + obsLength + fsLength + exceptionsLength
)

var builder strings.Builder
builder.Grow(totalLength)

builder.WriteString(fmt.Sprintf("Machine:\\n CheckTypes: %v\\n Op: %v\\n Values: (len: %d)\\n", m.CheckTypes, m.Ops[:m.NumOps], m.NumValues))

for i := m.NumValues - 1; i >= 0; i-- {
builder.WriteString(fmt.Sprintf(" #%d %v\\n", i, m.Values[i]))
}

builder.WriteString(" Exprs:\\n")

for i := len(m.Exprs) - 1; i >= 0; i-- {
builder.WriteString(fmt.Sprintf(" #%d %v\\n", i, m.Exprs[i]))
}

builder.WriteString(" Stmts:\\n")

for i := len(m.Stmts) - 1; i >= 0; i-- {
builder.WriteString(fmt.Sprintf(" #%d %v\\n", i, m.Stmts[i]))
}

builder.WriteString(" Blocks:\\n")

for i := len(m.Blocks) - 1; i > 0; i-- {
b := m.Blocks[i]
if b == nil {
continue
}

gen := builder.Len()/3 + 1
gens := "@" // strings.Repeat("@", gen)

if pv, ok := b.Source.(*PackageNode); ok {
// package blocks have too much, so just
// print the pkgpath.
builder.WriteString(fmt.Sprintf(" %s(%d) %s\\n", gens, gen, pv.PkgPath))
} else {
bsi := b.StringIndentedSlash(" ")
builder.WriteString(fmt.Sprintf(" %s(%d) %s\\n", gens, gen, bsi))

if b.Source != nil {
sb := b.GetSource(m.Store).GetStaticBlock().GetBlock()
builder.WriteString(fmt.Sprintf(" (s vals) %s(%d) %s\\n", gens, gen, sb.StringIndentedSlash(" ")))

sts := b.GetSource(m.Store).GetStaticBlock().Types
builder.WriteString(fmt.Sprintf(" (s typs) %s(%d) %s\\n", gens, gen, sts))
}
}

// Update b
switch bp := b.Parent.(type) {
case nil:
b = nil
case *Block:
b = bp
case RefValue:
builder.WriteString(fmt.Sprintf(" (block ref %v)\\n", bp.ObjectID))
b = nil
default:
panic("should not happen")
}
}

builder.WriteString(" Blocks (other):\\n")

for i := len(m.Blocks) - 2; i >= 0; i-- {
b := m.Blocks[i]

if b == nil || b.Source == nil {
continue
}

if _, ok := b.Source.(*PackageNode); ok {
break // done, skip *PackageNode.
} else {
builder.WriteString(fmt.Sprintf(" #%d %s\\n", i,
b.StringIndentedSlash(" ")))
if b.Source != nil {
sb := b.GetSource(m.Store).GetStaticBlock().GetBlock()
builder.WriteString(fmt.Sprintf(" (static) #%d %s\\n", i,
sb.StringIndentedSlash(" ")))
}
}
}

builder.WriteString(" Frames:\\n")

for i := len(m.Frames) - 1; i >= 0; i-- {
builder.WriteString(fmt.Sprintf(" #%d %s\\n", i, m.Frames[i]))
}

if m.Realm != nil {
builder.WriteString(fmt.Sprintf(" Realm:\\n %s\\n", m.Realm.Path))
}

builder.WriteString(" Exceptions:\\n")

for _, ex := range m.Exceptions {
builder.WriteString(fmt.Sprintf(" %s\\n", ex.Sprint(m)))
}

return builder.String()
}
6 changes: 5 additions & 1 deletion gnovm/pkg/gnolang/op_assign.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ func (m *Machine) doOpQuoAssign() {
}
}
// lv /= rv
quoAssign(lv.TV, rv)
err := quoAssign(m, lv.TV, rv)
if err != nil {
panic(err)
}

if lv.Base != nil {
m.Realm.DidUpdate(lv.Base.(Object), nil, nil)
}
Expand Down
60 changes: 58 additions & 2 deletions gnovm/pkg/gnolang/op_binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,10 @@ func (m *Machine) doOpQuo() {
}

// lv / rv
quoAssign(lv, rv)
err := quoAssign(m, lv, rv)
if err != nil {
panic(err)
}
}

func (m *Machine) doOpRem() {
Expand Down Expand Up @@ -845,45 +848,96 @@ func mulAssign(lv, rv *TypedValue) {
}

// for doOpQuo and doOpQuoAssign.
func quoAssign(lv, rv *TypedValue) {
func quoAssign(m *Machine, lv, rv *TypedValue) *Exception {
expt := &Exception{
Value: typedString("division by zero"),
Frame: m.LastFrame(),
Stacktrace: m.Stacktrace(),
}

// set the result in lv.
// NOTE this block is replicated in op_assign.go
switch baseOf(lv.T) {
case IntType:
if rv.GetInt() == 0 {
return expt
}
lv.SetInt(lv.GetInt() / rv.GetInt())
case Int8Type:
if rv.GetInt8() == 0 {
return expt
}
lv.SetInt8(lv.GetInt8() / rv.GetInt8())
case Int16Type:
if rv.GetInt16() == 0 {
return expt
}
lv.SetInt16(lv.GetInt16() / rv.GetInt16())
case Int32Type, UntypedRuneType:
if rv.GetInt32() == 0 {
return expt
}
lv.SetInt32(lv.GetInt32() / rv.GetInt32())
case Int64Type:
if rv.GetInt64() == 0 {
return expt
}
lv.SetInt64(lv.GetInt64() / rv.GetInt64())
case UintType:
if rv.GetUint() == 0 {
return expt
}
lv.SetUint(lv.GetUint() / rv.GetUint())
case Uint8Type:
if rv.GetUint8() == 0 {
return expt
}
lv.SetUint8(lv.GetUint8() / rv.GetUint8())
case DataByteType:
if rv.GetUint8() == 0 {
return expt
}
lv.SetDataByte(lv.GetDataByte() / rv.GetUint8())
case Uint16Type:
if rv.GetUint16() == 0 {
return expt
}
lv.SetUint16(lv.GetUint16() / rv.GetUint16())
case Uint32Type:
if rv.GetUint32() == 0 {
return expt
}
lv.SetUint32(lv.GetUint32() / rv.GetUint32())
case Uint64Type:
if rv.GetUint64() == 0 {
return expt
}
lv.SetUint64(lv.GetUint64() / rv.GetUint64())
case Float32Type:
// NOTE: gno doesn't fuse *+.
if rv.GetFloat32() == 0 {
return expt
}
lv.SetFloat32(lv.GetFloat32() / rv.GetFloat32())
// XXX FOR DETERMINISM, PANIC IF NAN.
case Float64Type:
// NOTE: gno doesn't fuse *+.
if rv.GetFloat64() == 0 {
return expt
}
lv.SetFloat64(lv.GetFloat64() / rv.GetFloat64())
// XXX FOR DETERMINISM, PANIC IF NAN.
case BigintType, UntypedBigintType:
if rv.GetBigInt().Sign() == 0 {
return expt
}
lb := lv.GetBigInt()
lb = big.NewInt(0).Quo(lb, rv.GetBigInt())
lv.V = BigintValue{V: lb}
case BigdecType, UntypedBigdecType:
if rv.GetBigDec().Cmp(apd.New(0, 0)) == 0 {
return expt
}
lb := lv.GetBigDec()
rb := rv.GetBigDec()
quo := apd.New(0, 0)
Expand All @@ -898,6 +952,8 @@ func quoAssign(lv, rv *TypedValue) {
lv.T,
))
}

return nil
}

// for doOpRem and doOpRemAssign.
Expand Down
Loading

0 comments on commit ce6141c

Please sign in to comment.