mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-13 15:33:40 +00:00
interp: bail out of loops that iterate too many times (#5395)
* interp: bail out of loops that iterate too many times The existing loop guard (errLoopUnrolled) only fires when a loop body emits runtime instructions. Loops that are fully evaluable at compile time, such as inserting thousands of entries into a map, were not caught and could hang the compiler. Add a per-basic-block iteration counter that triggers a recoverable error (errLoopTooLong) when any block is entered more than 1000 times in a single function call. This defers the init function to runtime, which is the same behavior as other interp bailouts. Profiling showed that 83% of CPU time was spent in GC, caused by allocation pressure from the interp memory cloning on each map mutation. The iteration limit avoids this entirely by bailing out before the quadratic cost becomes significant. Performance on the reproducer from #2090 (map init with strconv.Itoa): entries before after 5,000 7.4s 2.1s 10,000 17.5s 2.1s 20,000 48.0s 2.8s 65,536 >180s (OOM) 3.2s * Add -interp-loop-limit
This commit is contained in:
+2
-1
@@ -19,6 +19,7 @@ var (
|
||||
errUnsupportedRuntimeInst = errors.New("interp: unsupported instruction (to be emitted at runtime)")
|
||||
errMapAlreadyCreated = errors.New("interp: map already created")
|
||||
errLoopUnrolled = errors.New("interp: loop unrolled")
|
||||
errLoopTooLong = errors.New("interp: loop ran too many iterations")
|
||||
)
|
||||
|
||||
// This is one of the errors that can be returned from toLLVMValue when the
|
||||
@@ -29,7 +30,7 @@ var errInvalidPtrToIntSize = errors.New("interp: ptrtoint integer size does not
|
||||
func isRecoverableError(err error) bool {
|
||||
return err == errIntegerAsPointer || err == errUnsupportedInst ||
|
||||
err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated ||
|
||||
err == errLoopUnrolled || err == errInvalidPtrToIntSize
|
||||
err == errLoopUnrolled || err == errLoopTooLong || err == errInvalidPtrToIntSize
|
||||
}
|
||||
|
||||
// ErrorLine is one line in a traceback. The position may be missing.
|
||||
|
||||
Reference in New Issue
Block a user