【发布时间】:2020-07-25 02:25:54
【问题描述】:
我正在为(有趣和)科学应用程序编写一个小型玩具语言/编译器。核心设计原则是简单和高效(如果你愿意,可以使用某种“现代”Fortran)。该语言将具有内置数组,看起来像这样:
let x: Real[5] = {1.0, 2.0, 3.0, 4.0, 5.0}
let n = get_runtime_value()
let y: Integer[100,n] = ...
在上面的语句中,用户没有明确说明数组应该分配在栈上还是堆上。如果可能的话,我宁愿不把它暴露给用户(我的理由是大多数工程师不知道其中的区别,也不应该关心。他们还有其他问题要担心。)。
从技术上讲,我可以这样写:
if (some input parameter cannot be known at compile time)
allocate on the heap
else # candidate for the stack
if (the array is not returned by the function && the allocated size is smaller than some threshold)
allocate on the stack
else
allocate on the heap
然而,这个设计让我害怕有几个原因:
- 增加了复杂性,编译时间更长?
- 在 C++ 中,编译器可以执行 RVO 并直接在堆栈上返回一个值。我想我可以让算法更复杂来检测这种情况,但这会使整个事情变得更复杂/有缺陷/编译速度慢。
- 数组大小的微小变化可能会导致从堆栈切换到堆。这可能会让用户感到困惑。定义此阈值也需要小心。
- 我需要检查是否没有返回对该数组的某些引用(以及引用的引用等)。我想这可能会很昂贵。
请注意,我不想在我的语言中公开指针或引用。数组将始终在后台通过引用传递。
文献中有没有解决这个问题的巧妙方法?以前用现有的语言做过吗?我知道的所有语言都要求用户指定他们想要数据的位置:Fortran 有::allocatable,C++ 有std::vector 和std::array,等等。我也可以做一些类似llvm 的SmallVector 并且总是分配一些元素在移动到堆之前在堆栈上。我的方法有任何意义吗?我正在使用这个项目来了解更多关于编译器和语言设计的信息。有什么需要注意的吗?
【问题讨论】:
-
根据定义,当创建它们的函数返回时,“堆栈上”的对象会自动销毁。没有例外。您是如何在您的语言的 C++ 实现中提出的,以保证在创建对象的 C++ 函数返回后,不再需要您的语言的对象?
-
我想到了类似于 C++ 中的 RVO 的东西。但是,我需要更进一步,并确保调用者没有返回堆栈上的对象。否则,调用者的调用者最终会得到一个悬空指针。
-
你的语言有指针/引用吗?也就是说,是否可以将数组的引用/指针作为参数传递给函数,然后该函数将引用/指针存储在变量中?
-
默认答案是肯定的:人们可以创建现有变量的引用。但是,如果这变得太成问题,那么从语言中删除此类引用可能不会那么糟糕(除了函数参数)。它肯定会简化堆栈/堆分配的分析。
-
@Touloudou 我在问,因为在这种情况下,您不必担心返回数组,还需要担心将数组的引用传递给另一个函数,该函数将其存储在一个变量中(意味着引用可能比创建数组的函数寿命更长)。
标签: c++ compiler-construction llvm language-design