GHC的设计基于一种名为STG的东西,它代表"无骨架,无标签G机".
现在G-machine显然是"图形缩减机"的缩写,它定义了如何实现懒惰.未评估的thunk被存储为表达式树,并且执行该程序涉及将这些减少到正常形式.(树是非循环图,但Haskell的普遍递归意味着Haskell表达式形成一般图,因此图减少而不是树减少.)
不太清楚的是术语"无骨"和"无标记".
我认为 "无脊椎"指的是功能应用程序没有功能应用程序节点的"脊椎"这一事实.相反,您有一个对象,该对象命名所调用的函数并指向其所有参数.那是对的吗?
我认为"无标签"指的是构造函数节点没有用构造函数ID"标记",而是使用跳转指令解析case-expression.但现在我不确定这是否正确.相反,它似乎指的是节点没有用其评估状态标记的事实.谁能澄清这些解释中哪些(如果有的话)是正确的?
我想知道.maxstack是如何工作的.我知道它与您声明的类型的实际大小无关,而与它们的数量有关.我的问题是:
编译的一个趋势是使用类型化的中间语言.Haskell的ghc与它的core中间语言,系统F-ω变体,是本体系结构[1]的一个例子.另一个是LLVM,它的核心是一种类型化的中间语言[2].这种方法的好处是可以及早检测构成代码生成器部分的转换中的错误.此外,可以在优化和代码生成期间使用类型信息.
为了提高效率,对类型化的IR进行类型检查,而不是推断它们的类型.为了快速进行类型检查,每个变量和每个活页夹都带有类型以便于类型检查.
但是,编译器管道中的许多转换可能会引入新变量.例如,规范化转换K(.)可能会转换应用程序
M(N)
Run Code Online (Sandbox Code Playgroud)
变成一个表达式
let x = K(M) in
let y = K(N) in x(y)
Run Code Online (Sandbox Code Playgroud)
题.我想知道编译器如何处理给新引入的变量赋予类型的问题.难道他们重新类型检测,在上面的例子中K(M)和K(N)?这不是很费时间吗?它需要通过环境吗?他们是否使用AST节点中的映射来键入信息以避免重新运行类型检查?
S. Marlow,S.Peyton Jones,格拉斯哥Haskell编译器.
compiler-construction ghc intermediate-language compiler-optimization llvm-ir
什么backpatching意思?请举一个简单的例子来说明.
language-agnostic compiler-construction intermediate-language intermediate-code
与反编译本机x86二进制文件相比,为什么将.NET IL-code反编译为源代码如此容易?(Reflector在大多数情况下都会生成相当好的源代码,而反编译C++编译器的输出几乎是不可能的.)
是因为IL包含大量元数据吗?或者是因为IL是比x86指令更高的抽象?我做了一些研究,发现了以下两篇有用的文章,但它们都没有回答我的问题.
如果我想创建一个以实例IList作为参数(或任何其他接口,但让我们IList用作示例)的方法,我可以创建一个带有类型约束的泛型方法,例如:
public static void Foo1<T>(T list) where T : IList
{
}
Run Code Online (Sandbox Code Playgroud)
或者,我可以创建一个IList直接获取参数的方法:
public static void Foo2(IList list)
{
}
Run Code Online (Sandbox Code Playgroud)
对于所有意图和目的,似乎这些方法的行为完全相同:
List<string> myList = new List<string>();
Foo1(myList);
Foo2(myList);
Run Code Online (Sandbox Code Playgroud)
所以这是我的问题 - 这两种方法之间的区别是什么?似乎第二种方法更具可读性; 我应该注意哪些其他差异(生成不同的IL等)?提前致谢.
c# generics intermediate-language type-constraints type-parameter
如果我查看Linqpad中为以下两个代码片段创建的IL,我想知道这里发生了什么.
在c#中
int i = 42;
Run Code Online (Sandbox Code Playgroud)
得到以下IL代码
IL_0000: ret
Run Code Online (Sandbox Code Playgroud)
而在VB中
Dim i As Integer = 42
Run Code Online (Sandbox Code Playgroud)
它是
IL_0000: ldc.i4.s 2A
IL_0002: stloc.0
Run Code Online (Sandbox Code Playgroud)
显然,c#编译器理解该值从未使用过,因此根本不返回任何内容.在VB.NET中,实际代码被翻译.
这是由于编译器优化的差异还是还有其他工作原因?
更新:只是为了澄清这一点 - 我只是将这一行输入LinqPad并查看它创建的IL(最明确的是运行相应的编译器).有没有计划.
c# vb.net compiler-construction intermediate-language linqpad
我正在研究一种中间语言和一个虚拟机来运行具有一些"有问题"属性的函数式语言:
中间语言是基于堆栈的,具有当前命名空间的简单哈希表.只是让你了解它的外观,这是McCarthy91的功能:
# McCarthy 91: M(n) = n - 10 if n > 100 else M(M(n + 11))
.sub M
args
sto n
rcl n
float 100
gt
.if
.sub
rcl n
float 10
sub
.end
.sub
rcl n
float 11
add
list 1
rcl M
call-fast
list 1
rcl M
tail
.end
call-fast
.end
Run Code Online (Sandbox Code Playgroud)
"大循环"很简单:
随着sto,rcl和一大堆更多,有三种指令函数调用:
call 复制命名空间(深层复制)并将指令指针推送到调用堆栈call-fast 是相同的,但只创建一个浅的副本tail 基本上是'转到''实施非常简单.为了给你一个更好的主意,这里只是一个来自"大循环"中间的随机片段(更新,见下文)
} else …Run Code Online (Sandbox Code Playgroud) interpreter functional-programming go intermediate-language vm-implementation
比如我有(list "a" "1" "b" "2" "c" "3").
现在我想把这个列表变成一个"a1b2c3".
我怎么做?
谢谢.
您可以在IL中的.NET中的接口上定义静态构造函数.但是,如果这样做,则在接口上运行方法时不会运行静态构造函数:
.method public static void Main() {
.entrypoint
.locals init ( class IInterface cls1 )
// InterfaceClass static constructor is run
newobj instance void InterfaceClass::.ctor()
stloc.0
ldloc.0
// IInterface static constructor is not run!!!!!
callvirt instance int32 IInterface::Method()
call void [mscorlib]System.Console::WriteLine(int32)
ret
}
.class public interface IInterface {
.method private static specialname rtspecialname void .cctor() {
ldstr "Interface static cctor"
call void [mscorlib]System.Console::WriteLine(string)
ret
}
.method public abstract virtual instance int32 Method() {}
}
.class public InterfaceClass implements IInterface { …Run Code Online (Sandbox Code Playgroud) .net ×3
c# ×3
bytecode ×2
ghc ×2
vb.net ×2
cil ×1
compilation ×1
decompiling ×1
generics ×1
go ×1
haskell ×1
interface ×1
interpreter ×1
linqpad ×1
list ×1
llvm-ir ×1
racket ×1
reflection ×1
scheme ×1
string ×1