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:
littledan 2016-03-01 09:21:06 -08:00 committed by Commit bot
parent 503d589340
commit 78d845308f
7 changed files with 55 additions and 13 deletions

View File

@ -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);
}

View File

@ -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.

View File

@ -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 " \

View File

@ -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;
} }

View File

@ -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); \
} }

View File

@ -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;

View File

@ -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