aboutsummaryrefslogtreecommitdiffhomepage
path: root/interp/interp.go
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2021-07-14 20:10:37 +0200
committerRon Evans <[email protected]>2021-07-14 22:33:32 +0200
commitefa0410075ea492a1113224236a1210be74e1650 (patch)
tree0bb6dfcf34a29826a59c0bd75ad693f4429343c3 /interp/interp.go
parent607d8242111560233ffd54eda461a43cc9c4760b (diff)
downloadtinygo-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.go23
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
+ }
+ }
+}