diff options
author | Ayke van Laethem <[email protected]> | 2019-03-07 13:33:46 +0100 |
---|---|---|
committer | Ron Evans <[email protected]> | 2019-03-08 17:36:53 +0100 |
commit | 622d0ebde671a4c71fc771ef8f9210ff433c9fbe (patch) | |
tree | 00724eda34c158ffe776d5ec1829159425834ec1 /compiler/asserts.go | |
parent | b7cdf8cd0c1f66da9e6c4392ce5acbab911892c5 (diff) | |
download | tinygo-622d0ebde671a4c71fc771ef8f9210ff433c9fbe.tar.gz tinygo-622d0ebde671a4c71fc771ef8f9210ff433c9fbe.zip |
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.
Diffstat (limited to 'compiler/asserts.go')
-rw-r--r-- | compiler/asserts.go | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/compiler/asserts.go b/compiler/asserts.go new file mode 100644 index 000000000..4c09264ae --- /dev/null +++ b/compiler/asserts.go @@ -0,0 +1,31 @@ +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) +} |