Bug 1484385 - Move various error-report-related structures and types into js/public/ErrorReport.h to minimize dependencies (and ultimately to make jsfriendapi.h not depend on jsapi.h). r=jandem

--HG--
extra : rebase_source : a288defdb87af97cae31181db9239b18935ad3d2
This commit is contained in:
Jeff Walden 2018-08-20 07:45:44 -07:00
parent cd10720691
commit f95e60bba1
4 changed files with 297 additions and 249 deletions

294
js/public/ErrorReport.h Normal file
View File

@ -0,0 +1,294 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Error-reporting types and structures.
*
* Despite these types and structures existing in js/public, significant parts
* of their heritage date back to distant SpiderMonkey past, and they are not
* all universally well-thought-out as ideal, intended-to-be-permanent API.
* We may eventually replace this with something more consistent with
* ECMAScript the language and less consistent with '90s-era JSAPI inventions,
* but it's doubtful this will happen any time soon.
*/
#ifndef js_ErrorReport_h
#define js_ErrorReport_h
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include <iterator> // std::input_iterator_tag, std::iterator
#include <stddef.h> // size_t
#include <stdint.h> // int16_t, uint16_t
#include <string.h> // strlen
#include "jstypes.h" // JS_PUBLIC_API
#include "js/AllocPolicy.h" // js::SystemAllocPolicy
#include "js/CharacterEncoding.h" // JS::ConstUTF8CharsZ
#include "js/UniquePtr.h" // js::UniquePtr
#include "js/Vector.h" // js::Vector
struct JSContext;
class JSString;
/**
* Possible exception types. These types are part of a JSErrorFormatString
* structure. They define which error to throw in case of a runtime error.
*
* JSEXN_WARN is used for warnings in js.msg files (for instance because we
* don't want to prepend 'Error:' to warning messages). This value can go away
* if we ever decide to use an entirely separate mechanism for warnings.
*/
enum JSExnType
{
JSEXN_ERR,
JSEXN_FIRST = JSEXN_ERR,
JSEXN_INTERNALERR,
JSEXN_EVALERR,
JSEXN_RANGEERR,
JSEXN_REFERENCEERR,
JSEXN_SYNTAXERR,
JSEXN_TYPEERR,
JSEXN_URIERR,
JSEXN_DEBUGGEEWOULDRUN,
JSEXN_WASMCOMPILEERROR,
JSEXN_WASMLINKERROR,
JSEXN_WASMRUNTIMEERROR,
JSEXN_ERROR_LIMIT,
JSEXN_WARN = JSEXN_ERROR_LIMIT,
JSEXN_NOTE,
JSEXN_LIMIT
};
struct JSErrorFormatString
{
/** The error message name in ASCII. */
const char* name;
/** The error format string in ASCII. */
const char* format;
/** The number of arguments to expand in the formatted error message. */
uint16_t argCount;
/** One of the JSExnType constants above. */
int16_t exnType;
};
using JSErrorCallback =
const JSErrorFormatString* (*)(void* userRef, const unsigned errorNumber);
/**
* Base class that implements parts shared by JSErrorReport and
* JSErrorNotes::Note.
*/
class JSErrorBase
{
private:
// The (default) error message.
// If ownsMessage_ is true, the it is freed in destructor.
JS::ConstUTF8CharsZ message_;
public:
// Source file name, URL, etc., or null.
const char* filename;
// Source line number.
unsigned lineno;
// Zero-based column index in line.
unsigned column;
// the error number, e.g. see js.msg.
unsigned errorNumber;
private:
bool ownsMessage_ : 1;
public:
JSErrorBase()
: filename(nullptr), lineno(0), column(0),
errorNumber(0),
ownsMessage_(false)
{}
~JSErrorBase() {
freeMessage();
}
public:
const JS::ConstUTF8CharsZ message() const {
return message_;
}
void initOwnedMessage(const char* messageArg) {
initBorrowedMessage(messageArg);
ownsMessage_ = true;
}
void initBorrowedMessage(const char* messageArg) {
MOZ_ASSERT(!message_);
message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg));
}
JSString* newMessageString(JSContext* cx);
private:
void freeMessage();
};
/**
* Notes associated with JSErrorReport.
*/
class JSErrorNotes
{
public:
class Note final : public JSErrorBase
{};
private:
// Stores pointers to each note.
js::Vector<js::UniquePtr<Note>, 1, js::SystemAllocPolicy> notes_;
public:
JSErrorNotes();
~JSErrorNotes();
// Add an note to the given position.
bool addNoteASCII(JSContext* cx,
const char* filename, unsigned lineno, unsigned column,
JSErrorCallback errorCallback, void* userRef,
const unsigned errorNumber, ...);
bool addNoteLatin1(JSContext* cx,
const char* filename, unsigned lineno, unsigned column,
JSErrorCallback errorCallback, void* userRef,
const unsigned errorNumber, ...);
bool addNoteUTF8(JSContext* cx,
const char* filename, unsigned lineno, unsigned column,
JSErrorCallback errorCallback, void* userRef,
const unsigned errorNumber, ...);
JS_PUBLIC_API(size_t) length();
// Create a deep copy of notes.
js::UniquePtr<JSErrorNotes> copy(JSContext* cx);
class iterator final
: public std::iterator<std::input_iterator_tag, js::UniquePtr<Note>>
{
private:
js::UniquePtr<Note>* note_;
public:
explicit iterator(js::UniquePtr<Note>* note = nullptr) : note_(note)
{}
bool operator==(iterator other) const {
return note_ == other.note_;
}
bool operator!=(iterator other) const {
return !(*this == other);
}
iterator& operator++() {
note_++;
return *this;
}
reference operator*() {
return *note_;
}
};
JS_PUBLIC_API(iterator) begin();
JS_PUBLIC_API(iterator) end();
};
/**
* Describes a single error or warning that occurs in the execution of script.
*/
class JSErrorReport : public JSErrorBase
{
private:
// Offending source line without final '\n'.
// If ownsLinebuf_ is true, the buffer is freed in destructor.
const char16_t* linebuf_;
// Number of chars in linebuf_. Does not include trailing '\0'.
size_t linebufLength_;
// The 0-based offset of error token in linebuf_.
size_t tokenOffset_;
public:
// Associated notes, or nullptr if there's no note.
js::UniquePtr<JSErrorNotes> notes;
// error/warning, etc.
unsigned flags;
// One of the JSExnType constants.
int16_t exnType;
// See the comment in TransitiveCompileOptions.
bool isMuted : 1;
private:
bool ownsLinebuf_ : 1;
public:
JSErrorReport()
: linebuf_(nullptr), linebufLength_(0), tokenOffset_(0),
notes(nullptr),
flags(0), exnType(0), isMuted(false),
ownsLinebuf_(false)
{}
~JSErrorReport() {
freeLinebuf();
}
public:
const char16_t* linebuf() const {
return linebuf_;
}
size_t linebufLength() const {
return linebufLength_;
}
size_t tokenOffset() const {
return tokenOffset_;
}
void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg,
size_t tokenOffsetArg) {
initBorrowedLinebuf(linebufArg, linebufLengthArg, tokenOffsetArg);
ownsLinebuf_ = true;
}
void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg,
size_t tokenOffsetArg);
private:
void freeLinebuf();
};
/*
* JSErrorReport flag values. These may be freely composed.
*/
#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */
#define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */
#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */
#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */
#define JSREPORT_USER_1 0x8 /* user-defined flag */
/*
* If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception
* has been thrown for this runtime error, and the host should ignore it.
* Exception-aware hosts should also check for JS_IsExceptionPending if
* JS_ExecuteScript returns failure, and signal or propagate the exception, as
* appropriate.
*/
#define JSREPORT_IS_WARNING(flags) (((flags) & JSREPORT_WARNING) != 0)
#define JSREPORT_IS_EXCEPTION(flags) (((flags) & JSREPORT_EXCEPTION) != 0)
#define JSREPORT_IS_STRICT(flags) (((flags) & JSREPORT_STRICT) != 0)
#endif /* js_ErrorReport_h */

