1 /** 2 * Copyright: Enalye 3 * License: Zlib 4 * Authors: Enalye 5 */ 6 module grimoire.runtime.context; 7 8 import grimoire.assembly; 9 import grimoire.runtime.engine, grimoire.runtime.array, 10 grimoire.runtime.channel, grimoire.runtime.object; 11 12 /** 13 Represents a single function context in the callStack. 14 */ 15 struct GrStackFrame { 16 /// Size of the locals in the calling function. 17 uint ilocalStackSize, flocalStackSize, slocalStackSize, olocalStackSize; 18 /// PC to jumps back to. 19 uint retPosition; 20 /// All current function deferred blocks. 21 uint[] deferStack; 22 /// All current function exception handling blocks. 23 uint[] exceptionHandlers; 24 } 25 26 /** 27 Snapshot of the context's state. \ 28 Used when we need to restore the context to a previous state. 29 */ 30 struct GrContextState { 31 /// Current expression stack top 32 int istackPos, /// Ditto 33 fstackPos, /// Ditto 34 sstackPos, /// Ditto 35 ostackPos; 36 37 /// Callstack 38 GrStackFrame stackFrame; 39 40 /// Stack frame pointer for the current function. 41 /// Each function takes 2 integer: the return pc, and the local variable size. 42 uint stackPos; 43 44 /// Local variables: Access with Xlocals[XlocalsPos + variableIndex] 45 uint ilocalsPos, flocalsPos, slocalsPos, olocalsPos; 46 } 47 48 /** 49 Pause the associated context. 50 */ 51 abstract class GrBlocker { 52 /// Update the state, returns true if the context is still paused. 53 bool run(); 54 } 55 56 /** 57 Coroutines are contexts that hold local data. 58 */ 59 final class GrContext { 60 /// Default ctor. 61 this(GrEngine engine_) { 62 engine = engine_; 63 setupCallStack(4); 64 setupStack(8); 65 setupLocals(2, 2, 2, 2); 66 } 67 68 /// Parent engine where the context is running. 69 GrEngine engine; 70 71 /// Local variables 72 GrInt[] ilocals; 73 /// Ditto 74 GrFloat[] flocals; 75 /// Ditto 76 GrString[] slocals; 77 /// Ditto 78 GrPtr[] olocals; 79 80 /// Callstack 81 GrStackFrame[] callStack; 82 83 /// Expression stack. 84 GrInt[] istack; 85 /// Ditto 86 GrFloat[] fstack; 87 /// Ditto 88 GrString[] sstack; 89 /// Ditto 90 GrPtr[] ostack; 91 92 /// Operation pointer. 93 uint pc; 94 /// Local variables: Access with Xlocals[XlocalsPos + variableIndex] 95 uint ilocalsPos, flocalsPos, slocalsPos, olocalsPos; 96 /// Stack frame pointer for the current function. 97 /// Each function takes 2 integer: the return pc, and the local variable size. 98 uint stackPos; 99 100 /// Current expression stack top 101 int istackPos = -1, /// Ditto 102 fstackPos = -1, /// Ditto 103 sstackPos = -1, /// Ditto 104 ostackPos = -1; 105 106 /// Kill state, unwind the call stack and call all registered deferred statements. 107 bool isKilled; 108 109 /// An exception has been raised an is not caught. 110 bool isPanicking; 111 112 /// Set when the context is in a select/case statement. 113 /// Then, the context is not stopped by a blocking channel. 114 bool isEvaluatingChannel; 115 116 /// Set when the context is forced to yield by a blocking channel. 117 /// Release only when the channel is ready. 118 bool isLocked; 119 120 /// When evaluating, a blocking jump to this position will occur instead of blocking. 121 uint selectPositionJump; 122 123 /// The context will block until the blocker is cleared. 124 GrBlocker blocker; 125 126 /// Backup to restore stack state after select evaluation. 127 GrContextState[] states; 128 129 /// Current callstack max depth. 130 uint callStackLimit; 131 /// Current max local variable available. 132 uint ilocalsLimit, flocalsLimit, slocalsLimit, olocalsLimit; 133 134 /// Initialize the call stacks. 135 void setupCallStack(uint size) { 136 callStackLimit = size; 137 callStack = new GrStackFrame[callStackLimit]; 138 } 139 140 /// Initialize the expression stacks. 141 void setupStack(uint size) { 142 istack = new GrInt[size]; 143 fstack = new GrFloat[size]; 144 sstack = new GrString[size]; 145 ostack = new GrPtr[size]; 146 } 147 148 /// Initialize the local variable stacks. 149 void setupLocals(uint isize, uint fsize, uint ssize, uint osize) { 150 ilocalsLimit = isize; 151 flocalsLimit = fsize; 152 slocalsLimit = ssize; 153 olocalsLimit = osize; 154 ilocals = new GrInt[ilocalsLimit]; 155 flocals = new GrFloat[flocalsLimit]; 156 slocals = new GrString[slocalsLimit]; 157 olocals = new GrPtr[olocalsLimit]; 158 } 159 160 /// Double the current callstack size. 161 void doubleCallStackSize() { 162 callStackLimit <<= 1; 163 callStack.length = callStackLimit; 164 } 165 166 /// Double the current integer locals stacks' size. 167 void doubleIntLocalsStackSize(uint localsStackSize) { 168 while (localsStackSize >= ilocalsLimit) 169 ilocalsLimit <<= 1; 170 ilocals.length = ilocalsLimit; 171 } 172 173 /// Double the current float locals stacks' size. 174 void doubleFloatLocalsStackSize(uint localsStackSize) { 175 while (localsStackSize >= flocalsLimit) 176 flocalsLimit <<= 1; 177 flocals.length = flocalsLimit; 178 } 179 180 /// Double the current string locals stacks' size. 181 void doubleStringLocalsStackSize(uint localsStackSize) { 182 while (localsStackSize >= slocalsLimit) 183 slocalsLimit <<= 1; 184 slocals.length = slocalsLimit; 185 } 186 187 /// Double the current object locals stacks' size. 188 void doubleObjectLocalsStackSize(uint localsStackSize) { 189 while (localsStackSize >= olocalsLimit) 190 olocalsLimit <<= 1; 191 olocals.length = olocalsLimit; 192 } 193 194 alias setBool = setValue!GrBool; 195 alias setInt = setValue!GrInt; 196 alias setFloat = setValue!GrFloat; 197 alias setString = setValue!GrString; 198 alias setPtr = setValue!GrPtr; 199 200 void setInt32(int value) { 201 setValue!GrInt(cast(GrInt) value); 202 } 203 204 void setInt64(long value) { 205 setValue!GrInt(cast(GrInt) value); 206 } 207 208 void setFloat32(float value) { 209 setValue!GrFloat(cast(GrFloat) value); 210 } 211 212 void setFloat64(double value) { 213 setValue!GrFloat(cast(GrFloat) value); 214 } 215 216 void setObject(GrObject value) { 217 setValue!GrPtr(cast(GrPtr) value); 218 } 219 220 void setArray(T)(GrArray!T value) { 221 setValue!GrPtr(cast(GrPtr) value); 222 } 223 224 void setIntArray(GrIntArray value) { 225 setValue!GrPtr(cast(GrPtr) value); 226 } 227 228 void setFloatArray(GrFloatArray value) { 229 setValue!GrPtr(cast(GrPtr) value); 230 } 231 232 void setStringArray(GrStringArray value) { 233 setValue!GrPtr(cast(GrPtr) value); 234 } 235 236 void setObjectArray(GrObjectArray value) { 237 setValue!GrPtr(cast(GrPtr) value); 238 } 239 240 void setIntChannel(GrIntChannel value) { 241 setValue!GrPtr(cast(GrPtr) value); 242 } 243 244 void setFloatChannel(GrFloatChannel value) { 245 setValue!GrPtr(cast(GrPtr) value); 246 } 247 248 void setStringChannel(GrStringChannel value) { 249 setValue!GrPtr(cast(GrPtr) value); 250 } 251 252 void setObjectChannel(GrObjectChannel value) { 253 setValue!GrPtr(cast(GrPtr) value); 254 } 255 256 void setEnum(T)(T value) { 257 setValue!GrInt(cast(GrInt) value); 258 } 259 260 void setForeign(T)(T value) { 261 setValue!GrPtr(cast(GrPtr) value); 262 } 263 264 private void setValue(T)(T value) { 265 static if (is(T == GrInt)) { 266 istackPos++; 267 istack[istackPos] = value; 268 } 269 else static if (is(T == GrBool)) { 270 istackPos++; 271 istack[istackPos] = value; 272 } 273 else static if (is(T == GrFloat)) { 274 fstackPos++; 275 fstack[fstackPos] = value; 276 } 277 else static if (is(T == GrString)) { 278 sstackPos++; 279 sstack[sstackPos] = value; 280 } 281 else static if (is(T == GrPtr)) { 282 ostackPos++; 283 ostack[ostackPos] = value; 284 } 285 } 286 287 /// Register the current state of the context 288 void pushState() { 289 GrContextState state; 290 state.istackPos = istackPos; 291 state.fstackPos = fstackPos; 292 state.sstackPos = sstackPos; 293 state.ostackPos = ostackPos; 294 state.stackPos = stackPos; 295 state.stackFrame = callStack[stackPos]; 296 state.ilocalsPos = ilocalsPos; 297 state.flocalsPos = flocalsPos; 298 state.slocalsPos = slocalsPos; 299 state.olocalsPos = olocalsPos; 300 states ~= state; 301 } 302 303 /// Restore the last state of the context 304 void restoreState() { 305 if (!states.length) 306 throw new Exception("Fatal error: pop context state"); 307 GrContextState state = states[$ - 1]; 308 istackPos = state.istackPos; 309 fstackPos = state.fstackPos; 310 sstackPos = state.sstackPos; 311 ostackPos = state.ostackPos; 312 stackPos = state.stackPos; 313 ilocalsPos = state.ilocalsPos; 314 flocalsPos = state.flocalsPos; 315 slocalsPos = state.slocalsPos; 316 olocalsPos = state.olocalsPos; 317 callStack[stackPos] = state.stackFrame; 318 } 319 320 /// Remove last state of the context 321 void popState() { 322 states.length--; 323 } 324 325 /// Lock the context until the blocker is cleared 326 void block(GrBlocker blocker_) { 327 blocker = blocker_; 328 } 329 330 /// Unlock the context from the blocker 331 void unblock() { 332 blocker = null; 333 } 334 335 /// Dump stacks info 336 string dump() { 337 import std.conv : to; 338 339 string result = "Context Dump:"; 340 result ~= "\nfstack: " ~ to!string(fstack[0 .. (fstackPos + 1)]); 341 result ~= "\nistack: " ~ to!string(istack[0 .. (istackPos + 1)]); 342 result ~= "\nsstack: " ~ to!string(sstack[0 .. (sstackPos + 1)]); 343 result ~= "\nostack: " ~ to!string(ostack[0 .. (ostackPos + 1)]); 344 return result; 345 } 346 }