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