#pragma once #include "isolate/generic/error.h" #include "isolate/generic/handle_cast.h" #include "external_copy/external_copy.h" #include "external_copy/string.h" #include #include #include namespace ivm { /** * Parses script origin information from an option object and returns a non-v8 holder for the * information which can then be converted to a ScriptOrigin, perhaps in a different isolate from * the one it was read in. */ class ScriptOriginHolder { public: explicit ScriptOriginHolder(v8::MaybeLocal maybe_options, bool is_module = false); explicit operator v8::ScriptOrigin() const; private: std::string filename = ""; int32_t column_offset = 0; int32_t line_offset = 0; bool is_module; }; /** * Parser and holder for all common v8 compilation information like code string, cached data, script * origin, etc. */ class CodeCompilerHolder { public: CodeCompilerHolder( v8::Local code_handle, v8::MaybeLocal maybe_options, bool is_module = false); auto DidSupplyCachedData() const { return supplied_cached_data; } auto GetSource() -> std::unique_ptr; auto GetSourceString() -> v8::Local; void ResetSource(); void SaveCachedData(v8::ScriptCompiler::CachedData* cached_data); void SetCachedDataRejected(bool rejected) { cached_data_rejected = rejected; } auto ShouldProduceCachedData() const { return produce_cached_data && (!supplied_cached_data || cached_data_rejected); } void WriteCompileResults(v8::Local handle); private: auto GetCachedData() const -> std::unique_ptr; ScriptOriginHolder script_origin_holder; ExternalCopyString code_string; std::shared_ptr cached_data_out; std::shared_ptr cached_data_in; mutable v8::Local code_string_handle; size_t cached_data_in_size = 0; bool cached_data_rejected = false; bool produce_cached_data = false; bool supplied_cached_data = false; }; /** * Run a lambda which invokes the v8 compiler and annotate the exception with source / line number * if it throws. */ template auto RunWithAnnotatedErrors(Function fn) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::TryCatch try_catch{isolate}; try { return fn(); } catch (const detail::RuntimeErrorWithMessage& cc_error) { throw std::logic_error("Invalid error thrown by RunWithAnnotatedErrors"); } catch (const RuntimeError& cc_error) { try { assert(try_catch.HasCaught()); v8::Local context = isolate->GetCurrentContext(); v8::Local error = try_catch.Exception(); v8::Local message = try_catch.Message(); assert(error->IsObject()); int linenum = Unmaybe(message->GetLineNumber(context)); int start_column = Unmaybe(message->GetStartColumn(context)); auto name = message->GetScriptResourceName(); std::string decorator = (name->IsString() ? HandleCast(message->GetScriptResourceName()) : "") + ":" + std::to_string(linenum) + ":" + std::to_string(start_column + 1); auto message_key = HandleCast>("message"); std::string message_str = HandleCast(Unmaybe(error.As()->Get(context, message_key))); Unmaybe(error.As()->Set(context, message_key, HandleCast>(message_str + " [" + decorator + "]"))); isolate->ThrowException(error); throw RuntimeError(); } catch (const RuntimeError& cc_error) { try_catch.ReThrow(); throw RuntimeError(); } } } } // namespace ivm