// Copyright 2006-2008 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // The infrastructure used for (localized) message reporting in V8. // // Note: there's a big unresolved issue about ownership of the data // structures used by this framework. #ifndef V8_MESSAGES_H_ #define V8_MESSAGES_H_ #include <memory> #include "src/handles.h" #include "src/message-template.h" namespace v8 { namespace internal { namespace wasm { class WasmCode; } // Forward declarations. class AbstractCode; class FrameArray; class JSMessageObject; class LookupIterator; class SharedFunctionInfo; class SourceInfo; class WasmInstanceObject; class MessageLocation { public: MessageLocation(Handle<Script> script, int start_pos, int end_pos); MessageLocation(Handle<Script> script, int start_pos, int end_pos, Handle<SharedFunctionInfo> shared); MessageLocation(); Handle<Script> script() const { return script_; } int start_pos() const { return start_pos_; } int end_pos() const { return end_pos_; } Handle<SharedFunctionInfo> shared() const { return shared_; } private: Handle<Script> script_; int start_pos_; int end_pos_; Handle<SharedFunctionInfo> shared_; }; class StackFrameBase { public: virtual ~StackFrameBase() = default; virtual Handle<Object> GetReceiver() const = 0; virtual Handle<Object> GetFunction() const = 0; virtual Handle<Object> GetFileName() = 0; virtual Handle<Object> GetFunctionName() = 0; virtual Handle<Object> GetScriptNameOrSourceUrl() = 0; virtual Handle<Object> GetMethodName() = 0; virtual Handle<Object> GetTypeName() = 0; virtual Handle<Object> GetEvalOrigin(); // Returns the script ID if one is attached, -1 otherwise. int GetScriptId() const; virtual int GetPosition() const = 0; // Return 1-based line number, including line offset. virtual int GetLineNumber() = 0; // Return 1-based column number, including column offset if first line. virtual int GetColumnNumber() = 0; // Returns index for Promise.all() async frames, or -1 for other frames. virtual int GetPromiseIndex() const = 0; virtual bool IsNative() = 0; virtual bool IsToplevel() = 0; virtual bool IsEval(); virtual bool IsAsync() const = 0; virtual bool IsPromiseAll() const = 0; virtual bool IsConstructor() = 0; virtual bool IsStrict() const = 0; virtual MaybeHandle<String> ToString() = 0; // Used to signal that the requested field is unknown. static const int kNone = -1; protected: StackFrameBase() = default; explicit StackFrameBase(Isolate* isolate) : isolate_(isolate) {} Isolate* isolate_; private: virtual bool HasScript() const = 0; virtual Handle<Script> GetScript() const = 0; }; class JSStackFrame : public StackFrameBase { public: JSStackFrame(Isolate* isolate, Handle<Object> receiver, Handle<JSFunction> function, Handle<AbstractCode> code, int offset); ~JSStackFrame() override = default; Handle<Object> GetReceiver() const override { return receiver_; } Handle<Object> GetFunction() const override; Handle<Object> GetFileName() override; Handle<Object> GetFunctionName() override; Handle<Object> GetScriptNameOrSourceUrl() override; Handle<Object> GetMethodName() override; Handle<Object> GetTypeName() override; int GetPosition() const override; int GetLineNumber() override; int GetColumnNumber() override; int GetPromiseIndex() const override; bool IsNative() override; bool IsToplevel() override; bool IsAsync() const override { return is_async_; } bool IsPromiseAll() const override { return is_promise_all_; } bool IsConstructor() override { return is_constructor_; } bool IsStrict() const override { return is_strict_; } MaybeHandle<String> ToString() override; private: JSStackFrame() = default; void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix); bool HasScript() const override; Handle<Script> GetScript() const override; Handle<Object> receiver_; Handle<JSFunction> function_; Handle<AbstractCode> code_; int offset_; bool is_async_ : 1; bool is_constructor_ : 1; bool is_promise_all_ : 1; bool is_strict_ : 1; friend class FrameArrayIterator; }; class WasmStackFrame : public StackFrameBase { public: ~WasmStackFrame() override = default; Handle<Object> GetReceiver() const override; Handle<Object> GetFunction() const override; Handle<Object> GetFileName() override { return Null(); } Handle<Object> GetFunctionName() override; Handle<Object> GetScriptNameOrSourceUrl() override { return Null(); } Handle<Object> GetMethodName() override { return Null(); } Handle<Object> GetTypeName() override { return Null(); } int GetPosition() const override; int GetLineNumber() override { return wasm_func_index_; } int GetColumnNumber() override { return kNone; } int GetPromiseIndex() const override { return kNone; } bool IsNative() override { return false; } bool IsToplevel() override { return false; } bool IsAsync() const override { return false; } bool IsPromiseAll() const override { return false; } bool IsConstructor() override { return false; } bool IsStrict() const override { return false; } bool IsInterpreted() const { return code_ == nullptr; } MaybeHandle<String> ToString() override; protected: Handle<Object> Null() const; bool HasScript() const override; Handle<Script> GetScript() const override; Handle<WasmInstanceObject> wasm_instance_; uint32_t wasm_func_index_; wasm::WasmCode* code_; // null for interpreted frames. int offset_; private: WasmStackFrame() = default; void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix); friend class FrameArrayIterator; friend class AsmJsWasmStackFrame; }; class AsmJsWasmStackFrame : public WasmStackFrame { public: ~AsmJsWasmStackFrame() override = default; Handle<Object> GetReceiver() const override; Handle<Object> GetFunction() const override; Handle<Object> GetFileName() override; Handle<Object> GetScriptNameOrSourceUrl() override; int GetPosition() const override; int GetLineNumber() override; int GetColumnNumber() override; MaybeHandle<String> ToString() override; private: friend class FrameArrayIterator; AsmJsWasmStackFrame() = default; void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix); bool is_at_number_conversion_; }; class FrameArrayIterator { public: FrameArrayIterator(Isolate* isolate, Handle<FrameArray> array, int frame_ix = 0); StackFrameBase* Frame(); bool HasFrame() const; void Advance(); private: Isolate* isolate_; Handle<FrameArray> array_; int frame_ix_; WasmStackFrame wasm_frame_; AsmJsWasmStackFrame asm_wasm_frame_; JSStackFrame js_frame_; }; // Determines how stack trace collection skips frames. enum FrameSkipMode { // Unconditionally skips the first frame. Used e.g. when the Error constructor // is called, in which case the first frame is always a BUILTIN_EXIT frame. SKIP_FIRST, // Skip all frames until a specified caller function is seen. SKIP_UNTIL_SEEN, SKIP_NONE, }; class ErrorUtils : public AllStatic { public: static MaybeHandle<Object> Construct( Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target, Handle<Object> message, FrameSkipMode mode, Handle<Object> caller, bool suppress_detailed_trace); static MaybeHandle<String> ToString(Isolate* isolate, Handle<Object> recv); static MaybeHandle<Object> MakeGenericError( Isolate* isolate, Handle<JSFunction> constructor, MessageTemplate index, Handle<Object> arg0, Handle<Object> arg1, Handle<Object> arg2, FrameSkipMode mode); // Formats a textual stack trace from the given structured stack trace. // Note that this can call arbitrary JS code through Error.prepareStackTrace. static MaybeHandle<Object> FormatStackTrace(Isolate* isolate, Handle<JSObject> error, Handle<Object> stack_trace); }; class MessageFormatter { public: static const char* TemplateString(MessageTemplate index); static MaybeHandle<String> Format(Isolate* isolate, MessageTemplate index, Handle<String> arg0, Handle<String> arg1, Handle<String> arg2); static Handle<String> Format(Isolate* isolate, MessageTemplate index, Handle<Object> arg); }; // A message handler is a convenience interface for accessing the list // of message listeners registered in an environment class MessageHandler { public: // Returns a message object for the API to use. static Handle<JSMessageObject> MakeMessageObject( Isolate* isolate, MessageTemplate type, const MessageLocation* location, Handle<Object> argument, Handle<FixedArray> stack_frames); // Report a formatted message (needs JS allocation). static void ReportMessage(Isolate* isolate, const MessageLocation* loc, Handle<JSMessageObject> message); static void DefaultMessageReport(Isolate* isolate, const MessageLocation* loc, Handle<Object> message_obj); static Handle<String> GetMessage(Isolate* isolate, Handle<Object> data); static std::unique_ptr<char[]> GetLocalizedMessage(Isolate* isolate, Handle<Object> data); private: static void ReportMessageNoExceptions(Isolate* isolate, const MessageLocation* loc, Handle<Object> message_obj, v8::Local<v8::Value> api_exception_obj); }; } // namespace internal } // namespace v8 #endif // V8_MESSAGES_H_