View File

@ -17,7 +17,6 @@
#include "mozilla/RefPtr.h"
#include "mozilla/Variant.h"
#include <iterator>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
@ -29,6 +28,7 @@
#include "js/CallArgs.h"
#include "js/CharacterEncoding.h"
#include "js/Class.h"
#include "js/ErrorReport.h"
#include "js/GCVector.h"
#include "js/HashTable.h"
#include "js/Id.h"
@ -222,51 +222,6 @@ typedef void
JS::PromiseRejectionHandlingState state,
void* data);
/**
* Possible exception types. These types are part of a JSErrorFormatString
* structure. They define which error to throw in case of a runtime error.
*
* JSEXN_WARN is used for warnings in js.msg files (for instance because we
* don't want to prepend 'Error:' to warning messages). This value can go away
* if we ever decide to use an entirely separate mechanism for warnings.
*/
typedef enum JSExnType {
JSEXN_ERR,
JSEXN_FIRST = JSEXN_ERR,
JSEXN_INTERNALERR,
JSEXN_EVALERR,
JSEXN_RANGEERR,
JSEXN_REFERENCEERR,
JSEXN_SYNTAXERR,
JSEXN_TYPEERR,
JSEXN_URIERR,
JSEXN_DEBUGGEEWOULDRUN,
JSEXN_WASMCOMPILEERROR,
JSEXN_WASMLINKERROR,
JSEXN_WASMRUNTIMEERROR,
JSEXN_ERROR_LIMIT,
JSEXN_WARN = JSEXN_ERROR_LIMIT,
JSEXN_NOTE,
JSEXN_LIMIT
} JSExnType;
struct JSErrorFormatString {
/** The error message name in ASCII. */
const char* name;
/** The error format string in ASCII. */
const char* format;
/** The number of arguments to expand in the formatted error message. */
uint16_t argCount;
/** One of the JSExnType constants above. */
int16_t exnType;
};
typedef const JSErrorFormatString*
(* JSErrorCallback)(void* userRef, const unsigned errorNumber);
typedef bool
(* JSLocaleToUpperCase)(JSContext* cx, JS::HandleString src, JS::MutableHandleValue rval);
@ -5118,208 +5073,6 @@ JS_ReportOutOfMemory(JSContext* cx);
extern JS_PUBLIC_API(void)
JS_ReportAllocationOverflow(JSContext* cx);
/**
* Base class that implements parts shared by JSErrorReport and
* JSErrorNotes::Note.
*/
class JSErrorBase
{
// The (default) error message.
// If ownsMessage_ is true, the it is freed in destructor.
JS::ConstUTF8CharsZ message_;
public:
JSErrorBase()
: filename(nullptr), lineno(0), column(0),
errorNumber(0),
ownsMessage_(false)
{}
~JSErrorBase() {
freeMessage();
}
// Source file name, URL, etc., or null.
const char* filename;
// Source line number.
unsigned lineno;
// Zero-based column index in line.
unsigned column;
// the error number, e.g. see js.msg.
unsigned errorNumber;
private:
bool ownsMessage_ : 1;
public:
const JS::ConstUTF8CharsZ message() const {
return message_;
}
void initOwnedMessage(const char* messageArg) {
initBorrowedMessage(messageArg);
ownsMessage_ = true;
}
void initBorrowedMessage(const char* messageArg) {
MOZ_ASSERT(!message_);
message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg));
}
JSString* newMessageString(JSContext* cx);
private:
void freeMessage();
};
/**
* Notes associated with JSErrorReport.
*/
class JSErrorNotes
{
public:
class Note : public JSErrorBase
{};
private:
// Stores pointers to each note.
js::Vector<js::UniquePtr<Note>, 1, js::SystemAllocPolicy> notes_;
public:
JSErrorNotes();
~JSErrorNotes();
// Add an note to the given position.
bool addNoteASCII(JSContext* cx,
const char* filename, unsigned lineno, unsigned column,
JSErrorCallback errorCallback, void* userRef,
const unsigned errorNumber, ...);
bool addNoteLatin1(JSContext* cx,
const char* filename, unsigned lineno, unsigned column,
JSErrorCallback errorCallback, void* userRef,
const unsigned errorNumber, ...);
bool addNoteUTF8(JSContext* cx,
const char* filename, unsigned lineno, unsigned column,
JSErrorCallback errorCallback, void* userRef,
const unsigned errorNumber, ...);
JS_PUBLIC_API(size_t) length();
// Create a deep copy of notes.
js::UniquePtr<JSErrorNotes> copy(JSContext* cx);
class iterator : public std::iterator<std::input_iterator_tag, js::UniquePtr<Note>>
{
js::UniquePtr<Note>* note_;
public:
explicit iterator(js::UniquePtr<Note>* note = nullptr) : note_(note)
{}
bool operator==(iterator other) const {
return note_ == other.note_;
}
bool operator!=(iterator other) const {
return !(*this == other);
}
iterator& operator++() {
note_++;
return *this;
}
reference operator*() {
return *note_;
}
};
JS_PUBLIC_API(iterator) begin();
JS_PUBLIC_API(iterator) end();
};
/**
* Describes a single error or warning that occurs in the execution of script.
*/
class JSErrorReport : public JSErrorBase
{
// Offending source line without final '\n'.
// If ownsLinebuf_ is true, the buffer is freed in destructor.
const char16_t* linebuf_;
// Number of chars in linebuf_. Does not include trailing '\0'.
size_t linebufLength_;
// The 0-based offset of error token in linebuf_.
size_t tokenOffset_;
public:
JSErrorReport()
: linebuf_(nullptr), linebufLength_(0), tokenOffset_(0),
notes(nullptr),
flags(0), exnType(0), isMuted(false),
ownsLinebuf_(false)
{}
~JSErrorReport() {
freeLinebuf();
}
// Associated notes, or nullptr if there's no note.
js::UniquePtr<JSErrorNotes> notes;
// error/warning, etc.
unsigned flags;
// One of the JSExnType constants.
int16_t exnType;
// See the comment in TransitiveCompileOptions.
bool isMuted : 1;
private:
bool ownsLinebuf_ : 1;
public:
const char16_t* linebuf() const {
return linebuf_;
}
size_t linebufLength() const {
return linebufLength_;
}
size_t tokenOffset() const {
return tokenOffset_;
}
void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg,
size_t tokenOffsetArg) {
initBorrowedLinebuf(linebufArg, linebufLengthArg, tokenOffsetArg);
ownsLinebuf_ = true;
}
void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg,
size_t tokenOffsetArg);
private:
void freeLinebuf();
};
/*
* JSErrorReport flag values. These may be freely composed.
*/
#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */
#define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */
#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */
#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */
#define JSREPORT_USER_1 0x8 /* user-defined flag */
/*
* If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception
* has been thrown for this runtime error, and the host should ignore it.
* Exception-aware hosts should also check for JS_IsExceptionPending if
* JS_ExecuteScript returns failure, and signal or propagate the exception, as
* appropriate.
*/
#define JSREPORT_IS_WARNING(flags) (((flags) & JSREPORT_WARNING) != 0)
#define JSREPORT_IS_EXCEPTION(flags) (((flags) & JSREPORT_EXCEPTION) != 0)
#define JSREPORT_IS_STRICT(flags) (((flags) & JSREPORT_STRICT) != 0)
namespace JS {
using WarningReporter = void (*)(JSContext* cx, JSErrorReport* report);

View File

@ -19,6 +19,7 @@
#include "js/CallArgs.h"
#include "js/CallNonGenericMethod.h"
#include "js/Class.h"
#include "js/ErrorReport.h"
#include "js/HeapAPI.h"
#include "js/StableStringChars.h"
#include "js/TypeDecls.h"
@ -40,7 +41,6 @@
struct JSErrorFormatString;
struct JSJitInfo;
class JSErrorReport;
namespace JS {
template <class T>

View File

@ -131,6 +131,7 @@ EXPORTS.js += [
'../public/Conversions.h',
'../public/Date.h',
'../public/Debug.h',
'../public/ErrorReport.h',
'../public/GCAnnotations.h',
'../public/GCAPI.h',
'../public/GCHashTable.h',