改进OCaml为断言生成的lambda代码

改进OCaml为断言生成的lambda代码,ocaml,Ocaml,我想改进为“assert”OCAML3.12.1构造生成的lambda代码。以下是一个例子: let f x = assert (x = 4); assert (2 + x = 6); assert (x - x = 0); exit x 上面的文件longfilename.ml代表了大型OCaml模块,我希望改进lambda代码生成。它汇编为: $ ocamlopt -S longfilename.ml $ cat longfilename.s ...

我想改进为“assert”OCAML3.12.1构造生成的lambda代码。以下是一个例子:

let f x =
    assert (x = 4);
    assert (2 + x = 6);
    assert (x - x = 0);
    exit x
上面的文件longfilename.ml代表了大型OCaml模块,我希望改进lambda代码生成。它汇编为:

$ ocamlopt -S longfilename.ml
$ cat longfilename.s
...
    .data
    .quad   3072
_camlLongfilename__2:
    .quad   L100007
    .quad   9
    .quad   9
    .quad   2300
L100007: .L100007:
    .ascii  "longfilename.ml"
    .byte   0
    .data
    .quad   3072
_camlLongfilename__3:
    .quad   L100006
    .quad   7
    .quad   9
    .quad   2300
L100006: .L100006:
    .ascii  "longfilename.ml"
    .byte   0
    .data
    .quad   3072
_camlLongfilename__4:
    .quad   L100005
    .quad   5
    .quad   9
    .quad   2300
L100005: .L100005:
    .ascii  "longfilename.ml"
    .byte   0
...
以上这些都是多余的。每个断言可能来自的源文件的名称是重复的。罪魁祸首似乎是bytecomp/translcore.ml:

let assert_failed loc =
  (* [Location.get_pos_info] is too expensive *)
  let fname = match loc.Location.loc_start.Lexing.pos_fname with
              | "" -> !Location.input_name
              | x -> x
  in
  let pos = loc.Location.loc_start in
  let line = pos.Lexing.pos_lnum in
  let char = pos.Lexing.pos_cnum - pos.Lexing.pos_bol in
  Lprim(Praise, [Lprim(Pmakeblock(0, Immutable),
          [transl_path Predef.path_assert_failure;
           Lconst(Const_block(0,
              [Const_base(Const_string fname);
               Const_base(Const_int line);
               Const_base(Const_int char)]))])])
;;
从表面上看,这似乎足以给它起一个名字
Const_base(Const_string fname)
,并与 编译时哈希表。对于模块内优化, 这些变化可能是可控的 (只要哈希表在每个编译单元重置)

我在这里有点深奥,尤其是“每次编译时重置”
“单位”部分。有什么提示吗?

OCaml编译器中已经有一种机制可以共享一些常量:请参见
asmcomp/compilenv.ml
及其使用,特别是
asmcomp/cmmgen.ml
中的
结构化_常量值。我不熟悉这段代码,所以我不确定为什么您的特定用例没有被共享,但在lambda代码中,
Const_base(Const_string foo)
Const_immstring foo
之间似乎有区别;后者是共享的,也许前者不是

我不知道
immstring
的预期语义是什么。编译器似乎在内部使用它来编译方法标签(
bytecomp/translass.ml
),但不暴露于输入语言

(我怀疑区别是因为字符串是可变的,因此共享用户可见字符串将是可观察的,并改变程序行为。但是字符串常量已经被lambda取消,因此用户可以观察到语义不一致的共享。增加用户可见字符串的共享可能仍然会被拒绝,因为这是一种兼容性break.)

看看常量发出代码(
asmcomp/cmmgen.ml:emit_constant
)处理这些立即字符串的方式,它们的表示方式与普通字符串类似,因此您可以在
assert_failed
中修补编译器以使用
immstring
,一切都会正常

[按OP编辑]

Const_base(Const_string fname)
更改为
Const_immstring fname
,虽然稍微不兼容,但允许OCaml编译自己,编译Frama-C,新Frama-C通过回归测试。在原始示例中,效果如下,这正是预期的结果:

$ cat longfilename.s 
...
    .data
    .quad   3072
_camlLongfilename__2:
    .quad   L100005
    .quad   9
    .quad   9
    .data
    .quad   3072
_camlLongfilename__3:
    .quad   L100005
    .quad   7
    .quad   9
    .data
    .quad   3072
_camlLongfilename__4:
    .quad   L100005
    .quad   5
    .quad   9
    .quad   2300
L100005: .L100005:
    .ascii  "longfilename.ml"
    .byte   0

我知道在你可以简单地接受答案的情况下发表评论是不礼貌的,但我想祝贺你提供的解决方案。做得好。好,谢谢:)一旦你在,事实上知道这件事的人会告诉你这个想法有多糟糕。我宁愿保留我在问题追踪器上所能引起的对我没有解决办法的丑陋问题的一点关注,但请随意对5573发表意见。如果我找到一个解决方案,我会提交你的解决方案,作为一个补丁值得审查。