【问题标题】:Language with smart array allocation (heap or stack)具有智能数组分配(堆或堆栈)的语言
【发布时间】: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

然而,这个设计让我害怕有几个原因:

  1. 增加了复杂性,编译时间更长?
  2. 在 C++ 中,编译器可以执行 RVO 并直接在堆栈上返回一个值。我想我可以让算法更复杂来检测这种情况,但这会使整个事情变得更复杂/有缺陷/编译速度慢。
  3. 数组大小的微小变化可能会导致从堆栈切换到堆。这可能会让用户感到困惑。定义此阈值也需要小心。
  4. 我需要检查是否没有返回对该数组的某些引用(以及引用的引用等)。我想这可能会很昂贵。

请注意,我不想在我的语言中公开指针或引用。数组将始终在后台通过引用传递。

文献中有没有解决这个问题的巧妙方法?以前用现有的语言做过吗?我知道的所有语言都要求用户指定他们想要数据的位置:Fortran 有::allocatable,C++ 有std::vectorstd::array,等等。我也可以做一些类似llvm 的SmallVector 并且总是分配一些元素在移动到堆之前在堆栈上。我的方法有任何意义吗?我正在使用这个项目来了解更多关于编译器和语言设计的信息。有什么需要注意的吗?

【问题讨论】:

  • 根据定义,当创建它们的函数返回时,“堆栈上”的对象会自动销毁。没有例外。您是如何在您的语言的 C++ 实现中提出的,以保证在创建对象的 C++ 函数返回后,不再需要您的语言的对象?
  • 我想到了类似于 C++ 中的 RVO 的东西。但是,我需要更进一步,并确保调用者没有返回堆栈上的对象。否则,调用者的调用者最终会得到一个悬空指针。
  • 你的语言有指针/引用吗?也就是说,是否可以将数组的引用/指针作为参数传递给函数,然后该函数将引用/指针存储在变量中?
  • 默认答案是肯定的:人们可以创建现有变量的引用。但是,如果这变得太成问题,那么从语言中删除此类引用可能不会那么糟糕(除了函数参数)。它肯定会简化堆栈/堆分配的分析。
  • @Touloudou 我在问,因为在这种情况下,您不必担心返回数组,还需要担心将数组的引用传递给另一个函数,该函数将其存储在一个变量中(意味着引用可能比创建数组的函数寿命更长)。

标签: c++ compiler-construction llvm language-design


【解决方案1】:

这个选项真的取决于你,但如果我是你,我会让用户选择是在堆上分配还是在堆栈上分配。如果没有,它很可能会让您和用户感到非常困惑。如果您仍想实现该功能,我有一些提示。

  • 与其检查是否在编译时无法知道,不如检查在编译时可以知道的内容——这会简化事情。
  • 默认情况下在堆或堆栈上定义所有内容——这将使您更容易处理需要从堆栈切换到堆(反之亦然)的情况(这更容易,因为假设当append 被调用时,您可以切换到堆)。

最后,我建议您让用户明确声明堆栈或堆上的数组。

【讨论】:

    猜你喜欢
    • 2012-10-04
    • 2017-05-06
    • 1970-01-01
    • 2017-03-25
    • 2014-05-13
    • 1970-01-01
    • 2013-01-25
    • 2012-03-31
    相关资源
    最近更新 更多