jak-project/lsp/state/workspace.h
water111 395c98db19
[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

129 lines
5 KiB
C++

#pragma once
#include <optional>
#include <string>
#include <unordered_map>
#include "common/util/FileUtil.h"
#include "decompiler/util/DecompilerTypeSystem.h"
#include "goalc/compiler/Compiler.h"
#include "goalc/compiler/docs/DocTypes.h"
#include "lsp/protocol/common_types.h"
#include "lsp/protocol/document_diagnostics.h"
#include "lsp/protocol/document_symbols.h"
#include "lsp/state/lsp_requester.h"
class WorkspaceOGFile {
public:
WorkspaceOGFile(){};
WorkspaceOGFile(const std::string& content, const GameVersion& game_version);
// TODO - make private
int32_t version;
// TODO - keep an AST of the file instead
std::string m_content;
std::vector<std::string> m_lines;
std::vector<LSPSpec::DocumentSymbol> m_symbols;
std::vector<LSPSpec::Diagnostic> m_diagnostics;
GameVersion m_game_version;
std::optional<std::string> get_symbol_at_position(const LSPSpec::Position position) const;
};
class WorkspaceIRFile {
public:
WorkspaceIRFile(){};
WorkspaceIRFile(const std::string& content);
// TODO - make private
int32_t version;
std::vector<std::string> m_lines;
std::vector<LSPSpec::DocumentSymbol> m_symbols;
std::vector<LSPSpec::Diagnostic> m_diagnostics;
GameVersion m_game_version;
LSPSpec::DocumentUri m_all_types_uri = "";
fs::path m_all_types_file_path;
std::optional<std::string> get_mips_instruction_at_position(
const LSPSpec::Position position) const;
std::optional<std::string> get_symbol_at_position(const LSPSpec::Position position) const;
private:
void find_all_types_path(const std::string& line);
void find_function_symbol(const uint32_t line_num_zero_based, const std::string& line);
/// Make any relevant diagnostics on the IR line.
/// It's assumed each line in an IR can have atmost one diagnostic, and they are contained to just
/// that line!
void identify_diagnostics(const uint32_t line_num_zero_based, const std::string& line);
};
class WorkspaceAllTypesFile {
public:
WorkspaceAllTypesFile()
: m_dts(std::make_unique<decompiler::DecompilerTypeSystem>(GameVersion::Jak1)){};
WorkspaceAllTypesFile(const LSPSpec::DocumentUri& uri,
const GameVersion version,
const fs::path file_path)
: m_game_version(version),
m_uri(uri),
m_dts(std::make_unique<decompiler::DecompilerTypeSystem>(m_game_version)),
m_file_path(file_path){};
GameVersion m_game_version;
LSPSpec::DocumentUri m_uri;
std::unique_ptr<decompiler::DecompilerTypeSystem> m_dts;
fs::path m_file_path;
void parse_type_system();
void update_type_system();
};
class Workspace {
public:
enum class FileType { OpenGOAL, OpenGOALIR, Unsupported };
Workspace();
virtual ~Workspace();
bool is_initialized();
void set_initialized(bool new_value);
// Even though when a file is initially opened it has the language id
// many subsequent requests only provide a uri to the file
// and it's a lot faster to check the end of a string, then multiple tracked file maps
FileType determine_filetype_from_languageid(const std::string& language_id);
FileType determine_filetype_from_uri(const LSPSpec::DocumentUri& file_uri);
void start_tracking_file(const LSPSpec::DocumentUri& file_uri,
const std::string& language_id,
const std::string& content);
void update_tracked_file(const LSPSpec::DocumentUri& file_uri, const std::string& content);
void stop_tracking_file(const LSPSpec::DocumentUri& file_uri);
std::optional<WorkspaceOGFile> get_tracked_og_file(const LSPSpec::URI& file_uri);
std::optional<WorkspaceIRFile> get_tracked_ir_file(const LSPSpec::URI& file_uri);
std::optional<DefinitionMetadata> get_definition_info_from_all_types(
const std::string& symbol_name,
const LSPSpec::DocumentUri& all_types_uri);
std::optional<SymbolInfo> get_global_symbol_info(const WorkspaceOGFile& file,
const std::string& symbol_name);
std::optional<TypeSpec> get_symbol_typespec(const WorkspaceOGFile& file,
const std::string& symbol_name);
std::optional<Docs::DefinitionLocation> get_symbol_def_location(const WorkspaceOGFile& file,
const SymbolInfo& symbol_info);
private:
LSPRequester m_requester;
bool m_initialized = false;
std::unordered_map<LSPSpec::DocumentUri, WorkspaceOGFile> m_tracked_og_files = {};
std::unordered_map<LSPSpec::DocumentUri, WorkspaceIRFile> m_tracked_ir_files = {};
std::unordered_map<LSPSpec::DocumentUri, std::unique_ptr<WorkspaceAllTypesFile>>
m_tracked_all_types_files = {};
// TODO:
// OpenGOAL is still incredibly tightly coupled to the jak projects as a language
//
// In the future, information like GameVersion should just be within the project file
// and then we can track projects instead of games
//
// Until that decoupling happens, things like this will remain fairly clunky.
std::unordered_map<GameVersion, std::unique_ptr<Compiler>> m_compiler_instances;
};