mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-09-14 08:29:32 +00:00
runtime: avoid heap allocs for plain errors
This commit is contained in:
Vendored
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
target package code rodata data bss
|
target package code rodata data bss
|
||||||
hifive1b examples/echo 4533 323 0 2268
|
hifive1b examples/echo 4526 346 0 2268
|
||||||
microbit examples/serial 3002 382 8 2264
|
microbit examples/serial 2993 391 8 2264
|
||||||
wioterminal examples/pininterrupt 8331 1717 148 7496
|
wioterminal examples/pininterrupt 8309 1739 148 7496
|
||||||
|
|||||||
@@ -168,6 +168,39 @@ func TestBuild(t *testing.T) {
|
|||||||
runTestWithConfig("print.go", t, opts, nil, nil)
|
runTestWithConfig("print.go", t, opts, nil, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("gc=none-runtime-panic", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
opts := optionsFromTarget("cortex-m-qemu", sema)
|
||||||
|
opts.GC = "none"
|
||||||
|
opts.Scheduler = "none"
|
||||||
|
config, err := builder.NewConfig(&opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = Build("testdata/trivialpanic.go", t.TempDir()+"/trivialpanic", config)
|
||||||
|
if err != nil {
|
||||||
|
w := &bytes.Buffer{}
|
||||||
|
diagnostics.CreateDiagnostics(err).WriteTo(w, "")
|
||||||
|
t.Fatal(w.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("scheduler=none-uefi", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
opts := optionsFromTarget("uefi-amd64", sema)
|
||||||
|
opts.Scheduler = "none"
|
||||||
|
config, err := builder.NewConfig(&opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = Build("testdata/trivialpanic.go", t.TempDir()+"/trivialpanic", config)
|
||||||
|
if err != nil {
|
||||||
|
w := &bytes.Buffer{}
|
||||||
|
diagnostics.CreateDiagnostics(err).WriteTo(w, "")
|
||||||
|
t.Fatal(w.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("ldflags", func(t *testing.T) {
|
t.Run("ldflags", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
opts := optionsFromTarget("", sema)
|
opts := optionsFromTarget("", sema)
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import "unsafe"
|
|||||||
// There is only one goroutine so the task struct can be a global.
|
// There is only one goroutine so the task struct can be a global.
|
||||||
var mainTask Task
|
var mainTask Task
|
||||||
|
|
||||||
//go:linkname runtimePanic runtime.runtimePanic
|
//go:linkname runtimePanicSchedulerDisabled runtime.runtimePanicSchedulerDisabled
|
||||||
func runtimePanic(str string)
|
func runtimePanicSchedulerDisabled()
|
||||||
|
|
||||||
func Pause() {
|
func Pause() {
|
||||||
runtimePanic("scheduler is disabled")
|
runtimePanicSchedulerDisabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Current() *Task {
|
func Current() *Task {
|
||||||
@@ -22,13 +22,13 @@ func Current() *Task {
|
|||||||
//go:noinline
|
//go:noinline
|
||||||
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
||||||
// The compiler will error if this is reachable.
|
// The compiler will error if this is reachable.
|
||||||
runtimePanic("scheduler is disabled")
|
runtimePanicSchedulerDisabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
type state struct{}
|
type state struct{}
|
||||||
|
|
||||||
func (t *Task) Resume() {
|
func (t *Task) Resume() {
|
||||||
runtimePanic("scheduler is disabled")
|
runtimePanicSchedulerDisabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnSystemStack returns whether the caller is running on the system stack.
|
// OnSystemStack returns whether the caller is running on the system stack.
|
||||||
@@ -39,7 +39,7 @@ func OnSystemStack() bool {
|
|||||||
|
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
// System stack is the current stack, so this shouldn't be called.
|
// System stack is the current stack, so this shouldn't be called.
|
||||||
runtimePanic("scheduler is disabled")
|
runtimePanicSchedulerDisabled()
|
||||||
return 0 // unreachable
|
return 0 // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ package task
|
|||||||
|
|
||||||
//go:export tinygo_task_exit
|
//go:export tinygo_task_exit
|
||||||
func taskExit() {
|
func taskExit() {
|
||||||
runtimePanic("scheduler is disabled")
|
runtimePanicSchedulerDisabled()
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -207,7 +207,7 @@ func (ch *channel) trySend(value unsafe.Pointer) (sent bool, wake *task.Task) {
|
|||||||
// Note: we cannot currently recover from this panic.
|
// Note: we cannot currently recover from this panic.
|
||||||
// There's some state in the select statement especially that would be
|
// There's some state in the select statement especially that would be
|
||||||
// corrupted if we allowed recovering from this panic.
|
// corrupted if we allowed recovering from this panic.
|
||||||
runtimePanic("send on closed channel")
|
runtimePanic(errSendOnClosedChannel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no value in the buffer and we have a receiver available. Copy
|
// There is no value in the buffer and we have a receiver available. Copy
|
||||||
@@ -266,7 +266,7 @@ func chanSend(ch *channel, value unsafe.Pointer, op *channelOp) {
|
|||||||
// closed while sending).
|
// closed while sending).
|
||||||
if t.DataUint32() == chanOperationClosed {
|
if t.DataUint32() == chanOperationClosed {
|
||||||
// Oops, this channel was closed while sending!
|
// Oops, this channel was closed while sending!
|
||||||
runtimePanic("send on closed channel")
|
runtimePanic(errSendOnClosedChannel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +349,7 @@ func chanRecv(ch *channel, value unsafe.Pointer, op *channelOp) bool {
|
|||||||
func chanClose(ch *channel) {
|
func chanClose(ch *channel) {
|
||||||
if ch == nil {
|
if ch == nil {
|
||||||
// Not allowed by the language spec.
|
// Not allowed by the language spec.
|
||||||
runtimePanic("close of nil channel")
|
runtimePanic(errCloseNilChannel)
|
||||||
}
|
}
|
||||||
|
|
||||||
mask := interrupt.Disable()
|
mask := interrupt.Disable()
|
||||||
@@ -359,7 +359,7 @@ func chanClose(ch *channel) {
|
|||||||
// Not allowed by the language spec.
|
// Not allowed by the language spec.
|
||||||
ch.lock.Unlock()
|
ch.lock.Unlock()
|
||||||
interrupt.Restore(mask)
|
interrupt.Restore(mask)
|
||||||
runtimePanic("close of closed channel")
|
runtimePanic(errCloseClosedChannel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect waiters and wake them after unlocking.
|
// Collect waiters and wake them after unlocking.
|
||||||
|
|||||||
@@ -12,3 +12,30 @@ type plainError string
|
|||||||
|
|
||||||
func (e plainError) Error() string { return string(e) }
|
func (e plainError) Error() string { return string(e) }
|
||||||
func (e plainError) RuntimeError() {}
|
func (e plainError) RuntimeError() {}
|
||||||
|
|
||||||
|
const (
|
||||||
|
errNilPointer = plainError("nil pointer dereference")
|
||||||
|
errNilMap = plainError("assignment to entry in nil map")
|
||||||
|
errIndexOutOfRange = plainError("index out of range")
|
||||||
|
errSliceOutOfRange = plainError("slice out of range")
|
||||||
|
errSliceToArray = plainError("slice smaller than array")
|
||||||
|
errUnsafeSliceLength = plainError("unsafe.Slice/String: len out of range")
|
||||||
|
errChannelTooBig = plainError("new channel is too big")
|
||||||
|
errNegativeShift = plainError("negative shift")
|
||||||
|
errDivideByZero = plainError("divide by zero")
|
||||||
|
errBlockingExported = plainError("trying to do blocking operation in exported function")
|
||||||
|
errTimersUnsupported = plainError("timers not supported without a scheduler")
|
||||||
|
errIntegerOverflow = plainError("integer overflow")
|
||||||
|
errUnsupportedSignal = plainError("unsupported signal number")
|
||||||
|
errUnsupportedExit = plainError("unsupported: syscall.Exit")
|
||||||
|
errSendOnClosedChannel = plainError("send on closed channel")
|
||||||
|
errCloseNilChannel = plainError("close of nil channel")
|
||||||
|
errCloseClosedChannel = plainError("close of closed channel")
|
||||||
|
errWasmBeforeInit = plainError("//go:wasmexport function called before runtime initialization")
|
||||||
|
errWasmAfterMain = plainError("//go:wasmexport function called after main.main returned")
|
||||||
|
errWasmDidNotFinish = plainError("//go:wasmexport function did not finish")
|
||||||
|
errUncomparable = plainError("comparing un-comparable type")
|
||||||
|
errTypeAssert = plainError("type assert failed")
|
||||||
|
errSchedulerDisabled = plainError("scheduler is disabled")
|
||||||
|
errOutOfMemory = plainError("out of memory")
|
||||||
|
)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
|
|||||||
heapptr += size
|
heapptr += size
|
||||||
if heapptr < addr {
|
if heapptr < addr {
|
||||||
// The allocation size overflowed the heap pointer.
|
// The allocation size overflowed the heap pointer.
|
||||||
runtimePanic("out of memory")
|
runtimePanic(errOutOfMemory)
|
||||||
}
|
}
|
||||||
for heapptr > heapEnd {
|
for heapptr > heapEnd {
|
||||||
// Try to increase the heap and check again.
|
// Try to increase the heap and check again.
|
||||||
|
|||||||
@@ -832,7 +832,7 @@ func hashmapInterfaceHash(itf interface{}, seed uintptr) uint32 {
|
|||||||
}
|
}
|
||||||
return hash
|
return hash
|
||||||
default:
|
default:
|
||||||
runtimePanic("comparing un-comparable type")
|
runtimePanic(errUncomparable)
|
||||||
return 0 // unreachable
|
return 0 // unreachable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func reflectValueEqual(x, y reflectlite.Value) bool {
|
|||||||
case reflectlite.Interface:
|
case reflectlite.Interface:
|
||||||
return reflectValueEqual(x.Elem(), y.Elem())
|
return reflectValueEqual(x.Elem(), y.Elem())
|
||||||
default:
|
default:
|
||||||
runtimePanic("comparing un-comparable type")
|
runtimePanic(errUncomparable)
|
||||||
return false // unreachable
|
return false // unreachable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ func reflectValueEqual(x, y reflectlite.Value) bool {
|
|||||||
// returns false.
|
// returns false.
|
||||||
func interfaceTypeAssert(ok bool) {
|
func interfaceTypeAssert(ok bool) {
|
||||||
if !ok {
|
if !ok {
|
||||||
runtimePanic("type assert failed")
|
runtimePanic(errTypeAssert)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
-17
@@ -84,11 +84,11 @@ func panicOrGoexit(message interface{}, panicking panicState) {
|
|||||||
abort()
|
abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cause a runtime panic, which is (currently) always a string.
|
// Cause a recoverable runtime panic.
|
||||||
func runtimePanic(msg string) {
|
func runtimePanic(err Error) {
|
||||||
// As long as this function is inined, llvm.returnaddress(0) will return
|
// As long as this function is inlined, llvm.returnaddress(0) will return
|
||||||
// something sensible.
|
// something sensible.
|
||||||
runtimePanicAt(returnAddress(0), msg)
|
runtimePanicAt(returnAddress(0), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runtimeFatal terminates for runtime failures that cannot safely be
|
// runtimeFatal terminates for runtime failures that cannot safely be
|
||||||
@@ -103,7 +103,7 @@ func runtimeFatal(msg string) {
|
|||||||
abort()
|
abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runtimePanicAt(addr unsafe.Pointer, msg string) {
|
func runtimePanicAt(addr unsafe.Pointer, err Error) {
|
||||||
if panicStrategy() == tinygo.PanicStrategyTrap {
|
if panicStrategy() == tinygo.PanicStrategyTrap {
|
||||||
trap()
|
trap()
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ func runtimePanicAt(addr unsafe.Pointer, msg string) {
|
|||||||
if frame != nil {
|
if frame != nil {
|
||||||
// Use the normal panic mechanism so that this runtime error
|
// Use the normal panic mechanism so that this runtime error
|
||||||
// can be recovered with recover().
|
// can be recovered with recover().
|
||||||
frame.PanicValue = plainError(msg)
|
frame.PanicValue = err
|
||||||
frame.Panicking = panicTrue | (frame.Panicking & panicGoexit)
|
frame.Panicking = panicTrue | (frame.Panicking & panicGoexit)
|
||||||
tinygo_longjmp(frame)
|
tinygo_longjmp(frame)
|
||||||
// unreachable
|
// unreachable
|
||||||
@@ -128,11 +128,15 @@ func runtimePanicAt(addr unsafe.Pointer, msg string) {
|
|||||||
} else {
|
} else {
|
||||||
printstring("panic: runtime error: ")
|
printstring("panic: runtime error: ")
|
||||||
}
|
}
|
||||||
printstring(msg)
|
printstring(err.Error())
|
||||||
printnl()
|
printnl()
|
||||||
abort()
|
abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runtimePanicSchedulerDisabled() {
|
||||||
|
runtimePanicAt(returnAddress(0), errSchedulerDisabled)
|
||||||
|
}
|
||||||
|
|
||||||
// Called at the start of a function that includes a deferred call.
|
// Called at the start of a function that includes a deferred call.
|
||||||
// It gets passed in the stack-allocated defer frame and configures it.
|
// It gets passed in the stack-allocated defer frame and configures it.
|
||||||
// Note that the frame is not zeroed yet, so we need to initialize all values
|
// Note that the frame is not zeroed yet, so we need to initialize all values
|
||||||
@@ -220,54 +224,54 @@ func _recover(useParentFrame bool) interface{} {
|
|||||||
|
|
||||||
// Panic when trying to dereference a nil pointer.
|
// Panic when trying to dereference a nil pointer.
|
||||||
func nilPanic() {
|
func nilPanic() {
|
||||||
runtimePanicAt(returnAddress(0), "nil pointer dereference")
|
runtimePanicAt(returnAddress(0), errNilPointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when trying to add an entry to a nil map
|
// Panic when trying to add an entry to a nil map
|
||||||
func nilMapPanic() {
|
func nilMapPanic() {
|
||||||
runtimePanicAt(returnAddress(0), "assignment to entry in nil map")
|
runtimePanicAt(returnAddress(0), errNilMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when trying to access an array or slice out of bounds.
|
// Panic when trying to access an array or slice out of bounds.
|
||||||
func lookupPanic() {
|
func lookupPanic() {
|
||||||
runtimePanicAt(returnAddress(0), "index out of range")
|
runtimePanicAt(returnAddress(0), errIndexOutOfRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when trying to slice a slice out of bounds.
|
// Panic when trying to slice a slice out of bounds.
|
||||||
func slicePanic() {
|
func slicePanic() {
|
||||||
runtimePanicAt(returnAddress(0), "slice out of range")
|
runtimePanicAt(returnAddress(0), errSliceOutOfRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when trying to convert a slice to an array pointer (Go 1.17+) and the
|
// Panic when trying to convert a slice to an array pointer (Go 1.17+) and the
|
||||||
// slice is shorter than the array.
|
// slice is shorter than the array.
|
||||||
func sliceToArrayPointerPanic() {
|
func sliceToArrayPointerPanic() {
|
||||||
runtimePanicAt(returnAddress(0), "slice smaller than array")
|
runtimePanicAt(returnAddress(0), errSliceToArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when calling unsafe.Slice() (Go 1.17+) or unsafe.String() (Go 1.20+)
|
// Panic when calling unsafe.Slice() (Go 1.17+) or unsafe.String() (Go 1.20+)
|
||||||
// with a len that's too large (which includes if the ptr is nil and len is
|
// with a len that's too large (which includes if the ptr is nil and len is
|
||||||
// nonzero).
|
// nonzero).
|
||||||
func unsafeSlicePanic() {
|
func unsafeSlicePanic() {
|
||||||
runtimePanicAt(returnAddress(0), "unsafe.Slice/String: len out of range")
|
runtimePanicAt(returnAddress(0), errUnsafeSliceLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when trying to create a new channel that is too big.
|
// Panic when trying to create a new channel that is too big.
|
||||||
func chanMakePanic() {
|
func chanMakePanic() {
|
||||||
runtimePanicAt(returnAddress(0), "new channel is too big")
|
runtimePanicAt(returnAddress(0), errChannelTooBig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when a shift value is negative.
|
// Panic when a shift value is negative.
|
||||||
func negativeShiftPanic() {
|
func negativeShiftPanic() {
|
||||||
runtimePanicAt(returnAddress(0), "negative shift")
|
runtimePanicAt(returnAddress(0), errNegativeShift)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when there is a divide by zero.
|
// Panic when there is a divide by zero.
|
||||||
func divideByZeroPanic() {
|
func divideByZeroPanic() {
|
||||||
runtimePanicAt(returnAddress(0), "divide by zero")
|
runtimePanicAt(returnAddress(0), errDivideByZero)
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockingPanic() {
|
func blockingPanic() {
|
||||||
runtimePanicAt(returnAddress(0), "trying to do blocking operation in exported function")
|
runtimePanicAt(returnAddress(0), errBlockingExported)
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname fips_fatal crypto/internal/fips140.fatal
|
//go:linkname fips_fatal crypto/internal/fips140.fatal
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func syscall_Exit(code int) {
|
|||||||
// Because this is the "unknown" target we can't call an exit function.
|
// Because this is the "unknown" target we can't call an exit function.
|
||||||
// But we also can't just return since the program will likely expect this
|
// But we also can't just return since the program will likely expect this
|
||||||
// function to never return. So we panic instead.
|
// function to never return. So we panic instead.
|
||||||
runtimePanic("unsupported: syscall.Exit")
|
runtimePanic(errUnsupportedExit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is not yet any support for any form of parallelism on WebAssembly, so these
|
// There is not yet any support for any form of parallelism on WebAssembly, so these
|
||||||
|
|||||||
@@ -151,9 +151,9 @@ func tinygo_sigpanic() {
|
|||||||
sig := tinygo_caught_signal
|
sig := tinygo_caught_signal
|
||||||
switch sig {
|
switch sig {
|
||||||
case sig_SIGSEGV, sig_SIGBUS:
|
case sig_SIGSEGV, sig_SIGBUS:
|
||||||
runtimePanic("nil pointer dereference")
|
runtimePanic(errNilPointer)
|
||||||
case sig_SIGFPE:
|
case sig_SIGFPE:
|
||||||
runtimePanic("divide by zero")
|
runtimePanic(errDivideByZero)
|
||||||
default:
|
default:
|
||||||
runtimeFatal("signal")
|
runtimeFatal("signal")
|
||||||
}
|
}
|
||||||
@@ -382,7 +382,7 @@ func signal_enable(s uint32) {
|
|||||||
if s >= 32 {
|
if s >= 32 {
|
||||||
// TODO: to support higher signal numbers, we need to turn
|
// TODO: to support higher signal numbers, we need to turn
|
||||||
// receivedSignals into a uint32 array.
|
// receivedSignals into a uint32 array.
|
||||||
runtimePanicAt(returnAddress(0), "unsupported signal number")
|
runtimePanicAt(returnAddress(0), errUnsupportedSignal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is intentonally a non-atomic store. This is safe, since hasSignals
|
// This is intentonally a non-atomic store. This is safe, since hasSignals
|
||||||
@@ -399,7 +399,7 @@ func signal_ignore(s uint32) {
|
|||||||
if s >= 32 {
|
if s >= 32 {
|
||||||
// TODO: to support higher signal numbers, we need to turn
|
// TODO: to support higher signal numbers, we need to turn
|
||||||
// receivedSignals into a uint32 array.
|
// receivedSignals into a uint32 array.
|
||||||
runtimePanicAt(returnAddress(0), "unsupported signal number")
|
runtimePanicAt(returnAddress(0), errUnsupportedSignal)
|
||||||
}
|
}
|
||||||
tinygo_signal_ignore(s)
|
tinygo_signal_ignore(s)
|
||||||
}
|
}
|
||||||
@@ -409,7 +409,7 @@ func signal_disable(s uint32) {
|
|||||||
if s >= 32 {
|
if s >= 32 {
|
||||||
// TODO: to support higher signal numbers, we need to turn
|
// TODO: to support higher signal numbers, we need to turn
|
||||||
// receivedSignals into a uint32 array.
|
// receivedSignals into a uint32 array.
|
||||||
runtimePanicAt(returnAddress(0), "unsupported signal number")
|
runtimePanicAt(returnAddress(0), errUnsupportedSignal)
|
||||||
}
|
}
|
||||||
tinygo_signal_disable(s)
|
tinygo_signal_disable(s)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ var initializeCalled bool
|
|||||||
func wasmExportCheckRun() {
|
func wasmExportCheckRun() {
|
||||||
switch {
|
switch {
|
||||||
case !initializeCalled:
|
case !initializeCalled:
|
||||||
runtimePanic("//go:wasmexport function called before runtime initialization")
|
runtimePanic(errWasmBeforeInit)
|
||||||
case mainExited:
|
case mainExited:
|
||||||
runtimePanic("//go:wasmexport function called after main.main returned")
|
runtimePanic(errWasmAfterMain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +81,6 @@ func wasmExportCheckRun() {
|
|||||||
func wasmExportRun(done *bool) {
|
func wasmExportRun(done *bool) {
|
||||||
scheduler(true)
|
scheduler(true)
|
||||||
if !*done {
|
if !*done {
|
||||||
runtimePanic("//go:wasmexport function did not finish")
|
runtimePanic(errWasmDidNotFinish)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -315,11 +315,11 @@ func tinygo_init_exception_handler()
|
|||||||
func tinygo_sigpanic_windows(exceptionCode int32) {
|
func tinygo_sigpanic_windows(exceptionCode int32) {
|
||||||
switch uint32(exceptionCode) {
|
switch uint32(exceptionCode) {
|
||||||
case _EXCEPTION_ACCESS_VIOLATION, _EXCEPTION_IN_PAGE_ERROR:
|
case _EXCEPTION_ACCESS_VIOLATION, _EXCEPTION_IN_PAGE_ERROR:
|
||||||
runtimePanic("nil pointer dereference")
|
runtimePanic(errNilPointer)
|
||||||
case _EXCEPTION_INT_DIVIDE_BY_ZERO:
|
case _EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||||
runtimePanic("divide by zero")
|
runtimePanic(errDivideByZero)
|
||||||
case _EXCEPTION_INT_OVERFLOW:
|
case _EXCEPTION_INT_OVERFLOW:
|
||||||
runtimePanic("integer overflow")
|
runtimePanic(errIntegerOverflow)
|
||||||
default:
|
default:
|
||||||
runtimeFatal("unknown exception")
|
runtimeFatal("unknown exception")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,15 +60,15 @@ func NumCPU() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addTimer(tim *timerNode) {
|
func addTimer(tim *timerNode) {
|
||||||
runtimePanic("timers not supported without a scheduler")
|
runtimePanic(errTimersUnsupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
func reAddTimer(tn *timerNode) {
|
func reAddTimer(tn *timerNode) {
|
||||||
runtimePanic("timers not supported without a scheduler")
|
runtimePanic(errTimersUnsupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeTimer(tim *timer) *timerNode {
|
func removeTimer(tim *timer) *timerNode {
|
||||||
runtimePanic("timers not supported without a scheduler")
|
runtimePanic(errTimersUnsupported)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+17
@@ -313,12 +313,29 @@ func recoverMustPanic(name string, f func()) {
|
|||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func recoverRuntimeErrorValue(f func()) {
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
err, ok := r.(runtime.Error)
|
||||||
|
if ok {
|
||||||
|
println(" recovered runtime error:", err.Error())
|
||||||
|
} else {
|
||||||
|
println(" failed runtime error:", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
// Test recovering from nil map assignment and closed channel send.
|
// Test recovering from nil map assignment and closed channel send.
|
||||||
func recoverNilMapAndChan() {
|
func recoverNilMapAndChan() {
|
||||||
recoverMustPanic("nil map", func() {
|
recoverMustPanic("nil map", func() {
|
||||||
var m map[string]int
|
var m map[string]int
|
||||||
m["x"] = 1
|
m["x"] = 1
|
||||||
})
|
})
|
||||||
|
recoverRuntimeErrorValue(func() {
|
||||||
|
var m map[string]int
|
||||||
|
m["x"] = 1
|
||||||
|
})
|
||||||
recoverMustPanic("closed chan", func() {
|
recoverMustPanic("closed chan", func() {
|
||||||
ch := make(chan int)
|
ch := make(chan int)
|
||||||
close(ch)
|
close(ch)
|
||||||
|
|||||||
Vendored
+1
@@ -52,6 +52,7 @@ outer recovered: repanic value
|
|||||||
|
|
||||||
# recover from nil map and closed channel
|
# recover from nil map and closed channel
|
||||||
recovered: nil map
|
recovered: nil map
|
||||||
|
recovered runtime error: assignment to entry in nil map
|
||||||
recovered: closed chan
|
recovered: closed chan
|
||||||
recovered: close nil chan
|
recovered: close nil chan
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user