Ответ 1
Я не знаком с F #, но я написал интерпретатор ECMAScript-262 v.5 на С#, чтобы я мог относиться к некоторым вашим проблемам. Как вы знаете, исключение StackOverFlowException не может быть обнаружено в .NET-приложениях с версии 2.0. Существует довольно надежное обходное решение, хотя и быстро.
Если вы объявляете переменную в стеке, например int, адрес этой переменной представляет верхнюю часть стека и позволяет вам узнать, сколько осталось места. Итак, если вы записываете эту переменную при запуске, в то время как стек в основном пуст, вы можете ссылаться на него каждый раз, когда вы вводите новый контекст выполнения.
Вот несколько примеров из моего интерпретатора, которые решают эту проблему.
С#:
Это статические переменные, объявленные в основном классе Interpreter.
private static int TopOfStack;
private const int STACK_SIZE = 1000000;
Это статический конструктор основного класса Interpreter.
static Interpreter() {
InitializeGlobalEnvironment();
//---------------------------------------------------
// Get the address of a new variable allocated on the stack
// to represent the amount of memory available. Record
// the address.
//---------------------------------------------------
int stackVariable;
TopOfStack = (int)&stackVariable;
}
Этот код вызывается до того, как интерпретируется функция ECMAScript. Если адрес новой распределенной таблицы меньше чем short.Max, я бросаю catchable исключение. Вам нужно оставить некоторое пространство для стека вызовов, чтобы расслабиться.
internal static ExecutionContext EnterFunctionContext(IValue thisArg, LIST args, FUNCTION function) {
...
LexicalEnvironment localEnv = ECMA.NewDeclarativeEnvironment(function.Scope);
ExecutionContext context = new ExecutionContext() {
Strict = function.IsStrict,
VariableEnvironment = localEnv,
LexicalEnvironment = localEnv
};
int remainingStackSpace;
if (STACK_SIZE - (TopOfStack - (int)&remainingStackSpace) < short.MaxValue)
throw new ECMARuntimeException("stack overflow", RuntimeErrorType.RangeError);
CallStack.Push(context);
LexicalEnvironment env = CurrentContext.VariableEnvironment;
...
}
Когда следующий код интерпретируется, исключение создается вокруг итерации 1200.
Обновление: В сборке релизов около 4100 итераций.
ECMAScript:
RecursiveCall(0);
function RecursiveCall(counter){
return RecursiveCall(++counter);
}
Выход: RangeError: stack overflow
Вы можете увеличить размер стека в потоке с помощью конструктора Thread(ParameterizedThreadStart, Int32)
. Я просто не ощущал нужды.
Удачи вам в вашем проекте. Надеюсь, это поможет.