2009-04-30 5 views
7

스택없는 VM이란 시스템 "C-stack"을 사용하는 대신 자체 스택을 힙에 유지하는 구현을 의미합니다. 이것은 연속성 및 직렬화 가능 상태와 같은 많은 장점을 가지고 있지만 C 바인딩, 특히 C-VM-C 종류의 콜백 (또는 VM-C-VM)과 관련하여 몇 가지 단점이 있습니다.스택없는 VM 구현에서 어떤 C- 통합 문제가 발생합니까?

이러한 단점은 정확히 무엇입니까? 아무도 진짜 문제의 좋은 본보기를 줄 수 있습니까?

답변

5

당신은 이미 몇 가지 단점과 장점에 익숙한 것 같습니다.

일부 다른

: 그것은 B)가 쉬운 언어 수준 "스택 추적" C) 쉬운 같은 것들을 구성하는 기본 구현은 어떤 지원이없는 경우에도 는) 적절한 꼬리를 호출 최적화를 지원하는 것을 가능하게 당신이 지적한 바와 같이 적절한 연속을 추가하십시오.

저는 최근 C#에서 처음으로 .NET 스택을 사용하는 간단한 "Scheme"인터프리터를 작성했습니다. 그때 명시 적 스택을 사용하도록 썼다 재 - 그래서 아마도 다음은 당신을 도울 것입니다 :

첫 번째 버전은 암시 적 .NET 런타임 스택을 사용 ...

을 처음에는 그냥 클래스 계층이었다, 다른 형태 (람다,하자 등) 다음과 같은 인터페이스 인 구현과 : 추가에 대한

/// <summary> 
/// Fundamental interface for resolving "symbols" subject to scoping. 
/// </summary> 
public interface IEnvironment 
{ 
    object Lookup(string name); 
    IEnvironment Extend(string name, object value); 
} 

"예상대로

IEnvironment 모습

// A "form" is an expression that can be evaluted with 
// respect to an environment 
// e.g. 
// "(* x 3)" 
// "x" 
// "3" 
public interface IForm 
{ 
    object Evaluate(IEnvironment environment); 
} 

/// <summary> 
/// A function is either a builtin function (i.e. implemented directly in CSharp) 
/// or something that's been created by the Lambda form. 
/// </summary> 
public interface IFunction 
{ 
    object Invoke(object[] args); 
} 

는 암시 .NET 런타임 스택을 사용하는 경우였다 내 계획 인터프리터에 내장 명령은 "나는 처음에 다음과 같은 인터페이스를 가지고 있었다. 분명히 적은 코드가 있었지만 적절한 테일 재귀와 같은 것을 추가하는 것은 불가능했습니다. 가장 중요한 것은 인터프리터가 런타임 오류의 경우 "언어 수준"스택 추적을 제공하는 것이 어려웠습니다.

따라서 명시 적 (힙 할당) 스택을 갖도록 다시 작성했습니다.

내 "IFunction"인터페이스

내가 다시 계획 인터프리터에 전화 "지도"와 "적용"같은 것들을 구현할 수 있도록, 다음으로 변경했다 :

/// <summary> 
/// A function that wishes to use the thread state to 
/// evaluate its arguments. The function should either: 
/// a) Push tasks on to threadState.Pending which, when evaluated, will 
/// result in the result being placed on to threadState.Results 
/// b) Push its result directly on to threadState.Results 
/// </summary> 
public interface IStackFunction 
{ 
    void Evaluate(IThreadState threadState, object[] args); 
} 

그리고 IForm로 변경 :

public interface IForm 
{ 
    void Evaluate(IEnvironment environment, IThreadState s); 
} 

IThreadState은 다음과 같다 여기서

/// <summary> 
/// The state of the interpreter. 
/// The implementation of a task which takes some arguments, 
/// call them "x" and "y", and which returns an argument "z", 
/// should follow the following protocol: 
/// a) Call "PopResult" to get x and y 
/// b) Either 
/// i) push "z" directly onto IThreadState using PushResult OR 
/// ii) push a "task" on to the stack which will result in "z" being 
///  pushed on to the result stack. 
/// 
/// Note that ii) is "recursive" in its definition - that is, a task 
/// that is pushed on to the task stack may in turn push other tasks 
/// on the task stack which, when evaluated, 
/// ... ultimately will end up pushing the result via PushResult. 
/// </summary> 
public interface IThreadState 
{ 
    void PushTask(ITask task); 
    object PopResult(); 
    void PushResult(object result); 
} 

그리고 아이 태스크이다 :

public interface ITask 
{ 
    void Execute(IThreadState s); 
} 

그리고 내 주요 "이벤트"루프는 다음과 같습니다

ThreadState threadState = new ThreadState(); 
threadState.PushTask(null); 
threadState.PushTask(new EvaluateForm(f, environment)); 
ITask next = null; 

while ((next = threadState.PopTask()) != null) 
    next.Execute(threadState); 

return threadState.PopResult(); // Get what EvaluateForm evaluated to 

EvaluateForm은 특정 환경 IForm.Evaluate를 호출하는 작업입니다.

개인적으로,이 새로운 버전은 구현 관점에서 작동하기에 훨씬 "더 멋집니다."- 스택 추적을 쉽게 얻을 수 있으며 전체 연속을 구현하기 쉽습니다. 아직 C# Stack을 사용하지 않고 내 "스택"영구 링크 된 목록을 만들어야하고 ITask는 "call-continuation"작업을 수행 할 수 있도록 변경하기보다는 새 ThreadState를 "반환"합니다.

기본적으로 기본 언어 구현에 대한 의존도가 낮습니다.

유일한 단점은 성능입니다 ...하지만 제 경우에는 해석기이므로 성능에 대해서는별로 신경 쓰지 않습니다.

나는 또한 다시 쓰는 KAI C++ 컴파일러의 저자 중 하나에 의해, 스택과 함께 반복적 인 코드로 재귀 코드의 장점에 대한이 아주 좋은 문서를 가리키는 것 : Considering Recursion

+0

실제로 실제로 원시 코드 통합 만 고려하면 단점이있었습니다. 그러나 이야기에 감사드립니다. –

1

후 전자 Steve Dekorte (Io 프로그래밍 언어 작성자)와 Konstantin Olenin과의 메일 대화에서 문제와 해결책을 발견했습니다. VM에서 C 함수로의 호출을 상상해보십시오.이 함수는 VM 메서드를 다시 호출합니다. VM이 콜백을 실행하는 시간 동안 VM 상태의 일부는 VM 스택 외부에 배치됩니다 (C 스택 및 레지스터에 있음). 그 순간에 VM 상태를 저장하면 다음에 VM을로드 할 때 상태를 올바르게 복원 할 수 없다는 것을 보장합니다.

해결 방법은 VM을 메시지 수신자로 모델링하는 것입니다. VM은 비동기 알림을 원시 코드로 보내고 원시 코드는 VM에 비동기 알림을 보낼 수 있습니다. 즉, 단일 스레드 환경에서 VM이 제어를 받으면 VM 런타임과 관련없는 데이터를 제외하고 추가 상태가 저장되지 않습니다.

이것은 어떤 상황에서도 VM 상태를 올바르게 복원 할 수는 있지만 최소한 신뢰할 수있는 시스템을 빌드 할 수 있음을 의미하지는 않습니다.

관련 문제