Make RUNTIME_ASSERT have more useful output in debug mode
Runtime asserts are were previously a bit annoying to debug, due to the lack of a useful error message, even in debug mode. This patch prints out some more information in debug mode for runtime assert failures while preserving their exception-throwing semantics. While we're at it, it requires a semicolon after RUNTIME_ASSERT macro invocations. ``` $ rlwrap out/Debug/d8 --allow-natives-syntax V8 version 5.1.0 (candidate) d8> %ArrayBufferNeuter(1) # # Runtime error in ../../src/runtime/runtime-typedarray.cc, line 52 # # args[0]->IsJSArrayBuffer() ==== C stack trace =============================== 1: 0xf70ab5 2: 0xadeebf 3: 0xadedd4 4: 0x2ef17630693b (d8):1: illegal access %ArrayBufferNeuter(1) ^ d8> ``` Also give the other 'illegal access' case (a special SyntaxError type) a more descriptive error message for its sole usage. R=adamk Review URL: https://codereview.chromium.org/1748183002 Cr-Commit-Position: refs/heads/master@{#34401}
This commit is contained in:
parent
503d589340
commit
78d845308f
@ -115,3 +115,14 @@ extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
|
|||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
v8::base::OS::Abort();
|
v8::base::OS::Abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void V8_RuntimeError(const char* file, int line,
|
||||||
|
const char* message) {
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
v8::base::OS::PrintError("\n\n#\n# Runtime error in %s, line %d\n# ", file,
|
||||||
|
line);
|
||||||
|
v8::base::OS::PrintError("\n# %s\n", message);
|
||||||
|
v8::base::DumpBacktrace();
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
extern "C" V8_NORETURN void V8_Fatal(const char* file, int line,
|
extern "C" V8_NORETURN void V8_Fatal(const char* file, int line,
|
||||||
const char* format, ...);
|
const char* format, ...);
|
||||||
|
|
||||||
|
extern "C" void V8_RuntimeError(const char* file, int line,
|
||||||
|
const char* message);
|
||||||
|
|
||||||
// The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during
|
// The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during
|
||||||
// development, but they should not be relied on in the final product.
|
// development, but they should not be relied on in the final product.
|
||||||
|
@ -379,7 +379,6 @@ class CallSite {
|
|||||||
"% loop variable declaration may not have an initializer.") \
|
"% loop variable declaration may not have an initializer.") \
|
||||||
T(ForInOfLoopMultiBindings, \
|
T(ForInOfLoopMultiBindings, \
|
||||||
"Invalid left-hand side in % loop: Must have a single binding.") \
|
"Invalid left-hand side in % loop: Must have a single binding.") \
|
||||||
T(IllegalAccess, "Illegal access") \
|
|
||||||
T(IllegalBreak, "Illegal break statement") \
|
T(IllegalBreak, "Illegal break statement") \
|
||||||
T(IllegalContinue, "Illegal continue statement") \
|
T(IllegalContinue, "Illegal continue statement") \
|
||||||
T(IllegalLanguageModeDirective, \
|
T(IllegalLanguageModeDirective, \
|
||||||
@ -421,6 +420,7 @@ class CallSite {
|
|||||||
"Setter function argument must not be a rest parameter") \
|
"Setter function argument must not be a rest parameter") \
|
||||||
T(ParamDupe, "Duplicate parameter name not allowed in this context") \
|
T(ParamDupe, "Duplicate parameter name not allowed in this context") \
|
||||||
T(ParenthesisInArgString, "Function arg string contains parenthesis") \
|
T(ParenthesisInArgString, "Function arg string contains parenthesis") \
|
||||||
|
T(RuntimeWrongNumArgs, "Runtime function given wrong number of arguments") \
|
||||||
T(SingleFunctionLiteral, "Single function literal required") \
|
T(SingleFunctionLiteral, "Single function literal required") \
|
||||||
T(SloppyLexical, \
|
T(SloppyLexical, \
|
||||||
"Block-scoped declarations (let, const, function, class) not yet " \
|
"Block-scoped declarations (let, const, function, class) not yet " \
|
||||||
|
@ -4993,7 +4993,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
|
|||||||
|
|
||||||
// Check that the expected number of arguments are being passed.
|
// Check that the expected number of arguments are being passed.
|
||||||
if (function->nargs != -1 && function->nargs != args->length()) {
|
if (function->nargs != -1 && function->nargs != args->length()) {
|
||||||
ReportMessage(MessageTemplate::kIllegalAccess);
|
ReportMessage(MessageTemplate::kRuntimeWrongNumArgs);
|
||||||
*ok = false;
|
*ok = false;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,6 @@ RUNTIME_FUNCTION(Runtime_FormatMessageString) {
|
|||||||
return *result;
|
return *result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define CALLSITE_GET(NAME, RETURN) \
|
#define CALLSITE_GET(NAME, RETURN) \
|
||||||
RUNTIME_FUNCTION(Runtime_CallSite##NAME##RT) { \
|
RUNTIME_FUNCTION(Runtime_CallSite##NAME##RT) { \
|
||||||
HandleScope scope(isolate); \
|
HandleScope scope(isolate); \
|
||||||
@ -325,7 +324,7 @@ RUNTIME_FUNCTION(Runtime_FormatMessageString) {
|
|||||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, call_site_obj, 0); \
|
CONVERT_ARG_HANDLE_CHECKED(JSObject, call_site_obj, 0); \
|
||||||
Handle<String> result; \
|
Handle<String> result; \
|
||||||
CallSite call_site(isolate, call_site_obj); \
|
CallSite call_site(isolate, call_site_obj); \
|
||||||
RUNTIME_ASSERT(call_site.IsValid()) \
|
RUNTIME_ASSERT(call_site.IsValid()); \
|
||||||
return RETURN(call_site.NAME(), isolate); \
|
return RETURN(call_site.NAME(), isolate); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
|
|||||||
DCHECK(args.length() == 2);
|
DCHECK(args.length() == 2);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
|
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
|
CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
|
||||||
RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array))
|
RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array));
|
||||||
|
|
||||||
LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
|
LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
|
||||||
return isolate->heap()->undefined_value();
|
return isolate->heap()->undefined_value();
|
||||||
@ -207,8 +207,8 @@ RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
|
|||||||
USE(new_shared_array);
|
USE(new_shared_array);
|
||||||
RUNTIME_ASSERT(old_shared_array->length()->IsSmi());
|
RUNTIME_ASSERT(old_shared_array->length()->IsSmi());
|
||||||
RUNTIME_ASSERT(new_shared_array->length() == old_shared_array->length());
|
RUNTIME_ASSERT(new_shared_array->length() == old_shared_array->length());
|
||||||
RUNTIME_ASSERT(old_shared_array->HasFastElements())
|
RUNTIME_ASSERT(old_shared_array->HasFastElements());
|
||||||
RUNTIME_ASSERT(new_shared_array->HasFastElements())
|
RUNTIME_ASSERT(new_shared_array->HasFastElements());
|
||||||
int array_length = Smi::cast(old_shared_array->length())->value();
|
int array_length = Smi::cast(old_shared_array->length())->value();
|
||||||
for (int i = 0; i < array_length; i++) {
|
for (int i = 0; i < array_length; i++) {
|
||||||
Handle<Object> old_element;
|
Handle<Object> old_element;
|
||||||
|
@ -5,19 +5,49 @@
|
|||||||
#ifndef V8_RUNTIME_RUNTIME_UTILS_H_
|
#ifndef V8_RUNTIME_RUNTIME_UTILS_H_
|
||||||
#define V8_RUNTIME_RUNTIME_UTILS_H_
|
#define V8_RUNTIME_RUNTIME_UTILS_H_
|
||||||
|
|
||||||
|
#include "src/base/logging.h"
|
||||||
#include "src/runtime/runtime.h"
|
#include "src/runtime/runtime.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
#define RUNTIME_ASSERT(value) \
|
#ifdef DEBUG
|
||||||
if (!(value)) return isolate->ThrowIllegalOperation();
|
|
||||||
|
#define RUNTIME_ASSERT(value) \
|
||||||
|
do { \
|
||||||
|
if (!(value)) { \
|
||||||
|
V8_RuntimeError(__FILE__, __LINE__, #value); \
|
||||||
|
return isolate->ThrowIllegalOperation(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define RUNTIME_ASSERT_HANDLIFIED(value, T) \
|
||||||
|
do { \
|
||||||
|
if (!(value)) { \
|
||||||
|
V8_RuntimeError(__FILE__, __LINE__, #value); \
|
||||||
|
isolate->ThrowIllegalOperation(); \
|
||||||
|
return MaybeHandle<T>(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define RUNTIME_ASSERT(value) \
|
||||||
|
do { \
|
||||||
|
if (!(value)) { \
|
||||||
|
return isolate->ThrowIllegalOperation(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define RUNTIME_ASSERT_HANDLIFIED(value, T) \
|
#define RUNTIME_ASSERT_HANDLIFIED(value, T) \
|
||||||
if (!(value)) { \
|
do { \
|
||||||
isolate->ThrowIllegalOperation(); \
|
if (!(value)) { \
|
||||||
return MaybeHandle<T>(); \
|
isolate->ThrowIllegalOperation(); \
|
||||||
}
|
return MaybeHandle<T>(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// Cast the given object to a value of the specified type and store
|
// Cast the given object to a value of the specified type and store
|
||||||
// it in a variable with the given name. If the object is not of the
|
// it in a variable with the given name. If the object is not of the
|
||||||
|
Loading…
Reference in New Issue
Block a user