blob: 4aab728f7caf97b8325ea661f979fb4f56b287ad [file] [log] [blame]
// 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;
} // namespace wasm
// Forward declarations.
class AbstractCode;
class FrameArray;
class JSMessageObject;
class LookupIterator;
class PrimitiveHeapObject;
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<PrimitiveHeapObject> GetFunctionName() = 0;
virtual Handle<Object> GetScriptNameOrSourceUrl() = 0;
virtual Handle<PrimitiveHeapObject> GetMethodName() = 0;
virtual Handle<PrimitiveHeapObject> GetTypeName() = 0;
virtual Handle<PrimitiveHeapObject> GetEvalOrigin();
virtual Handle<PrimitiveHeapObject> GetWasmModuleName();
virtual Handle<HeapObject> 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 the index of the rejected promise in the Promise combinator input,
// or -1 if this frame is not a Promise combinator frame.
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 IsPromiseAny() 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<PrimitiveHeapObject> GetFunctionName() override;
Handle<Object> GetScriptNameOrSourceUrl() override;
Handle<PrimitiveHeapObject> GetMethodName() override;
Handle<PrimitiveHeapObject> 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 IsPromiseAny() const override { return is_promise_any_; }
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_promise_any_ : 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;
Handle<PrimitiveHeapObject> GetFunctionName() override;
Handle<Object> GetScriptNameOrSourceUrl() override;
Handle<PrimitiveHeapObject> GetMethodName() override { return Null(); }
Handle<PrimitiveHeapObject> GetTypeName() override { return Null(); }
Handle<PrimitiveHeapObject> GetWasmModuleName() override;
Handle<HeapObject> 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 IsPromiseAny() const override { return false; }
bool IsConstructor() override { return false; }
bool IsStrict() const override { return false; }
bool IsInterpreted() const { return code_ == nullptr; }
protected:
Handle<PrimitiveHeapObject> 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);
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<JSObject> NewIteratorError(Isolate* isolate,
Handle<Object> source);
static Handle<JSObject> NewCalledNonCallableError(Isolate* isolate,
Handle<Object> source);
static Handle<JSObject> NewConstructedNonConstructable(Isolate* isolate,
Handle<Object> source);
// Returns the Exception sentinel.
static Object ThrowSpreadArgError(Isolate* isolate, MessageTemplate id,
Handle<Object> object);
// Returns the Exception sentinel.
static Object ThrowLoadFromNullOrUndefined(Isolate* isolate,
Handle<Object> object,
MaybeHandle<Object> key);
};
class MessageFormatter {
public:
V8_EXPORT_PRIVATE 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> arg0,
Handle<Object> arg1 = Handle<Object>(),
Handle<Object> arg2 = Handle<Object>());
};
// 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_