public void Dispose() { // Write the cache back out to backing storage foreach (var(name, local) in _cache.OrderByDescending(a => SegmentIndex(a.Key))) { if (_mutated.Contains(name)) { var skip = _emitter.DefineLabel(); var dirty = _cacheDirty[name]; _emitter.LoadLocal(dirty); _emitter.BranchIfFalse(skip); _emitter.LoadLocal(local.Local); _emitter.EmitCoerce(local.Type, StackType.YololValue); EmitStoreValue(name); _emitter.MarkLabel(skip); } local.Local.Dispose(); } // Dispose the locals foreach (var local in _cacheDirty) { local.Value.Dispose(); } }
/// <summary> /// Emit code to dynamically check for errors. If an error would occur clear out the stack and jump away to the given label /// </summary> /// <typeparam name="TEmit"></typeparam> /// <param name="emitter"></param> /// <param name="errorLabel"></param> /// <param name="parameters"></param> public void EmitDynamicWillThrow <TEmit>(OptimisingEmitter <TEmit> emitter, Compiler.Emitter.Instructions.ExceptionBlock errorLabel, IReadOnlyList <Local> parameters) { // Load parameters back onto stack for (var i = parameters.Count - 1; i >= 0; i--) { emitter.LoadLocal(parameters[i]); } // Invoke the `will throw` method to discover if this invocation would trigger a runtime error emitter.Call(WillThrow); // Create a label to jump past the error handling for the normal case var noThrowLabel = emitter.DefineLabel(); // Jump past error handling if this is ok emitter.BranchIfFalse(noThrowLabel); // If execution reaches here it means an error would occur in this operation emitter.Leave(errorLabel); emitter.MarkLabel(noThrowLabel); }