tinygo/compiler/asserts.go
Ayke van Laethem 622d0ebde6 compiler: implement nil checks
This commit implements nil checks for all platforms. These nil checks
can be optimized on systems with a MMU, but since a major target is
systems without MMU, keep it this way for now.

It implements three checks:
  * Nil checks before dereferencing a pointer.
  * Nil checks before calculating an address (*ssa.FieldAddr and
    *ssa.IndexAddr)
  * Nil checks before calling a function pointer.

The first check has by far the biggest impact, with around 5% increase
in code size. The other checks only trigger in only some test cases and
have a minimal impact on code size.
This first nil check is also the one that is easiest to avoid on systems
with MMU, if necessary.
2019-03-08 17:36:53 +01:00

31 строка
1,1 КиБ
Go

package compiler
// This file implements functions that do certain safety checks that are
// required by the Go programming language.
import (
"tinygo.org/x/go-llvm"
)
// emitNilCheck checks whether the given pointer is nil, and panics if it is. It
// has no effect in well-behaved programs, but makes sure no uncaught nil
// pointer dereferences exist in valid Go code.
func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string) {
// Check whether this is a nil pointer.
faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".nil")
nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".next")
frame.blockExits[frame.currentBlock] = nextBlock // adjust outgoing block for phi nodes
// Compare against nil.
nilptr := llvm.ConstPointerNull(ptr.Type())
isnil := c.builder.CreateICmp(llvm.IntEQ, ptr, nilptr, "")
c.builder.CreateCondBr(isnil, faultBlock, nextBlock)
// Fail: this is a nil pointer, exit with a panic.
c.builder.SetInsertPointAtEnd(faultBlock)
c.createRuntimeCall("nilpanic", nil, "")
c.builder.CreateUnreachable()
// Ok: this is a valid pointer.
c.builder.SetInsertPointAtEnd(nextBlock)
}