Parcourir la source

Add a global arena to start cleaning up ASAN errors (#687)

Jon Meow il y a 4 ans
Parent
commit
b08f6bb0f1

+ 1 - 0
.codespell_ignore

@@ -6,3 +6,4 @@ circularly
 copyable
 inout
 pullrequest
+statics

+ 1 - 0
executable_semantics/ast/BUILD

@@ -31,6 +31,7 @@ cc_library(
     deps = [
         "//common:indirect_value",
         "//common:ostream",
+        "//executable_semantics/common:arena",
         "//executable_semantics/common:error",
         "@llvm-project//llvm:Support",
     ],

+ 16 - 15
executable_semantics/ast/expression.cpp

@@ -4,6 +4,7 @@
 
 #include "executable_semantics/ast/expression.h"
 
+#include "executable_semantics/common/arena.h"
 #include "executable_semantics/common/error.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/raw_ostream.h"
@@ -54,28 +55,28 @@ auto Expression::GetFunctionTypeLiteral() const -> const FunctionTypeLiteral& {
 }
 
 auto Expression::MakeTypeTypeLiteral(int line_num) -> const Expression* {
-  auto* t = new Expression();
+  auto* t = global_arena->New<Expression>();
   t->line_num = line_num;
   t->value = TypeTypeLiteral();
   return t;
 }
 
 auto Expression::MakeIntTypeLiteral(int line_num) -> const Expression* {
-  auto* t = new Expression();
+  auto* t = global_arena->New<Expression>();
   t->line_num = line_num;
   t->value = IntTypeLiteral();
   return t;
 }
 
 auto Expression::MakeBoolTypeLiteral(int line_num) -> const Expression* {
-  auto* t = new Expression();
+  auto* t = global_arena->New<Expression>();
   t->line_num = line_num;
   t->value = BoolTypeLiteral();
   return t;
 }
 
 auto Expression::MakeAutoTypeLiteral(int line_num) -> const Expression* {
-  auto* t = new Expression();
+  auto* t = global_arena->New<Expression>();
   t->line_num = line_num;
   t->value = AutoTypeLiteral();
   return t;
@@ -84,7 +85,7 @@ auto Expression::MakeAutoTypeLiteral(int line_num) -> const Expression* {
 // Returns a Continuation type AST node at the given source location.
 auto Expression::MakeContinuationTypeLiteral(int line_num)
     -> const Expression* {
-  auto* type = new Expression();
+  auto* type = global_arena->New<Expression>();
   type->line_num = line_num;
   type->value = ContinuationTypeLiteral();
   return type;
@@ -93,7 +94,7 @@ auto Expression::MakeContinuationTypeLiteral(int line_num)
 auto Expression::MakeFunctionTypeLiteral(int line_num, const Expression* param,
                                          const Expression* ret)
     -> const Expression* {
-  auto* t = new Expression();
+  auto* t = global_arena->New<Expression>();
   t->line_num = line_num;
   t->value = FunctionTypeLiteral({.parameter = param, .return_type = ret});
   return t;
@@ -101,7 +102,7 @@ auto Expression::MakeFunctionTypeLiteral(int line_num, const Expression* param,
 
 auto Expression::MakeIdentifierExpression(int line_num, std::string var)
     -> const Expression* {
-  auto* v = new Expression();
+  auto* v = global_arena->New<Expression>();
   v->line_num = line_num;
   v->value = IdentifierExpression({.name = std::move(var)});
   return v;
@@ -111,21 +112,21 @@ auto Expression::MakeBindingExpression(int line_num,
                                        std::optional<std::string> var,
                                        const Expression* type)
     -> const Expression* {
-  auto* v = new Expression();
+  auto* v = global_arena->New<Expression>();
   v->line_num = line_num;
   v->value = BindingExpression({.name = std::move(var), .type = type});
   return v;
 }
 
 auto Expression::MakeIntLiteral(int line_num, int i) -> const Expression* {
-  auto* e = new Expression();
+  auto* e = global_arena->New<Expression>();
   e->line_num = line_num;
   e->value = IntLiteral({.value = i});
   return e;
 }
 
 auto Expression::MakeBoolLiteral(int line_num, bool b) -> const Expression* {
-  auto* e = new Expression();
+  auto* e = global_arena->New<Expression>();
   e->line_num = line_num;
   e->value = BoolLiteral({.value = b});
   return e;
@@ -134,7 +135,7 @@ auto Expression::MakeBoolLiteral(int line_num, bool b) -> const Expression* {
 auto Expression::MakePrimitiveOperatorExpression(
     int line_num, enum Operator op, std::vector<const Expression*> args)
     -> const Expression* {
-  auto* e = new Expression();
+  auto* e = global_arena->New<Expression>();
   e->line_num = line_num;
   e->value =
       PrimitiveOperatorExpression({.op = op, .arguments = std::move(args)});
@@ -144,7 +145,7 @@ auto Expression::MakePrimitiveOperatorExpression(
 auto Expression::MakeCallExpression(int line_num, const Expression* fun,
                                     const Expression* arg)
     -> const Expression* {
-  auto* e = new Expression();
+  auto* e = global_arena->New<Expression>();
   e->line_num = line_num;
   e->value = CallExpression({.function = fun, .argument = arg});
   return e;
@@ -153,7 +154,7 @@ auto Expression::MakeCallExpression(int line_num, const Expression* fun,
 auto Expression::MakeFieldAccessExpression(int line_num, const Expression* exp,
                                            std::string field)
     -> const Expression* {
-  auto* e = new Expression();
+  auto* e = global_arena->New<Expression>();
   e->line_num = line_num;
   e->value =
       FieldAccessExpression({.aggregate = exp, .field = std::move(field)});
@@ -163,7 +164,7 @@ auto Expression::MakeFieldAccessExpression(int line_num, const Expression* exp,
 auto Expression::MakeTupleLiteral(int line_num,
                                   std::vector<FieldInitializer> args)
     -> const Expression* {
-  auto* e = new Expression();
+  auto* e = global_arena->New<Expression>();
   e->line_num = line_num;
   int i = 0;
   bool seen_named_member = false;
@@ -185,7 +186,7 @@ auto Expression::MakeTupleLiteral(int line_num,
 
 auto Expression::MakeIndexExpression(int line_num, const Expression* exp,
                                      const Expression* i) -> const Expression* {
-  auto* e = new Expression();
+  auto* e = global_arena->New<Expression>();
   e->line_num = line_num;
   e->value = IndexExpression({.aggregate = exp, .offset = i});
   return e;

+ 9 - 0
executable_semantics/common/BUILD

@@ -4,6 +4,15 @@
 
 package(default_visibility = ["//executable_semantics:__subpackages__"])
 
+cc_library(
+    name = "arena",
+    srcs = ["arena.cpp"],
+    hdrs = ["arena.h"],
+    deps = [
+        "@llvm-project//llvm:Support",
+    ],
+)
+
 cc_library(
     name = "error",
     hdrs = ["error.h"],

+ 11 - 0
executable_semantics/common/arena.cpp

@@ -0,0 +1,11 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/common/arena.h"
+
+namespace Carbon {
+
+llvm::ManagedStatic<Arena> global_arena;
+
+}  // namespace Carbon

+ 57 - 0
executable_semantics/common/arena.h

@@ -0,0 +1,57 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_COMMON_ARENA_H_
+#define EXECUTABLE_SEMANTICS_COMMON_ARENA_H_
+
+#include <memory>
+#include <vector>
+
+#include "llvm/Support/ManagedStatic.h"
+
+namespace Carbon {
+
+class Arena {
+ public:
+  // Allocates an object in the arena, returning a pointer to it.
+  template <typename T, typename... Args>
+  auto New(Args&&... args) -> T* {
+    auto smart_ptr =
+        std::make_unique<ArenaEntryTyped<T>>(std::forward<Args>(args)...);
+    T* raw_ptr = smart_ptr->Instance();
+    arena.push_back(std::move(smart_ptr));
+    return raw_ptr;
+  }
+
+ private:
+  // Virtualizes arena entries so that a single vector can contain many types,
+  // avoiding templated statics.
+  class ArenaEntry {
+   public:
+    virtual ~ArenaEntry() = default;
+  };
+
+  // Templated destruction of a pointer.
+  template <typename T>
+  class ArenaEntryTyped : public ArenaEntry {
+   public:
+    template <typename... Args>
+    explicit ArenaEntryTyped(Args&... args)
+        : instance(std::forward<Args>(args)...) {}
+
+    auto Instance() -> T* { return &instance; }
+
+   private:
+    T instance;
+  };
+
+  // Manages allocations in an arena for destruction at shutdown.
+  std::vector<std::unique_ptr<ArenaEntry>> arena;
+};
+
+extern llvm::ManagedStatic<Arena> global_arena;
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_COMMON_ARENA_H_

+ 3 - 0
executable_semantics/main.cpp

@@ -10,8 +10,11 @@
 #include "executable_semantics/syntax/parse.h"
 #include "executable_semantics/syntax/syntax_helpers.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/InitLLVM.h"
 
 int main(int argc, char* argv[]) {
+  llvm::InitLLVM(argc, argv);
+
   // Printing to stderr should flush stdout. This is most noticeable when stderr
   // is piped to stdout.
   llvm::errs().tie(&llvm::outs());