Inheritance: Microsoft.Scripting.Interpreter.Instruction
Ejemplo n.º 1
0
        private void CompileTryExpression(Expression expr) {
            var node = (TryExpression)expr;

            Label startOfFinally = MakeLabel();

            if (node.Finally != null) {
                _finallyLabels.Push(new FinallyLabels(startOfFinally));
            }

            int startingStack = _currentStackDepth;


            int start = _instructions.Count;
            this.Compile(node.Body);
            int end = _instructions.Count;


            if (_currentStackDepth != -1) {
                AddBranch(startOfFinally);
            }

            if (node.Finally == null && node.Fault == null && node.Handlers.Count == 1) {
                var handler = node.Handlers[0];
                if (handler.Filter == null && handler.Test == typeof(Exception) && handler.Variable == null) {
                    if (EndsWithRethrow(handler.Body)) {
                        var fault = this.AddHandler(null, null, start, end);
                        _currentStackDepth = startingStack;
                        CompileWithoutRethrow(handler.Body);
                        fault.EndHandlerIndex = this._instructions.Count;
                        startOfFinally.Mark();
                        return;
                    }
                }
            }

            foreach (var handler in node.Handlers) {
                if (handler.Filter != null) throw new NotImplementedException();
                var parameter = handler.Variable;

                // TODO we should only create one of these if needed for a rethrow
                if (parameter == null) {
                    parameter = Expression.Parameter(handler.Test, "currentException");
                    AddVariable(parameter);
                }
                this.AddHandler(handler.Test, parameter, start, end);

                _exceptionForRethrowStack.Push(parameter);
                _currentStackDepth = startingStack + 1;
                SetVariable(parameter, true);
                
                this.Compile(handler.Body);

                //TODO pop this scoped variable that we no longer need
                //PopVariable(parameter);
                _exceptionForRethrowStack.Pop();

                AddBranch(startOfFinally);
            }
            
            if (node.Fault != null) {
                throw new NotImplementedException();
            }

            if (node.Finally != null) {
                var myLabels = _finallyLabels.Pop();
                var myNewTargets = new List<Label>();

                int finallyStart = _instructions.Count;
                ParameterExpression finallyStateVar = null;
                ParameterExpression finallyStackValue = null;

                foreach (var kv in myLabels.labels) {
                    var label = kv.Key;
                    if (label._index == -1 || label._index < start || label._index > finallyStart) {
                        myNewTargets.Add(label);
                        var currentLabel = MakeLabel();
                        _currentStackDepth = -1;
                        currentLabel._expectedStackSize = label._expectedStackSize;
                        currentLabel.Mark();
                        foreach (var branch in kv.Value) {
                            currentLabel.SetOffset(branch);
                            label.RemoveBinding(branch);
                        }
                        if (finallyStateVar == null) {
                            finallyStateVar = Expression.Parameter(typeof(int), "finallyBranch");
                            AddVariable(finallyStateVar);
                            finallyStackValue = Expression.Parameter(typeof(object), "stackValue");
                            AddVariable(finallyStackValue);
                        }
                        if (myLabels.labelHasValue[label]) {
                            SetVariable(finallyStackValue, true);
                        }
                        PushConstant(myNewTargets.Count-1);
                        SetVariable(finallyStateVar, true);

                        AddBranch(startOfFinally);
                    }
                }

                _currentStackDepth = startingStack + ((node.Body.Type == typeof(void)) ? 0 : 1);

                startOfFinally.Mark();
                var faultHandler = this.AddHandler(null, null, start, end);
                this.Compile(node.Finally);
                if (node.Finally.Type != typeof(void)) {
                    AddInstruction(PopInstruction.Instance);
                }
                faultHandler.EndHandlerIndex = _instructions.Count;

                if (finallyStateVar != null) {
                    // we can make this much more efficient in the future
                    var si = new SwitchInstruction();
                    AddInstruction(GetVariable(finallyStateVar));

                    int switchIndex = _instructions.Count;
                    AddInstruction(si);
                    int switchStack = _currentStackDepth;
                    for (int i = 0; i < myNewTargets.Count; i++) {
                        _currentStackDepth = switchStack;
                        si.AddCase(i, _instructions.Count-switchIndex);
                        if (myLabels.labelHasValue[myNewTargets[i]]) {
                            AddInstruction(GetVariable(finallyStackValue));
                        }
                        var branchInstruction = AddBranch(myNewTargets[i]);
                        if (_finallyLabels.Count > 0) {
                            var labels = _finallyLabels.Peek();
                            labels.AddBranch(branchInstruction, myNewTargets[i], myLabels.labelHasValue[myNewTargets[i]]);
                        }
                    }
                    si.AddDefault(_instructions.Count - switchIndex);
                    _currentStackDepth = switchStack; // we might exit totally normally!
                }
            } else {
                startOfFinally.Mark();
            }

        }
Ejemplo n.º 2
0
        private void CompileSwitchExpression(Expression expr) {
            var node = (SwitchExpression)expr;

            if (node.Test.Type != typeof(int)) throw new NotImplementedException();

            Debug.Assert(node.Type == typeof(void));

            this.Compile(node.Test);
            int start = _instructions.Count;
            var switchInstruction = new SwitchInstruction();
            AddInstruction(switchInstruction);
            bool setDefault = false;
            int switchStack = _currentStackDepth;
            foreach (var clause in node.SwitchCases) {
                _currentStackDepth = switchStack;
                int offset = _instructions.Count - start;
                if (clause.IsDefault) {
                    setDefault = true;
                    switchInstruction.AddDefault(offset);
                } else {
                    switchInstruction.AddCase(clause.Value, offset);
                }
                this.Compile(clause.Body);
                Debug.Assert(_currentStackDepth == -1 || _currentStackDepth == switchStack);
            }
            if (!setDefault) {
                switchInstruction.AddDefault(_instructions.Count - start);
                _currentStackDepth = switchStack;
            }

            if (node.BreakLabel != null) {
                ReferenceLabel(node.BreakLabel).Mark();
            }
        }