diff options
author | Ayke van Laethem <[email protected]> | 2021-07-14 20:10:37 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2021-07-14 22:33:32 +0200 |
commit | efa0410075ea492a1113224236a1210be74e1650 (patch) | |
tree | 0bb6dfcf34a29826a59c0bd75ad693f4429343c3 /interp/interp.go | |
parent | 607d8242111560233ffd54eda461a43cc9c4760b (diff) | |
download | tinygo-efa0410075ea492a1113224236a1210be74e1650.tar.gz tinygo-efa0410075ea492a1113224236a1210be74e1650.zip |
interp: fix bug in compiler-time/run-time package initializers
Make sure that if a package initializer cannot be run, later package
initializers won't try to access any global variables touched by the
uninterpretable package initializer.
Diffstat (limited to 'interp/interp.go')
-rw-r--r-- | interp/interp.go | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/interp/interp.go b/interp/interp.go index 574fe01ab..cab9d9e35 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -116,9 +116,16 @@ func Run(mod llvm.Module, debug bool) error { if r.debug { fmt.Fprintln(os.Stderr, "not interpreting", r.pkgName, "because of error:", callErr.Error()) } + // Remove instructions that were created as part of interpreting + // the package. mem.revert() + // Create a call to the package initializer (which was + // previously deleted). i8undef := llvm.Undef(r.i8ptrType) r.builder.CreateCall(fn, []llvm.Value{i8undef, i8undef}, "") + // Make sure that any globals touched by the package + // initializer, won't be accessed by later package initializers. + r.markExternalLoad(fn) continue } return callErr @@ -272,3 +279,19 @@ func (r *runner) getFunction(llvmFn llvm.Value) *function { r.functionCache[llvmFn] = fn return fn } + +// markExternalLoad marks the given llvmValue as being loaded externally. This +// is primarily used to mark package initializers that could not be run at +// compile time. As an example, a package initialize might store to a global +// variable. Another package initializer might read from the same global +// variable. By marking this function as being run at runtime, that load +// instruction will need to be run at runtime instead of at compile time. +func (r *runner) markExternalLoad(llvmValue llvm.Value) { + mem := memoryView{r: r} + mem.markExternalLoad(llvmValue) + for index, obj := range mem.objects { + if obj.marked > r.objects[index].marked { + r.objects[index].marked = obj.marked + } + } +} |