1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // The infrastructure used for (localized) message reporting in V8. 6 // 7 // Note: there's a big unresolved issue about ownership of the data 8 // structures used by this framework. 9 10 #ifndef V8_EXECUTION_MESSAGES_H_ 11 #define V8_EXECUTION_MESSAGES_H_ 12 13 #include <memory> 14 15 #include "src/base/optional.h" 16 #include "src/common/message-template.h" 17 #include "src/handles/handles.h" 18 19 namespace v8 { 20 namespace internal { 21 namespace wasm { 22 class WasmCode; 23 } // namespace wasm 24 25 // Forward declarations. 26 class AbstractCode; 27 class FrameArray; 28 class JSMessageObject; 29 class LookupIterator; 30 class PrimitiveHeapObject; 31 class SharedFunctionInfo; 32 class SourceInfo; 33 class WasmInstanceObject; 34 35 class V8_EXPORT_PRIVATE MessageLocation { 36 public: 37 // Constructors for when source positions are already known. 38 // TODO(delphick): Collapse to a single constructor with a default parameter 39 // when we stop using the GCC that requires this separation. 40 MessageLocation(Handle<Script> script, int start_pos, int end_pos); 41 MessageLocation(Handle<Script> script, int start_pos, int end_pos, 42 Handle<SharedFunctionInfo> shared); 43 // Constructor for when source positions were not collected but which can be 44 // reconstructed from the SharedFuncitonInfo and bytecode offset. 45 MessageLocation(Handle<Script> script, Handle<SharedFunctionInfo> shared, 46 int bytecode_offset); 47 MessageLocation(); 48 script()49 Handle<Script> script() const { return script_; } start_pos()50 int start_pos() const { return start_pos_; } end_pos()51 int end_pos() const { return end_pos_; } bytecode_offset()52 int bytecode_offset() const { return bytecode_offset_; } shared()53 Handle<SharedFunctionInfo> shared() const { return shared_; } 54 55 private: 56 Handle<Script> script_; 57 int start_pos_; 58 int end_pos_; 59 int bytecode_offset_; 60 Handle<SharedFunctionInfo> shared_; 61 }; 62 63 class StackFrameBase { 64 public: 65 virtual ~StackFrameBase() = default; 66 67 virtual Handle<Object> GetReceiver() const = 0; 68 virtual Handle<Object> GetFunction() const = 0; 69 70 virtual Handle<Object> GetFileName() = 0; 71 virtual Handle<PrimitiveHeapObject> GetFunctionName() = 0; 72 virtual Handle<Object> GetScriptNameOrSourceUrl() = 0; 73 virtual Handle<PrimitiveHeapObject> GetMethodName() = 0; 74 virtual Handle<PrimitiveHeapObject> GetTypeName() = 0; 75 virtual Handle<PrimitiveHeapObject> GetEvalOrigin(); 76 virtual Handle<PrimitiveHeapObject> GetWasmModuleName(); 77 virtual Handle<HeapObject> GetWasmInstance(); 78 79 // Returns the script ID if one is attached, -1 otherwise. 80 int GetScriptId() const; 81 82 virtual int GetPosition() const = 0; 83 // Return 1-based line number, including line offset. 84 virtual int GetLineNumber() = 0; 85 // Return 1-based column number, including column offset if first line. 86 virtual int GetColumnNumber() = 0; 87 // Return 0-based Wasm function index. Returns -1 for non-Wasm frames. 88 virtual int GetWasmFunctionIndex(); 89 90 // Returns the index of the rejected promise in the Promise combinator input, 91 // or -1 if this frame is not a Promise combinator frame. 92 virtual int GetPromiseIndex() const = 0; 93 94 virtual bool IsNative() = 0; 95 virtual bool IsToplevel() = 0; 96 virtual bool IsEval(); 97 virtual bool IsAsync() const = 0; 98 virtual bool IsPromiseAll() const = 0; 99 virtual bool IsPromiseAny() const = 0; 100 virtual bool IsConstructor() = 0; 101 virtual bool IsStrict() const = 0; 102 103 // Used to signal that the requested field is unknown. 104 static const int kNone = -1; 105 106 protected: 107 StackFrameBase() = default; StackFrameBase(Isolate * isolate)108 explicit StackFrameBase(Isolate* isolate) : isolate_(isolate) {} 109 Isolate* isolate_; 110 111 private: 112 virtual bool HasScript() const = 0; 113 virtual Handle<Script> GetScript() const = 0; 114 }; 115 116 class JSStackFrame : public StackFrameBase { 117 public: 118 JSStackFrame(Isolate* isolate, Handle<Object> receiver, 119 Handle<JSFunction> function, Handle<AbstractCode> code, 120 int offset); 121 ~JSStackFrame() override = default; 122 GetReceiver()123 Handle<Object> GetReceiver() const override { return receiver_; } 124 Handle<Object> GetFunction() const override; 125 126 Handle<Object> GetFileName() override; 127 Handle<PrimitiveHeapObject> GetFunctionName() override; 128 Handle<Object> GetScriptNameOrSourceUrl() override; 129 Handle<PrimitiveHeapObject> GetMethodName() override; 130 Handle<PrimitiveHeapObject> GetTypeName() override; 131 132 int GetPosition() const override; 133 int GetLineNumber() override; 134 int GetColumnNumber() override; 135 136 int GetPromiseIndex() const override; 137 138 bool IsNative() override; 139 bool IsToplevel() override; IsAsync()140 bool IsAsync() const override { return is_async_; } IsPromiseAll()141 bool IsPromiseAll() const override { return is_promise_all_; } IsPromiseAny()142 bool IsPromiseAny() const override { return is_promise_any_; } IsConstructor()143 bool IsConstructor() override { return is_constructor_; } IsStrict()144 bool IsStrict() const override { return is_strict_; } 145 146 private: 147 JSStackFrame() = default; 148 void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix); 149 150 bool HasScript() const override; 151 Handle<Script> GetScript() const override; 152 153 Handle<Object> receiver_; 154 Handle<JSFunction> function_; 155 Handle<AbstractCode> code_; 156 int offset_; 157 mutable base::Optional<int> cached_position_; 158 159 bool is_async_ : 1; 160 bool is_constructor_ : 1; 161 bool is_promise_all_ : 1; 162 bool is_promise_any_ : 1; 163 bool is_strict_ : 1; 164 165 friend class FrameArrayIterator; 166 }; 167 168 class WasmStackFrame : public StackFrameBase { 169 public: 170 ~WasmStackFrame() override = default; 171 172 Handle<Object> GetReceiver() const override; 173 Handle<Object> GetFunction() const override; 174 175 Handle<Object> GetFileName() override; 176 Handle<PrimitiveHeapObject> GetFunctionName() override; 177 Handle<Object> GetScriptNameOrSourceUrl() override; GetMethodName()178 Handle<PrimitiveHeapObject> GetMethodName() override { return Null(); } GetTypeName()179 Handle<PrimitiveHeapObject> GetTypeName() override { return Null(); } 180 Handle<PrimitiveHeapObject> GetWasmModuleName() override; 181 Handle<HeapObject> GetWasmInstance() override; 182 183 int GetPosition() const override; GetLineNumber()184 int GetLineNumber() override { return 0; } 185 int GetColumnNumber() override; GetWasmFunctionIndex()186 int GetWasmFunctionIndex() override { return wasm_func_index_; } 187 GetPromiseIndex()188 int GetPromiseIndex() const override { return GetPosition(); } 189 IsNative()190 bool IsNative() override { return false; } IsToplevel()191 bool IsToplevel() override { return false; } IsAsync()192 bool IsAsync() const override { return false; } IsPromiseAll()193 bool IsPromiseAll() const override { return false; } IsPromiseAny()194 bool IsPromiseAny() const override { return false; } IsConstructor()195 bool IsConstructor() override { return false; } IsStrict()196 bool IsStrict() const override { return false; } IsInterpreted()197 bool IsInterpreted() const { return code_ == nullptr; } 198 199 protected: 200 Handle<PrimitiveHeapObject> Null() const; 201 202 bool HasScript() const override; 203 Handle<Script> GetScript() const override; 204 205 Handle<WasmInstanceObject> wasm_instance_; 206 uint32_t wasm_func_index_; 207 wasm::WasmCode* code_; // null for interpreted frames. 208 int offset_; 209 210 private: 211 int GetModuleOffset() const; 212 213 WasmStackFrame() = default; 214 void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix); 215 216 friend class FrameArrayIterator; 217 friend class AsmJsWasmStackFrame; 218 }; 219 220 class AsmJsWasmStackFrame : public WasmStackFrame { 221 public: 222 ~AsmJsWasmStackFrame() override = default; 223 224 Handle<Object> GetReceiver() const override; 225 Handle<Object> GetFunction() const override; 226 227 Handle<Object> GetFileName() override; 228 Handle<Object> GetScriptNameOrSourceUrl() override; 229 230 int GetPosition() const override; 231 int GetLineNumber() override; 232 int GetColumnNumber() override; 233 234 private: 235 friend class FrameArrayIterator; 236 AsmJsWasmStackFrame() = default; 237 void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix); 238 239 bool is_at_number_conversion_; 240 }; 241 242 class FrameArrayIterator { 243 public: 244 FrameArrayIterator(Isolate* isolate, Handle<FrameArray> array, 245 int frame_ix = 0); 246 247 StackFrameBase* Frame(); 248 249 bool HasFrame() const; 250 void Advance(); 251 252 private: 253 Isolate* isolate_; 254 255 Handle<FrameArray> array_; 256 int frame_ix_; 257 258 WasmStackFrame wasm_frame_; 259 AsmJsWasmStackFrame asm_wasm_frame_; 260 JSStackFrame js_frame_; 261 }; 262 263 // Determines how stack trace collection skips frames. 264 enum FrameSkipMode { 265 // Unconditionally skips the first frame. Used e.g. when the Error constructor 266 // is called, in which case the first frame is always a BUILTIN_EXIT frame. 267 SKIP_FIRST, 268 // Skip all frames until a specified caller function is seen. 269 SKIP_UNTIL_SEEN, 270 SKIP_NONE, 271 }; 272 273 class ErrorUtils : public AllStatic { 274 public: 275 // |kNone| is useful when you don't need the stack information at all, for 276 // example when creating a deserialized error. 277 enum class StackTraceCollection { kDetailed, kSimple, kNone }; 278 static MaybeHandle<JSObject> Construct(Isolate* isolate, 279 Handle<JSFunction> target, 280 Handle<Object> new_target, 281 Handle<Object> message); 282 static MaybeHandle<JSObject> Construct( 283 Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target, 284 Handle<Object> message, FrameSkipMode mode, Handle<Object> caller, 285 StackTraceCollection stack_trace_collection); 286 287 static MaybeHandle<String> ToString(Isolate* isolate, Handle<Object> recv); 288 289 static Handle<JSObject> MakeGenericError( 290 Isolate* isolate, Handle<JSFunction> constructor, MessageTemplate index, 291 Handle<Object> arg0, Handle<Object> arg1, Handle<Object> arg2, 292 FrameSkipMode mode); 293 294 // Formats a textual stack trace from the given structured stack trace. 295 // Note that this can call arbitrary JS code through Error.prepareStackTrace. 296 static MaybeHandle<Object> FormatStackTrace(Isolate* isolate, 297 Handle<JSObject> error, 298 Handle<Object> stack_trace); 299 300 static Handle<JSObject> NewIteratorError(Isolate* isolate, 301 Handle<Object> source); 302 static Handle<JSObject> NewCalledNonCallableError(Isolate* isolate, 303 Handle<Object> source); 304 static Handle<JSObject> NewConstructedNonConstructable(Isolate* isolate, 305 Handle<Object> source); 306 // Returns the Exception sentinel. 307 static Object ThrowSpreadArgError(Isolate* isolate, MessageTemplate id, 308 Handle<Object> object); 309 // Returns the Exception sentinel. 310 static Object ThrowLoadFromNullOrUndefined(Isolate* isolate, 311 Handle<Object> object, 312 MaybeHandle<Object> key); 313 }; 314 315 class MessageFormatter { 316 public: 317 V8_EXPORT_PRIVATE static const char* TemplateString(MessageTemplate index); 318 319 V8_EXPORT_PRIVATE static MaybeHandle<String> Format(Isolate* isolate, 320 MessageTemplate index, 321 Handle<String> arg0, 322 Handle<String> arg1, 323 Handle<String> arg2); 324 325 static Handle<String> Format(Isolate* isolate, MessageTemplate index, 326 Handle<Object> arg0, 327 Handle<Object> arg1 = Handle<Object>(), 328 Handle<Object> arg2 = Handle<Object>()); 329 }; 330 331 // A message handler is a convenience interface for accessing the list 332 // of message listeners registered in an environment 333 class MessageHandler { 334 public: 335 // Returns a message object for the API to use. 336 V8_EXPORT_PRIVATE static Handle<JSMessageObject> MakeMessageObject( 337 Isolate* isolate, MessageTemplate type, const MessageLocation* location, 338 Handle<Object> argument, Handle<FixedArray> stack_frames); 339 340 // Report a formatted message (needs JS allocation). 341 V8_EXPORT_PRIVATE static void ReportMessage(Isolate* isolate, 342 const MessageLocation* loc, 343 Handle<JSMessageObject> message); 344 345 static void DefaultMessageReport(Isolate* isolate, const MessageLocation* loc, 346 Handle<Object> message_obj); 347 static Handle<String> GetMessage(Isolate* isolate, Handle<Object> data); 348 static std::unique_ptr<char[]> GetLocalizedMessage(Isolate* isolate, 349 Handle<Object> data); 350 351 private: 352 static void ReportMessageNoExceptions(Isolate* isolate, 353 const MessageLocation* loc, 354 Handle<Object> message_obj, 355 v8::Local<v8::Value> api_exception_obj); 356 }; 357 358 } // namespace internal 359 } // namespace v8 360 361 #endif // V8_EXECUTION_MESSAGES_H_ 362