@@ -34,21 +34,9 @@ func (c *Compiler) emitLookupBoundsCheck(frame *Frame, arrayLen, index llvm.Valu
3434 arrayLen = c .builder .CreateZExt (arrayLen , index .Type (), "" )
3535 }
3636
37- faultBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , "lookup.outofbounds" )
38- nextBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , "lookup.next" )
39- frame .blockExits [frame .currentBlock ] = nextBlock // adjust outgoing block for phi nodes
40-
4137 // Now do the bounds check: index >= arrayLen
4238 outOfBounds := c .builder .CreateICmp (llvm .IntUGE , index , arrayLen , "" )
43- c .builder .CreateCondBr (outOfBounds , faultBlock , nextBlock )
44-
45- // Fail: this is a nil pointer, exit with a panic.
46- c .builder .SetInsertPointAtEnd (faultBlock )
47- c .createRuntimeCall ("lookupPanic" , nil , "" )
48- c .builder .CreateUnreachable ()
49-
50- // Ok: this is a valid pointer.
51- c .builder .SetInsertPointAtEnd (nextBlock )
39+ c .createRuntimeAssert (frame , outOfBounds , "lookup" , "lookupPanic" )
5240}
5341
5442// emitSliceBoundsCheck emits a bounds check before a slicing operation to make
@@ -103,25 +91,13 @@ func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high, max l
10391 }
10492 }
10593
106- faultBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , "slice.outofbounds" )
107- nextBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , "slice.next" )
108- frame .blockExits [frame .currentBlock ] = nextBlock // adjust outgoing block for phi nodes
109-
11094 // Now do the bounds check: low > high || high > capacity
11195 outOfBounds1 := c .builder .CreateICmp (llvm .IntUGT , low , high , "slice.lowhigh" )
11296 outOfBounds2 := c .builder .CreateICmp (llvm .IntUGT , high , max , "slice.highmax" )
11397 outOfBounds3 := c .builder .CreateICmp (llvm .IntUGT , max , capacity , "slice.maxcap" )
11498 outOfBounds := c .builder .CreateOr (outOfBounds1 , outOfBounds2 , "slice.lowmax" )
11599 outOfBounds = c .builder .CreateOr (outOfBounds , outOfBounds3 , "slice.lowcap" )
116- c .builder .CreateCondBr (outOfBounds , faultBlock , nextBlock )
117-
118- // Fail: this is a nil pointer, exit with a panic.
119- c .builder .SetInsertPointAtEnd (faultBlock )
120- c .createRuntimeCall ("slicePanic" , nil , "" )
121- c .builder .CreateUnreachable ()
122-
123- // Ok: this is a valid pointer.
124- c .builder .SetInsertPointAtEnd (nextBlock )
100+ c .createRuntimeAssert (frame , outOfBounds , "slice" , "slicePanic" )
125101}
126102
127103// emitChanBoundsCheck emits a bounds check before creating a new channel to
@@ -167,32 +143,9 @@ func (c *Compiler) emitChanBoundsCheck(frame *Frame, elementSize uint64, bufSize
167143 maxBufSize = llvm .ConstZExt (maxBufSize , bufSize .Type ())
168144 }
169145
146+ // Do the check for a too large (or negative) buffer size.
170147 bufSizeTooBig := c .builder .CreateICmp (llvm .IntUGE , bufSize , maxBufSize , "" )
171- // Check whether we can resolve this check at compile time.
172- if ! bufSizeTooBig .IsAConstantInt ().IsNil () {
173- val := bufSizeTooBig .ZExtValue ()
174- if val == 0 {
175- // Everything is constant so the check does not have to be emitted
176- // in IR. This avoids emitting some redundant IR in the vast
177- // majority of cases.
178- return
179- }
180- }
181-
182- faultBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , "chan.outofbounds" )
183- nextBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , "chan.next" )
184- frame .blockExits [frame .currentBlock ] = nextBlock // adjust outgoing block for phi nodes
185-
186- // Now branch to the out-of-bounds or the regular block.
187- c .builder .CreateCondBr (bufSizeTooBig , faultBlock , nextBlock )
188-
189- // Fail: this channel is created with an invalid size parameter.
190- c .builder .SetInsertPointAtEnd (faultBlock )
191- c .createRuntimeCall ("chanMakePanic" , nil , "" )
192- c .builder .CreateUnreachable ()
193-
194- // Ok: this channel value is not too big.
195- c .builder .SetInsertPointAtEnd (nextBlock )
148+ c .createRuntimeAssert (frame , bufSizeTooBig , "chan" , "chanMakePanic" )
196149}
197150
198151// emitNilCheck checks whether the given pointer is nil, and panics if it is. It
@@ -204,11 +157,6 @@ func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string
204157 return
205158 }
206159
207- // Check whether this is a nil pointer.
208- faultBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , blockPrefix + ".nil" )
209- nextBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , blockPrefix + ".next" )
210- frame .blockExits [frame .currentBlock ] = nextBlock // adjust outgoing block for phi nodes
211-
212160 // Compare against nil.
213161 var isnil llvm.Value
214162 if ptr .Type ().PointerAddressSpace () == 0 {
@@ -227,13 +175,36 @@ func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string
227175 nilptr := llvm .ConstPointerNull (ptr .Type ())
228176 isnil = c .builder .CreateICmp (llvm .IntEQ , ptr , nilptr , "" )
229177 }
230- c .builder .CreateCondBr (isnil , faultBlock , nextBlock )
231178
232- // Fail: this is a nil pointer, exit with a panic.
179+ // Emit the nil check in IR.
180+ c .createRuntimeAssert (frame , isnil , blockPrefix , "nilPanic" )
181+ }
182+
183+ // createRuntimeAssert is a common function to create a new branch on an assert
184+ // bool, calling an assert func if the assert value is true (1).
185+ func (c * Compiler ) createRuntimeAssert (frame * Frame , assert llvm.Value , blockPrefix , assertFunc string ) {
186+ // Check whether we can resolve this check at compile time.
187+ if ! assert .IsAConstantInt ().IsNil () {
188+ val := assert .ZExtValue ()
189+ if val == 0 {
190+ // Everything is constant so the check does not have to be emitted
191+ // in IR. This avoids emitting some redundant IR.
192+ return
193+ }
194+ }
195+
196+ faultBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , blockPrefix + ".throw" )
197+ nextBlock := c .ctx .AddBasicBlock (frame .fn .LLVMFn , blockPrefix + ".next" )
198+ frame .blockExits [frame .currentBlock ] = nextBlock // adjust outgoing block for phi nodes
199+
200+ // Now branch to the out-of-bounds or the regular block.
201+ c .builder .CreateCondBr (assert , faultBlock , nextBlock )
202+
203+ // Fail: the assert triggered so panic.
233204 c .builder .SetInsertPointAtEnd (faultBlock )
234- c .createRuntimeCall ("nilPanic" , nil , "" )
205+ c .createRuntimeCall (assertFunc , nil , "" )
235206 c .builder .CreateUnreachable ()
236207
237- // Ok: this is a valid pointer .
208+ // Ok: assert didn't trigger so continue normally .
238209 c .builder .SetInsertPointAtEnd (nextBlock )
239210}
0 commit comments