10

我想改进为“断言”OCaml 3.12.1 构造生成的 lambda 代码。这是一个例子:

let f x =
    assert (x = 4);
    assert (2 + x = 6);
    assert (x - x = 0);
    exit x

上面的文件 longfilename.ml 代表了我希望改进 lambda 代码生成的大型 OCaml 模块。它编译为:

$ 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)从表面上看,给 命名,并使用编译时哈希表来存储和重用它似乎就足够了 。对于模块内优化,更改可能是可管理的(只要在每个编译单元处重置哈希表)。

我在这里有点超出我的深度,尤其是“在每个编译单元重置”部分。有什么提示吗?

4

1 回答 1

8

OCaml 编译器中已经有一种机制可以共享一些常量:请参阅asmcomp/compilenv.ml及其使用,特别是structured_constantsasmcomp/cmmgen.ml. 我不熟悉此代码,因此不确定为什么不共享您的特定用例,但似乎 lambda 代码中的 ;Const_base (Const_string foo)Const_immstring foo; 后者是共享的,而前者可能不是。

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

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

看看这些直接字符串是由常量发射代码 ( asmcomp/cmmgen.ml:emit_constant) 处理的方式,它们就像通常的字符串一样表示,所以也许你可以只修补编译器以使用immstringinassert_failed并且事情会起作用。

[由操作编辑]

更改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
于 2012-04-04T12:27:00.027 回答