text: // 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_EXECUTION_MESSAGES_H_
  #define V8_EXECUTION_MESSAGES_H_
  
  #include <memory>
  
  #include "src/base/optional.h"
  #include "src/common/message-template.h"
  #include "src/handles/handles.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 V8_EXPORT_PRIVATE MessageLocation {
   public:
    // Constructors for when source positions are already known.
    // TODO(delphick): Collapse to a single constructor with a default parameter
    // when we stop using the GCC that requires this separation.
    MessageLocation(Handle<Script> script, int start_pos, int end_pos);
    MessageLocation(Handle<Script> script, int start_pos, int end_pos,
                    Handle<SharedFunctionInfo> shared);
    // Constructor for when source positions were not collected but which can be
    // reconstructed from the SharedFuncitonInfo and bytecode offset.
    MessageLocation(Handle<Script> script, Handle<SharedFunctionInfo> shared,
                    int bytecode_offset);
    MessageLocation();
  
    Handle<Script> script() const { return script_; }
    int start_pos() const { return start_pos_; }
    int end_pos() const { return end_pos_; }
    int bytecode_offset() const { return bytecode_offset_; }
    Handle<SharedFunctionInfo> shared() const { return shared_; }
  
   private:
    Handle<Script> script_;
    int start_pos_;
    int end_pos_;
    int bytecode_offset_;
    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();
    virtual Handle<Object> GetWasmModuleName();
    virtual Handle<Object> GetWasmInstance();
  
    // 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;
    // Return 0-based Wasm function index. Returns -1 for non-Wasm frames.
    virtual int GetWasmFunctionIndex();
  
    // 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;
  
    // 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_; }
  
   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_;
    mutable base::Optional<int> cached_position_;
  
    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(); }
    Handle<Object> GetWasmModuleName() override;
    Handle<Object> GetWasmInstance() override;
  
    int GetPosition() const override;
    int GetLineNumber() override { return 0; }
    int GetColumnNumber() override;
    int GetWasmFunctionIndex() override { return wasm_func_index_; }
  
    int GetPromiseIndex() const override { return GetPosition(); }
  
    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; }
  
   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:
    int GetModuleOffset() const;
  
    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;
  
   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:
    // |kNone| is useful when you don't need the stack information at all, for
    // example when creating a deserialized error.
    enum class StackTraceCollection { kDetailed, kSimple, kNone };
    static MaybeHandle<JSObject> Construct(
        Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
        Handle<Object> message, FrameSkipMode mode, Handle<Object> caller,
        StackTraceCollection stack_trace_collection);
  
    static MaybeHandle<String> ToString(Isolate* isolate, Handle<Object> recv);
  
    static Handle<JSObject> 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);
  
    static Handle<Object> NewIteratorError(Isolate* isolate,
                                           Handle<Object> source);
    static Handle<Object> NewCalledNonCallableError(Isolate* isolate,
                                                    Handle<Object> source);
    static Handle<Object> NewConstructedNonConstructable(Isolate* isolate,
                                                         Handle<Object> source);
    static Object ThrowSpreadArgIsNullOrUndefinedError(Isolate* isolate,
                                                       Handle<Object> object);
    static Object ThrowLoadFromNullOrUndefined(Isolate* isolate,
                                               Handle<Object> object);
    static Object ThrowLoadFromNullOrUndefined(Isolate* isolate,
                                               Handle<Object> object,
                                               MaybeHandle<Object> key);
  };
  
  class MessageFormatter {
   public:
    static const char* TemplateString(MessageTemplate index);
  
    V8_EXPORT_PRIVATE 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.
    V8_EXPORT_PRIVATE 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).
    V8_EXPORT_PRIVATE 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_EXECUTION_MESSAGES_H_
  