2020-09-13 21:32:55 -04:00
|
|
|
#pragma once
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
/*!
|
|
|
|
* @file Env.h
|
|
|
|
* The Env tree. The stores all of the nested scopes/contexts during compilation and also
|
|
|
|
* manages the memory for stuff generated during compiling.
|
|
|
|
*/
|
2020-09-05 16:37:37 -04:00
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
#include <memory>
|
2022-06-22 23:37:46 -04:00
|
|
|
#include <string>
|
2020-09-06 12:45:31 -04:00
|
|
|
#include <vector>
|
2022-06-22 23:37:46 -04:00
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
#include "Label.h"
|
2022-06-22 23:37:46 -04:00
|
|
|
#include "StaticObject.h"
|
2020-09-06 12:45:31 -04:00
|
|
|
#include "Val.h"
|
|
|
|
|
2022-06-22 23:37:46 -04:00
|
|
|
#include "common/goos/Object.h"
|
|
|
|
#include "common/type_system/TypeSpec.h"
|
|
|
|
|
|
|
|
#include "goalc/regalloc/allocator_interface.h"
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
class FileEnv;
|
|
|
|
class BlockEnv;
|
2021-08-24 22:15:26 -04:00
|
|
|
class FunctionEnv;
|
|
|
|
class SymbolMacroEnv;
|
|
|
|
class MacroExpandEnv;
|
2020-09-06 16:58:25 -04:00
|
|
|
class IR;
|
2020-09-06 12:45:31 -04:00
|
|
|
|
2021-08-24 22:15:26 -04:00
|
|
|
enum class EnvKind { FILE_ENV, FUNCTION_ENV, SYMBOL_MACRO_ENV, MACRO_EXPAND_ENV, OTHER_ENV };
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
/*!
|
|
|
|
* Parent class for Env's
|
|
|
|
*/
|
|
|
|
class Env {
|
|
|
|
public:
|
2021-08-24 22:15:26 -04:00
|
|
|
explicit Env(EnvKind kind, Env* parent);
|
2020-09-06 12:45:31 -04:00
|
|
|
virtual std::string print() = 0;
|
2021-08-26 20:33:00 -04:00
|
|
|
void emit(const goos::Object& form, std::unique_ptr<IR> ir);
|
2021-08-24 22:15:26 -04:00
|
|
|
virtual RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class);
|
2020-09-12 13:11:42 -04:00
|
|
|
virtual void constrain_reg(IRegConstraint constraint); // todo, remove!
|
2020-09-13 17:34:02 -04:00
|
|
|
virtual RegVal* lexical_lookup(goos::Object sym);
|
2020-09-06 12:45:31 -04:00
|
|
|
virtual BlockEnv* find_block(const std::string& name);
|
2020-09-07 19:17:48 -04:00
|
|
|
virtual std::unordered_map<std::string, Label>& get_label_map();
|
2020-09-19 16:50:42 -04:00
|
|
|
RegVal* make_gpr(const TypeSpec& ts);
|
2020-12-30 15:33:51 -05:00
|
|
|
RegVal* make_fpr(const TypeSpec& ts);
|
2021-02-05 15:00:17 -05:00
|
|
|
RegVal* make_vfr(const TypeSpec& ts);
|
2020-09-06 12:45:31 -04:00
|
|
|
virtual ~Env() = default;
|
|
|
|
Env* parent() { return m_parent; }
|
|
|
|
|
2020-12-04 12:57:10 -05:00
|
|
|
template <typename IR_Type, typename... Args>
|
2021-08-26 20:33:00 -04:00
|
|
|
void emit_ir(const goos::Object& form, Args&&... args) {
|
|
|
|
emit(form, std::make_unique<IR_Type>(std::forward<Args>(args)...));
|
2020-12-04 12:57:10 -05:00
|
|
|
}
|
|
|
|
|
2021-08-24 22:15:26 -04:00
|
|
|
FileEnv* file_env() { return m_lowest_envs.file_env; }
|
|
|
|
FunctionEnv* function_env() { return m_lowest_envs.function_env; }
|
|
|
|
SymbolMacroEnv* symbol_macro_env() { return m_lowest_envs.symbol_macro_env; }
|
|
|
|
MacroExpandEnv* macro_expand_env() { return m_lowest_envs.macro_expand_env; }
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
protected:
|
2021-08-24 22:15:26 -04:00
|
|
|
EnvKind m_kind;
|
2020-09-06 12:45:31 -04:00
|
|
|
Env* m_parent = nullptr;
|
2021-08-24 22:15:26 -04:00
|
|
|
|
|
|
|
// cache of the lowest env of the given type, possibly including ourselves
|
|
|
|
struct {
|
|
|
|
FileEnv* file_env = nullptr;
|
|
|
|
FunctionEnv* function_env = nullptr;
|
|
|
|
SymbolMacroEnv* symbol_macro_env = nullptr;
|
|
|
|
MacroExpandEnv* macro_expand_env = nullptr;
|
|
|
|
} m_lowest_envs;
|
2020-09-06 12:45:31 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* The top-level Env. Holds FileEnvs for all files.
|
|
|
|
*/
|
|
|
|
class GlobalEnv : public Env {
|
|
|
|
public:
|
|
|
|
GlobalEnv();
|
|
|
|
std::string print() override;
|
2021-08-24 22:15:26 -04:00
|
|
|
RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class) override;
|
2020-09-06 12:45:31 -04:00
|
|
|
void constrain_reg(IRegConstraint constraint) override;
|
2020-09-13 17:34:02 -04:00
|
|
|
RegVal* lexical_lookup(goos::Object sym) override;
|
2020-09-06 12:45:31 -04:00
|
|
|
BlockEnv* find_block(const std::string& name) override;
|
|
|
|
~GlobalEnv() = default;
|
|
|
|
|
|
|
|
FileEnv* add_file(std::string name);
|
2022-11-29 19:22:22 -05:00
|
|
|
// TODO - consider refactoring to use a Trie
|
|
|
|
std::vector<std::string> list_files_with_prefix(const std::string& prefix);
|
2024-05-12 12:37:59 -04:00
|
|
|
std::vector<std::unique_ptr<FileEnv>>& get_files();
|
2020-09-06 12:45:31 -04:00
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<std::unique_ptr<FileEnv>> m_files;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* An Env for an entire file (or input to the REPL)
|
|
|
|
*/
|
|
|
|
class FileEnv : public Env {
|
|
|
|
public:
|
|
|
|
FileEnv(Env* parent, std::string name);
|
|
|
|
std::string print() override;
|
|
|
|
void add_function(std::unique_ptr<FunctionEnv> fe);
|
|
|
|
void add_top_level_function(std::unique_ptr<FunctionEnv> fe);
|
2020-09-12 13:11:42 -04:00
|
|
|
void add_static(std::unique_ptr<StaticObject> s);
|
2020-09-06 12:45:31 -04:00
|
|
|
void debug_print_tl();
|
2023-02-24 18:32:30 -05:00
|
|
|
const std::vector<std::unique_ptr<FunctionEnv>>& functions() { return m_functions; }
|
2020-09-12 13:11:42 -04:00
|
|
|
const std::vector<std::unique_ptr<StaticObject>>& statics() { return m_statics; }
|
2020-12-05 17:09:46 -05:00
|
|
|
std::string get_anon_function_name() {
|
|
|
|
return "anon-function-" + std::to_string(m_anon_func_counter++);
|
|
|
|
}
|
2020-09-13 10:40:21 -04:00
|
|
|
const FunctionEnv& top_level_function() {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(m_top_level_func);
|
2020-09-13 10:40:21 -04:00
|
|
|
return *m_top_level_func;
|
|
|
|
}
|
2020-11-13 22:33:57 -05:00
|
|
|
const std::string& name() { return m_name; }
|
2020-09-06 12:45:31 -04:00
|
|
|
|
2020-09-06 17:42:20 -04:00
|
|
|
bool is_empty();
|
2020-09-06 12:45:31 -04:00
|
|
|
~FileEnv() = default;
|
|
|
|
|
2021-02-03 11:07:47 -05:00
|
|
|
template <typename T, class... Args>
|
|
|
|
T* alloc_val(Args&&... args) {
|
|
|
|
std::unique_ptr<T> new_obj = std::make_unique<T>(std::forward<Args>(args)...);
|
|
|
|
m_vals.push_back(std::move(new_obj));
|
|
|
|
return (T*)m_vals.back().get();
|
|
|
|
}
|
|
|
|
|
2021-12-12 12:52:23 -05:00
|
|
|
int default_segment() const { return m_default_segment; }
|
2023-02-13 16:39:14 -05:00
|
|
|
void set_nondebug_file() { m_default_segment = MAIN_SEGMENT; }
|
2021-12-12 12:52:23 -05:00
|
|
|
void set_debug_file() { m_default_segment = DEBUG_SEGMENT; }
|
2023-02-13 16:39:14 -05:00
|
|
|
bool is_debug_file() const { return default_segment() == DEBUG_SEGMENT; }
|
2021-12-12 12:52:23 -05:00
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
void cleanup_after_codegen();
|
|
|
|
|
2024-05-12 12:37:59 -04:00
|
|
|
// TODO - privatize these eventually
|
|
|
|
std::unordered_set<std::string> m_required_files; // TODO - a string for now
|
|
|
|
std::unordered_set<std::string> m_missing_required_files; // TODO - a string for now
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
protected:
|
|
|
|
std::string m_name;
|
2023-02-24 18:32:30 -05:00
|
|
|
std::vector<std::unique_ptr<FunctionEnv>> m_functions;
|
2020-09-12 13:11:42 -04:00
|
|
|
std::vector<std::unique_ptr<StaticObject>> m_statics;
|
2020-12-05 17:09:46 -05:00
|
|
|
int m_anon_func_counter = 0;
|
2021-02-03 11:07:47 -05:00
|
|
|
std::vector<std::unique_ptr<Val>> m_vals;
|
2021-12-12 12:52:23 -05:00
|
|
|
int m_default_segment = MAIN_SEGMENT;
|
2020-09-06 12:45:31 -04:00
|
|
|
|
|
|
|
// statics
|
|
|
|
FunctionEnv* m_top_level_func = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* An Env which manages the scope for (declare ...) statements.
|
|
|
|
*/
|
|
|
|
class DeclareEnv : public Env {
|
|
|
|
public:
|
2021-08-24 22:15:26 -04:00
|
|
|
explicit DeclareEnv(EnvKind kind, Env* parent) : Env(kind, parent) {}
|
2020-09-06 12:45:31 -04:00
|
|
|
virtual std::string print() = 0;
|
|
|
|
~DeclareEnv() = default;
|
|
|
|
|
|
|
|
struct Settings {
|
|
|
|
bool is_set = false; // has the user set these with a (declare)?
|
|
|
|
bool inline_by_default = false; // if a function, inline when possible?
|
|
|
|
bool save_code = true; // if a function, should we save the code?
|
|
|
|
bool allow_inline = false; // should we allow the user to use this an inline function
|
2020-12-04 12:57:10 -05:00
|
|
|
bool print_asm = false; // should we print out the asm for this function?
|
2020-09-07 13:28:16 -04:00
|
|
|
} settings;
|
2020-09-06 12:45:31 -04:00
|
|
|
};
|
|
|
|
|
2020-09-07 19:17:48 -04:00
|
|
|
class IR_GotoLabel;
|
|
|
|
|
|
|
|
struct UnresolvedGoto {
|
2020-09-13 17:34:02 -04:00
|
|
|
IR_GotoLabel* ir = nullptr;
|
|
|
|
std::string label;
|
|
|
|
};
|
|
|
|
|
|
|
|
class IR_ConditionalBranch;
|
|
|
|
|
|
|
|
struct UnresolvedConditionalGoto {
|
|
|
|
IR_ConditionalBranch* ir = nullptr;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::string label;
|
|
|
|
};
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
class FunctionEnv : public DeclareEnv {
|
|
|
|
public:
|
2021-08-26 20:33:00 -04:00
|
|
|
FunctionEnv(Env* parent, std::string name, const goos::Reader* reader);
|
2020-09-06 12:45:31 -04:00
|
|
|
std::string print() override;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::unordered_map<std::string, Label>& get_label_map() override;
|
2020-09-06 16:58:25 -04:00
|
|
|
void set_segment(int seg) { segment = seg; }
|
2021-08-26 20:33:00 -04:00
|
|
|
void emit(const goos::Object& form, std::unique_ptr<IR> ir, Env* lowest_env);
|
2020-09-06 12:45:31 -04:00
|
|
|
void finish();
|
2021-08-24 22:15:26 -04:00
|
|
|
RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class) override;
|
2020-09-13 10:40:21 -04:00
|
|
|
const std::vector<std::unique_ptr<IR>>& code() const { return m_code; }
|
2021-08-26 20:33:00 -04:00
|
|
|
const std::vector<goos::Object>& code_source() const { return m_code_debug_source; }
|
2020-09-06 16:58:25 -04:00
|
|
|
int max_vars() const { return m_iregs.size(); }
|
|
|
|
const std::vector<IRegConstraint>& constraints() { return m_constraints; }
|
2020-09-12 13:11:42 -04:00
|
|
|
void constrain(const IRegConstraint& c) { m_constraints.push_back(c); }
|
2021-08-24 22:15:26 -04:00
|
|
|
void set_allocations(AllocationResult&& result) { m_regalloc_result = std::move(result); }
|
2020-09-13 17:34:02 -04:00
|
|
|
RegVal* lexical_lookup(goos::Object sym) override;
|
2020-09-06 16:58:25 -04:00
|
|
|
const AllocationResult& alloc_result() { return m_regalloc_result; }
|
|
|
|
bool needs_aligned_stack() const { return m_aligned_stack_required; }
|
2020-09-12 13:11:42 -04:00
|
|
|
void require_aligned_stack() { m_aligned_stack_required = true; }
|
2020-09-13 17:34:02 -04:00
|
|
|
Label* alloc_unnamed_label() {
|
|
|
|
m_unnamed_labels.emplace_back(std::make_unique<Label>());
|
|
|
|
return m_unnamed_labels.back().get();
|
|
|
|
}
|
2020-11-13 22:33:57 -05:00
|
|
|
const std::string& name() const { return m_name; }
|
|
|
|
|
2022-01-21 21:11:57 -05:00
|
|
|
struct StackSpace {
|
|
|
|
int start_slot;
|
|
|
|
int slot_count;
|
|
|
|
};
|
|
|
|
StackSpace allocate_aligned_stack_space(int size_bytes, int align_bytes);
|
2020-12-06 15:42:26 -05:00
|
|
|
StackVarAddrVal* allocate_aligned_stack_variable(const TypeSpec& ts,
|
|
|
|
int size_bytes,
|
|
|
|
int align_bytes);
|
2022-01-21 21:11:57 -05:00
|
|
|
StackVarAddrVal* allocate_stack_singleton(const TypeSpec& ts, int size_bytes, int align_bytes);
|
2020-11-22 12:22:19 -05:00
|
|
|
int stack_slots_used_for_stack_vars() const { return m_stack_var_slots_used; }
|
|
|
|
|
2021-12-12 12:52:23 -05:00
|
|
|
int segment_for_static_data() {
|
|
|
|
if (segment == TOP_LEVEL_SEGMENT) {
|
|
|
|
return file_env()->default_segment();
|
|
|
|
} else {
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-12 13:11:42 -04:00
|
|
|
int idx_in_file = -1;
|
2020-09-06 12:45:31 -04:00
|
|
|
|
|
|
|
template <typename T, class... Args>
|
|
|
|
T* alloc_val(Args&&... args) {
|
|
|
|
std::unique_ptr<T> new_obj = std::make_unique<T>(std::forward<Args>(args)...);
|
|
|
|
m_vals.push_back(std::move(new_obj));
|
|
|
|
return (T*)m_vals.back().get();
|
|
|
|
}
|
2020-09-07 19:17:48 -04:00
|
|
|
|
|
|
|
template <typename T, class... Args>
|
|
|
|
T* alloc_env(Args&&... args) {
|
|
|
|
std::unique_ptr<T> new_obj = std::make_unique<T>(std::forward<Args>(args)...);
|
|
|
|
m_envs.push_back(std::move(new_obj));
|
|
|
|
return (T*)m_envs.back().get();
|
|
|
|
}
|
|
|
|
|
2021-06-04 13:43:19 -04:00
|
|
|
const std::vector<std::unique_ptr<RegVal>>& reg_vals() const { return m_iregs; }
|
|
|
|
|
2021-07-22 20:14:08 -04:00
|
|
|
RegVal* push_reg_val(std::unique_ptr<RegVal> in);
|
|
|
|
|
2020-09-06 16:58:25 -04:00
|
|
|
int segment = -1;
|
2020-09-06 17:42:20 -04:00
|
|
|
std::string method_of_type_name = "#f";
|
2023-09-30 11:06:09 -04:00
|
|
|
TypeSpec method_function_type;
|
|
|
|
std::optional<int> method_id;
|
2020-09-13 10:40:21 -04:00
|
|
|
bool is_asm_func = false;
|
2020-12-06 15:42:26 -05:00
|
|
|
bool asm_func_saved_regs = false;
|
2020-12-04 12:57:10 -05:00
|
|
|
TypeSpec asm_func_return_type;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::vector<UnresolvedGoto> unresolved_gotos;
|
2020-09-13 17:34:02 -04:00
|
|
|
std::vector<UnresolvedConditionalGoto> unresolved_cond_gotos;
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
std::unordered_map<goos::InternedSymbolPtr, RegVal*, goos::InternedSymbolPtr::hash> params;
|
2020-09-07 19:17:48 -04:00
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
protected:
|
2020-09-07 19:17:48 -04:00
|
|
|
void resolve_gotos();
|
2020-09-06 12:45:31 -04:00
|
|
|
std::string m_name;
|
|
|
|
std::vector<std::unique_ptr<IR>> m_code;
|
2021-08-26 20:33:00 -04:00
|
|
|
std::vector<goos::Object> m_code_debug_source;
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
std::vector<std::unique_ptr<RegVal>> m_iregs;
|
|
|
|
std::vector<std::unique_ptr<Val>> m_vals;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::vector<std::unique_ptr<Env>> m_envs;
|
2020-09-06 12:45:31 -04:00
|
|
|
std::vector<IRegConstraint> m_constraints;
|
2021-08-26 20:33:00 -04:00
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
AllocationResult m_regalloc_result;
|
|
|
|
|
|
|
|
bool m_aligned_stack_required = false;
|
2020-11-22 12:22:19 -05:00
|
|
|
int m_stack_var_slots_used = 0;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::unordered_map<std::string, Label> m_labels;
|
2020-09-13 17:34:02 -04:00
|
|
|
std::vector<std::unique_ptr<Label>> m_unnamed_labels;
|
2022-01-21 21:11:57 -05:00
|
|
|
std::unordered_map<std::string, StackSpace> m_stack_singleton_slots;
|
|
|
|
|
2021-08-26 20:33:00 -04:00
|
|
|
const goos::Reader* m_reader = nullptr;
|
2020-09-06 12:45:31 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
class BlockEnv : public Env {
|
|
|
|
public:
|
|
|
|
BlockEnv(Env* parent, std::string name);
|
|
|
|
std::string print() override;
|
|
|
|
BlockEnv* find_block(const std::string& name) override;
|
2020-09-06 16:58:25 -04:00
|
|
|
|
2020-09-07 19:17:48 -04:00
|
|
|
std::string name;
|
|
|
|
Label end_label = nullptr;
|
|
|
|
RegVal* return_value = nullptr;
|
|
|
|
std::vector<TypeSpec> return_types;
|
2020-09-06 12:45:31 -04:00
|
|
|
};
|
|
|
|
|
2020-09-12 13:11:42 -04:00
|
|
|
class LexicalEnv : public DeclareEnv {
|
2020-09-06 12:45:31 -04:00
|
|
|
public:
|
2021-08-24 22:15:26 -04:00
|
|
|
explicit LexicalEnv(Env* parent) : DeclareEnv(EnvKind::OTHER_ENV, parent) {}
|
2020-09-13 17:34:02 -04:00
|
|
|
RegVal* lexical_lookup(goos::Object sym) override;
|
2020-09-06 12:45:31 -04:00
|
|
|
std::string print() override;
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
std::unordered_map<goos::InternedSymbolPtr, RegVal*, goos::InternedSymbolPtr::hash> vars;
|
2020-09-06 12:45:31 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
class LabelEnv : public Env {
|
|
|
|
public:
|
2021-08-24 22:15:26 -04:00
|
|
|
explicit LabelEnv(Env* parent) : Env(EnvKind::OTHER_ENV, parent) {}
|
2020-09-12 13:11:42 -04:00
|
|
|
std::string print() override { return "labelenv"; }
|
2020-09-07 19:17:48 -04:00
|
|
|
std::unordered_map<std::string, Label>& get_label_map() override;
|
2020-11-22 20:10:33 -05:00
|
|
|
BlockEnv* find_block(const std::string& name) override;
|
2020-09-07 19:17:48 -04:00
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
protected:
|
|
|
|
std::unordered_map<std::string, Label> m_labels;
|
|
|
|
};
|
|
|
|
|
2021-08-24 22:15:26 -04:00
|
|
|
class SymbolMacroEnv : public Env {
|
2020-09-12 13:11:42 -04:00
|
|
|
public:
|
2021-08-24 22:15:26 -04:00
|
|
|
explicit SymbolMacroEnv(Env* parent) : Env(EnvKind::SYMBOL_MACRO_ENV, parent) {}
|
|
|
|
// key is goos symbols.
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash> macros;
|
2021-08-24 22:15:26 -04:00
|
|
|
std::string print() override { return "symbol-macro-env"; }
|
2020-09-12 13:11:42 -04:00
|
|
|
};
|
2020-09-06 12:45:31 -04:00
|
|
|
|
2021-08-24 22:15:26 -04:00
|
|
|
class MacroExpandEnv : public Env {
|
2020-09-12 13:11:42 -04:00
|
|
|
public:
|
2021-08-24 22:15:26 -04:00
|
|
|
MacroExpandEnv(Env* parent,
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
const goos::InternedSymbolPtr macro_name,
|
2021-08-24 22:15:26 -04:00
|
|
|
const goos::Object& macro_body,
|
|
|
|
const goos::Object& macro_use)
|
|
|
|
: Env(EnvKind::MACRO_EXPAND_ENV, parent),
|
|
|
|
m_macro_name(macro_name),
|
|
|
|
m_macro_body(macro_body),
|
|
|
|
m_macro_use_location(macro_use) {
|
|
|
|
MacroExpandEnv* parent_macro = nullptr;
|
|
|
|
if (parent) {
|
|
|
|
parent_macro = parent->macro_expand_env();
|
|
|
|
}
|
|
|
|
if (parent_macro) {
|
|
|
|
m_root_form = parent_macro->m_root_form;
|
|
|
|
} else {
|
|
|
|
m_root_form = m_macro_use_location;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string print() override { return "macro-env"; }
|
|
|
|
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
const goos::InternedSymbolPtr name() const { return m_macro_name; }
|
2021-08-24 22:15:26 -04:00
|
|
|
const goos::Object& macro_body() const { return m_macro_body; }
|
|
|
|
const goos::Object& macro_use_location() const { return m_macro_use_location; }
|
|
|
|
const goos::Object& root_form() const { return m_root_form; }
|
|
|
|
|
|
|
|
private:
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
const goos::InternedSymbolPtr m_macro_name = {nullptr};
|
2021-08-24 22:15:26 -04:00
|
|
|
goos::Object m_macro_body;
|
|
|
|
goos::Object m_macro_use_location;
|
|
|
|
goos::Object m_root_form;
|
2020-09-12 13:11:42 -04:00
|
|
|
};
|
2020-09-05 16:37:37 -04:00
|
|
|
|
2020-09-06 16:58:25 -04:00
|
|
|
template <typename T>
|
2021-08-24 22:15:26 -04:00
|
|
|
T* get_parent_env_of_type_slow(Env* in) {
|
2020-09-06 16:58:25 -04:00
|
|
|
for (;;) {
|
2020-09-06 12:45:31 -04:00
|
|
|
auto attempt = dynamic_cast<T*>(in);
|
2020-09-06 16:58:25 -04:00
|
|
|
if (attempt)
|
|
|
|
return attempt;
|
|
|
|
if (dynamic_cast<GlobalEnv*>(in)) {
|
2020-09-06 12:45:31 -04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
in = in->parent();
|
|
|
|
}
|
|
|
|
}
|
2021-08-24 22:15:26 -04:00
|
|
|
|
|
|
|
inline Env::Env(EnvKind kind, Env* parent) : m_kind(kind), m_parent(parent) {
|
|
|
|
if (m_kind == EnvKind::FILE_ENV) {
|
|
|
|
m_lowest_envs.file_env = static_cast<FileEnv*>(this);
|
|
|
|
} else {
|
|
|
|
m_lowest_envs.file_env = m_parent ? m_parent->m_lowest_envs.file_env : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_kind == EnvKind::FUNCTION_ENV) {
|
|
|
|
m_lowest_envs.function_env = static_cast<FunctionEnv*>(this);
|
|
|
|
} else {
|
|
|
|
m_lowest_envs.function_env = m_parent ? m_parent->m_lowest_envs.function_env : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_kind == EnvKind::SYMBOL_MACRO_ENV) {
|
|
|
|
m_lowest_envs.symbol_macro_env = static_cast<SymbolMacroEnv*>(this);
|
|
|
|
} else {
|
|
|
|
m_lowest_envs.symbol_macro_env = m_parent ? m_parent->m_lowest_envs.symbol_macro_env : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_kind == EnvKind::MACRO_EXPAND_ENV) {
|
|
|
|
m_lowest_envs.macro_expand_env = static_cast<MacroExpandEnv*>(this);
|
|
|
|
} else {
|
|
|
|
m_lowest_envs.macro_expand_env = m_parent ? m_parent->m_lowest_envs.macro_expand_env : nullptr;
|
|
|
|
}
|
|
|
|
}
|