1/*
2 * gomacro - A Go interpreter with Lisp-like macros
3 *
4 * Copyright (C) 2017-2019 Massimiliano Ghilardi
5 *
6 *     This Source Code Form is subject to the terms of the Mozilla Public
7 *     License, v. 2.0. If a copy of the MPL was not distributed with this
8 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 *
11 * exec.go
12 *
13 *  Created on Apr 09, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package fast
18
19import (
20	"go/token"
21
22	. "github.com/cosmos72/gomacro/base"
23)
24
25func (code *Code) Clear() {
26	code.List = nil
27	code.DebugPos = nil
28	code.WithDefers = false
29}
30
31func (code *Code) Len() int {
32	return len(code.List)
33}
34
35func (code *Code) Truncate(n int) {
36	if len(code.List) > n {
37		code.List = code.List[0:n]
38	}
39	if len(code.DebugPos) > n {
40		code.DebugPos = code.DebugPos[0:n]
41	}
42}
43
44func (code *Code) Append(stmt Stmt, pos token.Pos) {
45	if stmt != nil {
46		code.List = append(code.List, stmt)
47		code.DebugPos = append(code.DebugPos, pos)
48	}
49}
50
51func (code *Code) AsExpr() *Expr {
52	fun := code.Exec()
53	if fun == nil {
54		return nil
55	}
56	return expr0(fun)
57}
58
59// spinInterrupt is the statement executed while waiting for an interrupt to be serviced.
60// To signal an interrupt, a statement must set env.ThreadGlobals.Signal to the desired signal,
61// then return env.ThreadGlobals.Interrupt, env
62func spinInterrupt(env *Env) (Stmt, *Env) {
63	run := env.Run
64	if run.Signals.IsEmpty() {
65		run.Signals.Sync = SigReturn
66	} else if sig := run.Signals.Async; sig != SigNone {
67		run.applyAsyncSignal(sig)
68	}
69	return run.Interrupt, env
70}
71
72func (run *Run) applyAsyncSignal(sig Signal) {
73	run.Signals.Async = SigNone
74	switch sig {
75	case SigNone:
76		break
77	case SigDebug:
78		run.applyDebugOp(DebugOpStep)
79	default:
80		panic(SigInterrupt)
81	}
82}
83
84func pushDefer(g *Run, deferOf *Env, panicking bool) (retg *Run, deferOf_ *Env, isDefer bool) {
85	deferOf_ = g.DeferOfFun
86	if panicking {
87		g.PanicFun = deferOf
88	}
89	g.DeferOfFun = deferOf
90	g.ExecFlags.SetStartDefer(true)
91	return g, deferOf_, g.ExecFlags.IsDefer()
92}
93
94func popDefer(run *Run, deferOf *Env, isDefer bool) {
95	run.DeferOfFun = deferOf
96	run.ExecFlags.SetStartDefer(false)
97	run.ExecFlags.SetDefer(isDefer)
98}
99
100func restore(run *Run, isDefer bool, interrupt Stmt, caller *Env) {
101	run.ExecFlags.SetDefer(isDefer)
102	run.Interrupt = interrupt
103	run.CurrEnv = caller
104	run.Signals.Sync = SigNone
105	if sig := run.Signals.Async; sig == SigInterrupt {
106		// do NOT handle async SigDebug here
107		run.applyAsyncSignal(sig)
108	}
109}
110
111func maybeRepanic(run *Run) bool {
112	if run.PanicFun != nil {
113		panic(run.Panic)
114	}
115	// either not panicking or recover() invoked, no longer panicking
116	return false
117}
118
119func (run *Run) interrupt() {
120	const CtrlCDebug = OptDebugger | OptCtrlCEnterDebugger
121	var sig Signal
122	if run.Options&CtrlCDebug == CtrlCDebug {
123		sig = SigDebug
124	} else {
125		sig = SigInterrupt
126	}
127	run.Signals.Async = sig
128}
129
130// Exec returns a func(*Env) that will execute the compiled code
131func (code *Code) Exec() func(*Env) {
132	all := code.List
133	pos := code.DebugPos
134	defers := code.WithDefers
135
136	code.Clear()
137	if len(all) == 0 {
138		return nil
139	}
140	all = append(all, spinInterrupt)
141
142	if defers {
143		// code to support defer is slower... isolate it in a separate function
144		return execWithFlags(all, pos)
145	}
146	return exec(all, pos)
147}
148
149func exec(all []Stmt, pos []token.Pos) func(*Env) {
150	return func(env *Env) {
151		run := env.Run
152		run.Signals.Sync = SigNone
153		if run.ExecFlags != 0 {
154			// code to support defer and debugger is slower... isolate it in a separate function
155			reExecWithFlags(env, all, pos, all[0], 0)
156			return
157		}
158		if sig := run.Signals.Async; sig != SigNone {
159			run.applyAsyncSignal(sig)
160		}
161		saveInterrupt := run.Interrupt
162		run.Interrupt = nil
163
164		stmt := all[0]
165		env.IP = 0
166		env.Code = all
167		env.DebugPos = pos
168
169		for j := 0; j < 5; j++ {
170			if stmt, env = stmt(env); stmt != nil {
171				if stmt, env = stmt(env); stmt != nil {
172					if stmt, env = stmt(env); stmt != nil {
173						if stmt, env = stmt(env); stmt != nil {
174							if stmt, env = stmt(env); stmt != nil {
175								if stmt, env = stmt(env); stmt != nil {
176									if stmt, env = stmt(env); stmt != nil {
177										if stmt, env = stmt(env); stmt != nil {
178											if stmt, env = stmt(env); stmt != nil {
179												if stmt, env = stmt(env); stmt != nil {
180													if stmt, env = stmt(env); stmt != nil {
181														if stmt, env = stmt(env); stmt != nil {
182															if stmt, env = stmt(env); stmt != nil {
183																if stmt, env = stmt(env); stmt != nil {
184																	if run.Signals.IsEmpty() {
185																		continue
186																	}
187																}
188															}
189														}
190													}
191												}
192											}
193										}
194									}
195								}
196							}
197						}
198					}
199				}
200			}
201			goto finish
202		}
203
204		run.Interrupt = spinInterrupt
205		for {
206			stmt, env = stmt(env)
207			stmt, env = stmt(env)
208			stmt, env = stmt(env)
209			stmt, env = stmt(env)
210			stmt, env = stmt(env)
211			stmt, env = stmt(env)
212			stmt, env = stmt(env)
213			stmt, env = stmt(env)
214			stmt, env = stmt(env)
215			stmt, env = stmt(env)
216			stmt, env = stmt(env)
217			stmt, env = stmt(env)
218			stmt, env = stmt(env)
219			stmt, env = stmt(env)
220			stmt, env = stmt(env)
221
222			if !run.Signals.IsEmpty() {
223				break
224			}
225		}
226	finish:
227		// restore env.ThreadGlobals.Interrupt and Signal before returning
228		run.Interrupt = saveInterrupt
229		if sig := run.Signals.Async; sig != SigNone {
230			run.applyAsyncSignal(sig) // may set run.Signals.Debug if OptCtrlCEnterDebugger is set
231		}
232		if run.Signals.Debug == SigNone {
233			run.Signals.Sync = SigNone
234		} else {
235			reExecWithFlags(env, all, pos, stmt, env.IP)
236		}
237	}
238}
239
240// execWithFlags returns a function that will execute the given compiled code, including support for defer() and debugger
241func execWithFlags(all []Stmt, pos []token.Pos) func(*Env) {
242	return func(env *Env) {
243		env.Run.Signals.Sync = SigNone
244		reExecWithFlags(env, all, pos, all[0], 0)
245	}
246}
247
248func reExecWithFlags(env *Env, all []Stmt, pos []token.Pos, stmt Stmt, ip int) {
249	run := env.Run
250
251	ef := &run.ExecFlags
252	trace := run.Options&OptDebugDebugger != 0
253	if trace {
254		run.Debugf("reExecWithFlags:  executing function   stmt = %p, env = %p, IP = %v, execFlags = %v, signals = %#v", stmt, env, ip, *ef, run.Signals)
255	}
256	if sig := run.Signals.Async; sig != SigNone {
257		run.applyAsyncSignal(sig)
258	}
259	caller := run.CurrEnv
260	// restore g.IsDefer, g.Signal, g.DebugCallDepth, g.Interrupt and g.Caller on return
261	defer restore(run, run.ExecFlags.IsDefer(), run.Interrupt, caller)
262	ef.SetDefer(ef.StartDefer())
263	ef.SetStartDefer(false)
264	ef.SetDebug(run.Signals.Debug != SigNone)
265
266	funenv := env
267	env.IP = ip
268	env.Code = all
269	env.DebugPos = pos
270
271	panicking, panicking2 := true, false
272	rundefer := func(fun func()) {
273		if panicking || panicking2 {
274			panicking = true
275			panicking2 = false
276			run.Panic = recover()
277		}
278		defer popDefer(pushDefer(run, funenv, panicking))
279		panicking2 = true // detect panics inside defer
280		fun()
281		panicking2 = false
282		if panicking {
283			panicking = maybeRepanic(run)
284		}
285	}
286
287	if stmt == nil || !run.Signals.IsEmpty() {
288		goto signal
289	}
290again:
291	run.Interrupt = nil
292	for j := 0; j < 5; j++ {
293		if stmt, env = stmt(env); stmt != nil {
294			if stmt, env = stmt(env); stmt != nil {
295				if stmt, env = stmt(env); stmt != nil {
296					if stmt, env = stmt(env); stmt != nil {
297						if stmt, env = stmt(env); stmt != nil {
298							if stmt, env = stmt(env); stmt != nil {
299								if stmt, env = stmt(env); stmt != nil {
300									if stmt, env = stmt(env); stmt != nil {
301										if stmt, env = stmt(env); stmt != nil {
302											if stmt, env = stmt(env); stmt != nil {
303												if stmt, env = stmt(env); stmt != nil {
304													if stmt, env = stmt(env); stmt != nil {
305														if stmt, env = stmt(env); stmt != nil {
306															if stmt, env = stmt(env); stmt != nil {
307																if run.Signals.IsEmpty() {
308																	continue
309																}
310															}
311														}
312													}
313												}
314											}
315										}
316									}
317								}
318							}
319						}
320					}
321				}
322			}
323		}
324		for run.Signals.Sync == SigDefer {
325			run.Signals.Sync = SigNone
326			fun := run.InstallDefer
327			run.InstallDefer = nil
328			defer rundefer(fun)
329			stmt = env.Code[env.IP]
330			if stmt == nil {
331				goto signal
332			}
333		}
334		if !run.Signals.IsEmpty() {
335			goto signal
336		}
337		continue
338	}
339
340	run.Interrupt = spinInterrupt
341	for {
342		stmt, env = stmt(env)
343		stmt, env = stmt(env)
344		stmt, env = stmt(env)
345		stmt, env = stmt(env)
346		stmt, env = stmt(env)
347		stmt, env = stmt(env)
348		stmt, env = stmt(env)
349		stmt, env = stmt(env)
350		stmt, env = stmt(env)
351		stmt, env = stmt(env)
352		stmt, env = stmt(env)
353		stmt, env = stmt(env)
354		stmt, env = stmt(env)
355		stmt, env = stmt(env)
356		stmt, env = stmt(env)
357
358		for run.Signals.Sync == SigDefer {
359			run.Signals.Sync = SigNone
360			fun := run.InstallDefer
361			run.InstallDefer = nil
362			defer rundefer(fun)
363			// single step
364			stmt = env.Code[env.IP]
365			stmt, env = stmt(env)
366		}
367		if !run.Signals.IsEmpty() {
368			goto signal
369		}
370	}
371signal:
372	if sig := run.Signals.Async; sig != SigNone {
373		// if OptCtrlCEnterDebugger is set, convert early
374		// Signals.Async = SigDebug to Signals.Debug = SigDebug
375		run.applyAsyncSignal(sig)
376	}
377
378	for run.Signals.Debug != SigNone {
379		run.Interrupt = spinInterrupt
380		stmt, env = singleStep(env)
381		if trace {
382			run.Debugf("singleStep returned stmt = %p, env = %p, IP = %v, execFlags = %v, signals = %#v", stmt, env, env.IP, run.ExecFlags, run.Signals)
383		}
384		// a Sync or Async signal may be pending.
385		sig := run.Signals.Sync
386		if run.Signals.IsEmpty() || sig == SigDefer {
387			goto again
388		} else if sig == SigReturn {
389			break
390		} else if sig = run.Signals.Async; sig != SigNone {
391			run.applyAsyncSignal(sig)
392		}
393	}
394	panicking = false
395	// no need to restore g.IsDefer, g.Signal, g.Interrupt:
396	// done by defer restore(g, g.IsDefer, interrupt) above
397	return
398}
399