Move Error methods to C++
This ports a large portion of Error methods to C++, including the constructor, stack setter and getter, and Error.prototype.toString. BUG= Committed: https://crrev.com/5742da056a290caa13a0b8717ddb1e43424e0d31 Review-Url: https://codereview.chromium.org/2142933003 Cr-Original-Commit-Position: refs/heads/master@{#37870} Cr-Commit-Position: refs/heads/master@{#37908}
This commit is contained in:
parent
d6a38645ef
commit
9211dee01a
1
BUILD.gn
1
BUILD.gn
@ -878,6 +878,7 @@ v8_source_set("v8_base") {
|
||||
"src/builtins/builtins-boolean.cc",
|
||||
"src/builtins/builtins-dataview.cc",
|
||||
"src/builtins/builtins-date.cc",
|
||||
"src/builtins/builtins-error.cc",
|
||||
"src/builtins/builtins-function.cc",
|
||||
"src/builtins/builtins-global.cc",
|
||||
"src/builtins/builtins-internal.cc",
|
||||
|
133
src/accessors.cc
133
src/accessors.cc
@ -1116,6 +1116,139 @@ Handle<AccessorInfo> Accessors::BoundFunctionNameInfo(
|
||||
attributes);
|
||||
}
|
||||
|
||||
//
|
||||
// Accessors::ErrorStack
|
||||
//
|
||||
|
||||
namespace {
|
||||
|
||||
MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate,
|
||||
Handle<JSObject> error) {
|
||||
RETURN_ON_EXCEPTION(
|
||||
isolate,
|
||||
JSReceiver::SetProperty(error, isolate->factory()->stack_trace_symbol(),
|
||||
isolate->factory()->undefined_value(), STRICT),
|
||||
JSReceiver);
|
||||
return error;
|
||||
}
|
||||
|
||||
MaybeHandle<Object> FormatStackTrace(Isolate* isolate, Handle<JSObject> error,
|
||||
Handle<Object> stack_trace) {
|
||||
// TODO(jgruber): Port FormatStackTrace from JS.
|
||||
Handle<JSFunction> fun = isolate->error_format_stack_trace();
|
||||
|
||||
int argc = 2;
|
||||
ScopedVector<Handle<Object>> argv(argc);
|
||||
argv[0] = error;
|
||||
argv[1] = stack_trace;
|
||||
|
||||
Handle<Object> formatted_stack_trace;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, formatted_stack_trace,
|
||||
Execution::Call(isolate, fun, error, argc, argv.start()), Object);
|
||||
|
||||
return formatted_stack_trace;
|
||||
}
|
||||
|
||||
bool IsAccessor(Handle<Object> receiver, Handle<Name> name,
|
||||
Handle<JSObject> holder) {
|
||||
LookupIterator it(receiver, name, holder,
|
||||
LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
// Skip any access checks we might hit. This accessor should never hit in a
|
||||
// situation where the caller does not have access.
|
||||
if (it.state() == LookupIterator::ACCESS_CHECK) {
|
||||
CHECK(it.HasAccess());
|
||||
it.Next();
|
||||
}
|
||||
return (it.state() == LookupIterator::ACCESSOR);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Accessors::ErrorStackGetter(
|
||||
v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
|
||||
HandleScope scope(isolate);
|
||||
Handle<JSObject> holder =
|
||||
Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
|
||||
|
||||
// Retrieve the structured stack trace.
|
||||
|
||||
Handle<Object> stack_trace;
|
||||
Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
|
||||
MaybeHandle<Object> maybe_stack_trace =
|
||||
JSObject::GetProperty(holder, stack_trace_symbol);
|
||||
if (!maybe_stack_trace.ToHandle(&stack_trace) ||
|
||||
stack_trace->IsUndefined(isolate)) {
|
||||
Handle<Object> result = isolate->factory()->undefined_value();
|
||||
info.GetReturnValue().Set(Utils::ToLocal(result));
|
||||
return;
|
||||
}
|
||||
|
||||
// Format it, clear the internal structured trace and reconfigure as a data
|
||||
// property.
|
||||
|
||||
Handle<Object> formatted_stack_trace;
|
||||
if (!FormatStackTrace(isolate, holder, stack_trace)
|
||||
.ToHandle(&formatted_stack_trace)) {
|
||||
isolate->OptionalRescheduleException(false);
|
||||
return;
|
||||
}
|
||||
|
||||
MaybeHandle<Object> result = ClearInternalStackTrace(isolate, holder);
|
||||
if (result.is_null()) {
|
||||
isolate->OptionalRescheduleException(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// If stack is still an accessor (this could have changed in the meantime
|
||||
// since FormatStackTrace can execute arbitrary JS), replace it with a data
|
||||
// property.
|
||||
Handle<Object> receiver = Utils::OpenHandle(*info.This());
|
||||
Handle<Name> name = Utils::OpenHandle(*key);
|
||||
if (IsAccessor(receiver, name, holder)) {
|
||||
result = ReplaceAccessorWithDataProperty(isolate, receiver, holder, name,
|
||||
formatted_stack_trace);
|
||||
if (result.is_null()) {
|
||||
isolate->OptionalRescheduleException(false);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// The stack property has been modified in the meantime.
|
||||
if (!JSObject::GetProperty(holder, name).ToHandle(&formatted_stack_trace)) {
|
||||
isolate->OptionalRescheduleException(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace);
|
||||
info.GetReturnValue().Set(value);
|
||||
}
|
||||
|
||||
void Accessors::ErrorStackSetter(v8::Local<v8::Name> name,
|
||||
v8::Local<v8::Value> val,
|
||||
const v8::PropertyCallbackInfo<void>& info) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
|
||||
HandleScope scope(isolate);
|
||||
Handle<JSObject> obj =
|
||||
Handle<JSObject>::cast(Utils::OpenHandle(*info.This()));
|
||||
|
||||
// Clear internal properties to avoid memory leaks.
|
||||
Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
|
||||
if (JSReceiver::HasOwnProperty(obj, stack_trace_symbol).FromMaybe(false)) {
|
||||
ClearInternalStackTrace(isolate, obj);
|
||||
}
|
||||
|
||||
Accessors::ReconfigureToDataProperty(name, val, info);
|
||||
}
|
||||
|
||||
Handle<AccessorInfo> Accessors::ErrorStackInfo(Isolate* isolate,
|
||||
PropertyAttributes attributes) {
|
||||
Handle<AccessorInfo> info =
|
||||
MakeAccessor(isolate, isolate->factory()->stack_string(),
|
||||
&ErrorStackGetter, &ErrorStackSetter, attributes);
|
||||
return info;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -24,6 +24,7 @@ class AccessorInfo;
|
||||
V(ArrayLength) \
|
||||
V(BoundFunctionLength) \
|
||||
V(BoundFunctionName) \
|
||||
V(ErrorStack) \
|
||||
V(FunctionArguments) \
|
||||
V(FunctionCaller) \
|
||||
V(FunctionName) \
|
||||
@ -46,9 +47,10 @@ class AccessorInfo;
|
||||
V(ScriptIsEmbedderDebugScript) \
|
||||
V(StringLength)
|
||||
|
||||
#define ACCESSOR_SETTER_LIST(V) \
|
||||
V(ReconfigureToDataProperty) \
|
||||
V(ArrayLengthSetter) \
|
||||
#define ACCESSOR_SETTER_LIST(V) \
|
||||
V(ReconfigureToDataProperty) \
|
||||
V(ArrayLengthSetter) \
|
||||
V(ErrorStackSetter) \
|
||||
V(FunctionPrototypeSetter)
|
||||
|
||||
// Accessors contains all predefined proxy accessors.
|
||||
|
@ -966,6 +966,71 @@ static void InstallWithIntrinsicDefaultProto(Isolate* isolate,
|
||||
isolate->native_context()->set(context_index, *function);
|
||||
}
|
||||
|
||||
static void InstallError(Isolate* isolate, Handle<JSObject> global,
|
||||
Handle<String> name, int context_index) {
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<JSFunction> error_fun =
|
||||
InstallFunction(global, name, JS_ERROR_TYPE, JSObject::kHeaderSize,
|
||||
isolate->initial_object_prototype(),
|
||||
Builtins::kErrorConstructor, DONT_ENUM);
|
||||
error_fun->shared()->set_instance_class_name(*factory->Error_string());
|
||||
error_fun->shared()->DontAdaptArguments();
|
||||
error_fun->shared()->set_construct_stub(
|
||||
*isolate->builtins()->ErrorConstructor());
|
||||
error_fun->shared()->set_length(1);
|
||||
error_fun->shared()->set_native(true);
|
||||
|
||||
if (context_index == Context::ERROR_FUNCTION_INDEX) {
|
||||
Handle<JSFunction> capture_stack_trace_fun =
|
||||
SimpleInstallFunction(error_fun, "captureStackTrace",
|
||||
Builtins::kErrorCaptureStackTrace, 2, false);
|
||||
capture_stack_trace_fun->shared()->set_native(true);
|
||||
}
|
||||
|
||||
InstallWithIntrinsicDefaultProto(isolate, error_fun, context_index);
|
||||
|
||||
{
|
||||
Handle<JSObject> prototype =
|
||||
factory->NewJSObject(isolate->object_function(), TENURED);
|
||||
|
||||
JSObject::AddProperty(prototype, factory->name_string(), name, DONT_ENUM);
|
||||
JSObject::AddProperty(prototype, factory->message_string(),
|
||||
factory->empty_string(), DONT_ENUM);
|
||||
JSObject::AddProperty(prototype, factory->constructor_string(), error_fun,
|
||||
DONT_ENUM);
|
||||
|
||||
Handle<JSFunction> to_string_fun =
|
||||
SimpleInstallFunction(prototype, factory->toString_string(),
|
||||
Builtins::kErrorPrototypeToString, 0, true);
|
||||
to_string_fun->shared()->set_native(true);
|
||||
|
||||
if (context_index != Context::ERROR_FUNCTION_INDEX) {
|
||||
Handle<JSFunction> global_error = isolate->error_function();
|
||||
CHECK(JSReceiver::SetPrototype(error_fun, global_error, false,
|
||||
Object::THROW_ON_ERROR)
|
||||
.FromMaybe(false));
|
||||
CHECK(JSReceiver::SetPrototype(prototype,
|
||||
handle(global_error->prototype(), isolate),
|
||||
false, Object::THROW_ON_ERROR)
|
||||
.FromMaybe(false));
|
||||
}
|
||||
|
||||
Accessors::FunctionSetPrototype(error_fun, prototype).Assert();
|
||||
}
|
||||
|
||||
Handle<Map> initial_map(error_fun->initial_map());
|
||||
Map::EnsureDescriptorSlack(initial_map, 1);
|
||||
|
||||
PropertyAttributes attribs = DONT_ENUM;
|
||||
Handle<AccessorInfo> error_stack =
|
||||
Accessors::ErrorStackInfo(isolate, attribs);
|
||||
{
|
||||
AccessorConstantDescriptor d(Handle<Name>(Name::cast(error_stack->name())),
|
||||
error_stack, attribs);
|
||||
initial_map->AppendDescriptor(&d);
|
||||
}
|
||||
}
|
||||
|
||||
// This is only called if we are not using snapshots. The equivalent
|
||||
// work in the snapshot case is done in HookUpGlobalObject.
|
||||
@ -1509,59 +1574,38 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
}
|
||||
|
||||
{ // -- E r r o r
|
||||
Handle<JSFunction> error_fun = InstallFunction(
|
||||
global, "Error", JS_ERROR_TYPE, JSObject::kHeaderSize,
|
||||
isolate->initial_object_prototype(), Builtins::kIllegal);
|
||||
InstallWithIntrinsicDefaultProto(isolate, error_fun,
|
||||
Context::ERROR_FUNCTION_INDEX);
|
||||
InstallError(isolate, global, factory->Error_string(),
|
||||
Context::ERROR_FUNCTION_INDEX);
|
||||
}
|
||||
|
||||
{ // -- E v a l E r r o r
|
||||
Handle<JSFunction> eval_error_fun = InstallFunction(
|
||||
global, "EvalError", JS_ERROR_TYPE, JSObject::kHeaderSize,
|
||||
isolate->initial_object_prototype(), Builtins::kIllegal);
|
||||
InstallWithIntrinsicDefaultProto(isolate, eval_error_fun,
|
||||
Context::EVAL_ERROR_FUNCTION_INDEX);
|
||||
InstallError(isolate, global, factory->EvalError_string(),
|
||||
Context::EVAL_ERROR_FUNCTION_INDEX);
|
||||
}
|
||||
|
||||
{ // -- R a n g e E r r o r
|
||||
Handle<JSFunction> range_error_fun = InstallFunction(
|
||||
global, "RangeError", JS_ERROR_TYPE, JSObject::kHeaderSize,
|
||||
isolate->initial_object_prototype(), Builtins::kIllegal);
|
||||
InstallWithIntrinsicDefaultProto(isolate, range_error_fun,
|
||||
Context::RANGE_ERROR_FUNCTION_INDEX);
|
||||
InstallError(isolate, global, factory->RangeError_string(),
|
||||
Context::RANGE_ERROR_FUNCTION_INDEX);
|
||||
}
|
||||
|
||||
{ // -- R e f e r e n c e E r r o r
|
||||
Handle<JSFunction> reference_error_fun = InstallFunction(
|
||||
global, "ReferenceError", JS_ERROR_TYPE, JSObject::kHeaderSize,
|
||||
isolate->initial_object_prototype(), Builtins::kIllegal);
|
||||
InstallWithIntrinsicDefaultProto(isolate, reference_error_fun,
|
||||
Context::REFERENCE_ERROR_FUNCTION_INDEX);
|
||||
InstallError(isolate, global, factory->ReferenceError_string(),
|
||||
Context::REFERENCE_ERROR_FUNCTION_INDEX);
|
||||
}
|
||||
|
||||
{ // -- S y n t a x E r r o r
|
||||
Handle<JSFunction> syntax_error_fun = InstallFunction(
|
||||
global, "SyntaxError", JS_ERROR_TYPE, JSObject::kHeaderSize,
|
||||
isolate->initial_object_prototype(), Builtins::kIllegal);
|
||||
InstallWithIntrinsicDefaultProto(isolate, syntax_error_fun,
|
||||
Context::SYNTAX_ERROR_FUNCTION_INDEX);
|
||||
InstallError(isolate, global, factory->SyntaxError_string(),
|
||||
Context::SYNTAX_ERROR_FUNCTION_INDEX);
|
||||
}
|
||||
|
||||
{ // -- T y p e E r r o r
|
||||
Handle<JSFunction> type_error_fun = InstallFunction(
|
||||
global, "TypeError", JS_ERROR_TYPE, JSObject::kHeaderSize,
|
||||
isolate->initial_object_prototype(), Builtins::kIllegal);
|
||||
InstallWithIntrinsicDefaultProto(isolate, type_error_fun,
|
||||
Context::TYPE_ERROR_FUNCTION_INDEX);
|
||||
InstallError(isolate, global, factory->TypeError_string(),
|
||||
Context::TYPE_ERROR_FUNCTION_INDEX);
|
||||
}
|
||||
|
||||
{ // -- U R I E r r o r
|
||||
Handle<JSFunction> uri_error_fun = InstallFunction(
|
||||
global, "URIError", JS_ERROR_TYPE, JSObject::kHeaderSize,
|
||||
isolate->initial_object_prototype(), Builtins::kIllegal);
|
||||
InstallWithIntrinsicDefaultProto(isolate, uri_error_fun,
|
||||
Context::URI_ERROR_FUNCTION_INDEX);
|
||||
InstallError(isolate, global, factory->URIError_string(),
|
||||
Context::URI_ERROR_FUNCTION_INDEX);
|
||||
}
|
||||
|
||||
// Initialize the embedder data slot.
|
||||
|
210
src/builtins/builtins-error.cc
Normal file
210
src/builtins/builtins-error.cc
Normal file
@ -0,0 +1,210 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/builtins/builtins-utils.h"
|
||||
|
||||
#include "src/accessors.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/property-descriptor.h"
|
||||
#include "src/string-builder.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// ES6 section 19.5.1.1 Error ( message )
|
||||
BUILTIN(ErrorConstructor) {
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// 1. If NewTarget is undefined, let newTarget be the active function object,
|
||||
// else let newTarget be NewTarget.
|
||||
|
||||
Handle<JSFunction> target = args.target<JSFunction>();
|
||||
Handle<JSReceiver> new_target;
|
||||
if (args.new_target()->IsJSReceiver()) {
|
||||
new_target = Handle<JSReceiver>::cast(args.new_target());
|
||||
} else {
|
||||
new_target = target;
|
||||
}
|
||||
|
||||
// 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%",
|
||||
// « [[ErrorData]] »).
|
||||
Handle<JSObject> err;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, err,
|
||||
JSObject::New(target, new_target));
|
||||
|
||||
// 3. If message is not undefined, then
|
||||
// a. Let msg be ? ToString(message).
|
||||
// b. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]:
|
||||
// true, [[Enumerable]]: false, [[Configurable]]: true}.
|
||||
// c. Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
|
||||
// 4. Return O.
|
||||
|
||||
Handle<Object> msg = args.atOrUndefined(isolate, 1);
|
||||
if (!msg->IsUndefined(isolate)) {
|
||||
Handle<String> msg_string;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, msg_string,
|
||||
Object::ToString(isolate, msg));
|
||||
RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate,
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
err, isolate->factory()->message_string(), msg_string, DONT_ENUM));
|
||||
}
|
||||
|
||||
// Capture the stack trace unless we're setting up.
|
||||
if (!isolate->bootstrapper()->IsActive()) {
|
||||
// Optionally capture a more detailed stack trace for the message.
|
||||
RETURN_FAILURE_ON_EXCEPTION(isolate,
|
||||
isolate->CaptureAndSetDetailedStackTrace(err));
|
||||
// Capture a simple stack trace for the stack property.
|
||||
RETURN_FAILURE_ON_EXCEPTION(isolate,
|
||||
isolate->CaptureAndSetSimpleStackTrace(err));
|
||||
}
|
||||
|
||||
return *err;
|
||||
}
|
||||
|
||||
// static
|
||||
BUILTIN(ErrorCaptureStackTrace) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<Object> object_obj = args.atOrUndefined(isolate, 1);
|
||||
if (!object_obj->IsJSObject()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kInvalidArgument, object_obj));
|
||||
}
|
||||
Handle<JSObject> object = Handle<JSObject>::cast(object_obj);
|
||||
Handle<Object> caller = args.atOrUndefined(isolate, 2);
|
||||
|
||||
// TODO(jgruber): Eagerly format the stack trace and remove accessors.h
|
||||
// include.
|
||||
|
||||
// Handle writes to the global object.
|
||||
|
||||
if (object->IsJSGlobalProxy()) {
|
||||
Map* map = object->map();
|
||||
if (map->has_hidden_prototype()) {
|
||||
object = handle(JSGlobalObject::cast(map->prototype()), isolate);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the stack property is read-only.
|
||||
|
||||
bool is_extensible = true;
|
||||
if (!JSObject::IsExtensible(object)) {
|
||||
is_extensible = false;
|
||||
}
|
||||
|
||||
PropertyDescriptor desc;
|
||||
Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
|
||||
isolate, object, isolate->factory()->stack_string(), &desc);
|
||||
if (owned.FromMaybe(false)) {
|
||||
if (!desc.configurable() || !desc.writable()) {
|
||||
is_extensible = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_extensible) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kDefineDisallowed,
|
||||
isolate->factory()->stack_string(), object));
|
||||
}
|
||||
|
||||
// Add stack accessors to the given object
|
||||
|
||||
Handle<Map> map(object->map());
|
||||
PropertyAttributes attribs = DONT_ENUM;
|
||||
Handle<AccessorInfo> error_stack =
|
||||
Accessors::ErrorStackInfo(isolate, attribs);
|
||||
{
|
||||
AccessorConstantDescriptor d(Handle<Name>(Name::cast(error_stack->name())),
|
||||
error_stack, attribs);
|
||||
Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
|
||||
int index = old_descriptors->SearchWithCache(isolate, *d.GetKey(), *map);
|
||||
if (index == DescriptorArray::kNotFound) {
|
||||
// TODO(jgruber): This ensures we do not crash when CaptureStackTrace is
|
||||
// called on an object with an existing "stack" property. This will be
|
||||
// removed as soon as we move to eager trace formatting.
|
||||
Handle<Map> new_map =
|
||||
Map::CopyInsertDescriptor(map, &d, INSERT_TRANSITION);
|
||||
JSObject::MigrateToMap(object, new_map, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect the stack trace.
|
||||
|
||||
RETURN_FAILURE_ON_EXCEPTION(isolate,
|
||||
isolate->CaptureAndSetDetailedStackTrace(object));
|
||||
RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, isolate->CaptureAndSetSimpleStackTrace(object, caller));
|
||||
|
||||
return *isolate->factory()->undefined_value();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
MaybeHandle<String> GetStringPropertyOrDefault(Isolate* isolate,
|
||||
Handle<JSReceiver> recv,
|
||||
Handle<String> key,
|
||||
Handle<String> default_str) {
|
||||
Handle<Object> obj;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, JSObject::GetProperty(recv, key),
|
||||
String);
|
||||
|
||||
Handle<String> str;
|
||||
if (obj->IsUndefined(isolate)) {
|
||||
str = default_str;
|
||||
} else {
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, str, Object::ToString(isolate, obj),
|
||||
String);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ES6 section 19.5.3.4 Error.prototype.toString ( )
|
||||
BUILTIN(ErrorPrototypeToString) {
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// 1. Let O be the this value.
|
||||
// 2. If Type(O) is not Object, throw a TypeError exception.
|
||||
CHECK_RECEIVER(JSReceiver, receiver, "Error.prototype.toString");
|
||||
|
||||
// 3. Let name be ? Get(O, "name").
|
||||
// 4. If name is undefined, let name be "Error"; otherwise let name be
|
||||
// ? ToString(name).
|
||||
Handle<String> name_key = isolate->factory()->name_string();
|
||||
Handle<String> name_default = isolate->factory()->Error_string();
|
||||
Handle<String> name;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, name,
|
||||
GetStringPropertyOrDefault(isolate, receiver, name_key, name_default));
|
||||
|
||||
// 5. Let msg be ? Get(O, "message").
|
||||
// 6. If msg is undefined, let msg be the empty String; otherwise let msg be
|
||||
// ? ToString(msg).
|
||||
Handle<String> msg_key = isolate->factory()->message_string();
|
||||
Handle<String> msg_default = isolate->factory()->empty_string();
|
||||
Handle<String> msg;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, msg,
|
||||
GetStringPropertyOrDefault(isolate, receiver, msg_key, msg_default));
|
||||
|
||||
// 7. If name is the empty String, return msg.
|
||||
// 8. If msg is the empty String, return name.
|
||||
if (name->length() == 0) return *msg;
|
||||
if (msg->length() == 0) return *name;
|
||||
|
||||
// 9. Return the result of concatenating name, the code unit 0x003A (COLON),
|
||||
// the code unit 0x0020 (SPACE), and msg.
|
||||
IncrementalStringBuilder builder(isolate);
|
||||
builder.AppendString(name);
|
||||
builder.AppendCString(": ");
|
||||
builder.AppendString(msg);
|
||||
RETURN_RESULT_OR_FAILURE(isolate, builder.Finish());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -142,6 +142,7 @@ void Builtins::Generate_GeneratorPrototypeThrow(CodeStubAssembler* assembler) {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
|
||||
namespace {
|
||||
|
@ -285,6 +285,11 @@ namespace internal {
|
||||
CPP(DatePrototypeToJson) \
|
||||
CPP(DateUTC) \
|
||||
\
|
||||
/* Error */ \
|
||||
CPP(ErrorConstructor) \
|
||||
CPP(ErrorCaptureStackTrace) \
|
||||
CPP(ErrorPrototypeToString) \
|
||||
\
|
||||
/* Function */ \
|
||||
CPP(FunctionConstructor) \
|
||||
ASM(FunctionPrototypeApply) \
|
||||
|
@ -101,6 +101,7 @@ enum BindingFlags {
|
||||
V(ASYNC_FUNCTION_AWAIT_INDEX, JSFunction, async_function_await) \
|
||||
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
|
||||
V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
|
||||
V(ERROR_FORMAT_STACK_TRACE_INDEX, JSFunction, error_format_stack_trace) \
|
||||
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
|
||||
V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
|
||||
V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
|
||||
|
@ -59,6 +59,7 @@
|
||||
V(enumerable_string, "enumerable") \
|
||||
V(Error_string, "Error") \
|
||||
V(eval_string, "eval") \
|
||||
V(EvalError_string, "EvalError") \
|
||||
V(false_string, "false") \
|
||||
V(float32x4_string, "float32x4") \
|
||||
V(Float32x4_string, "Float32x4") \
|
||||
@ -92,6 +93,7 @@
|
||||
V(length_string, "length") \
|
||||
V(line_string, "line") \
|
||||
V(Map_string, "Map") \
|
||||
V(message_string, "message") \
|
||||
V(minus_infinity_string, "-Infinity") \
|
||||
V(minus_zero_string, "-0") \
|
||||
V(name_string, "name") \
|
||||
@ -114,6 +116,8 @@
|
||||
V(prototype_string, "prototype") \
|
||||
V(Proxy_string, "Proxy") \
|
||||
V(query_colon_string, "(?:)") \
|
||||
V(RangeError_string, "RangeError") \
|
||||
V(ReferenceError_string, "ReferenceError") \
|
||||
V(RegExp_string, "RegExp") \
|
||||
V(script_string, "script") \
|
||||
V(setPrototypeOf_string, "setPrototypeOf") \
|
||||
@ -129,12 +133,14 @@
|
||||
V(String_string, "String") \
|
||||
V(symbol_string, "symbol") \
|
||||
V(Symbol_string, "Symbol") \
|
||||
V(SyntaxError_string, "SyntaxError") \
|
||||
V(this_string, "this") \
|
||||
V(throw_string, "throw") \
|
||||
V(timed_out, "timed-out") \
|
||||
V(toJSON_string, "toJSON") \
|
||||
V(toString_string, "toString") \
|
||||
V(true_string, "true") \
|
||||
V(TypeError_string, "TypeError") \
|
||||
V(uint16x8_string, "uint16x8") \
|
||||
V(Uint16x8_string, "Uint16x8") \
|
||||
V(uint32x4_string, "uint32x4") \
|
||||
@ -143,6 +149,7 @@
|
||||
V(Uint8x16_string, "Uint8x16") \
|
||||
V(undefined_string, "undefined") \
|
||||
V(undefined_to_string, "[object Undefined]") \
|
||||
V(URIError_string, "URIError") \
|
||||
V(valueOf_string, "valueOf") \
|
||||
V(values_string, "values") \
|
||||
V(value_string, "value") \
|
||||
@ -168,7 +175,6 @@
|
||||
V(error_end_pos_symbol) \
|
||||
V(error_script_symbol) \
|
||||
V(error_start_pos_symbol) \
|
||||
V(formatted_stack_trace_symbol) \
|
||||
V(frozen_symbol) \
|
||||
V(hash_code_symbol) \
|
||||
V(home_object_symbol) \
|
||||
|
@ -329,12 +329,34 @@ static Handle<FixedArray> MaybeGrow(Isolate* isolate,
|
||||
}
|
||||
|
||||
class StackTraceHelper {
|
||||
private:
|
||||
enum FrameSkipMode {
|
||||
SKIP_FIRST,
|
||||
SKIP_UNTIL_SEEN,
|
||||
SKIP_NONE,
|
||||
};
|
||||
|
||||
public:
|
||||
StackTraceHelper(Isolate* isolate, Handle<Object> caller)
|
||||
: isolate_(isolate), caller_(caller) {
|
||||
// If the caller parameter is a function we skip frames until we're
|
||||
// under it before starting to collect.
|
||||
seen_caller_ = !caller->IsJSFunction();
|
||||
// The caller parameter can be used to skip a specific set of frames in the
|
||||
// stack trace. It can be:
|
||||
// * null, when called from a standard error constructor. We unconditionally
|
||||
// skip the top frame, which is always a builtin-exit frame for the error
|
||||
// constructor builtin.
|
||||
// * a JSFunction, when called by the user from Error.captureStackTrace().
|
||||
// We skip each frame until encountering the caller function.
|
||||
// * For any other value, all frames are included in the trace.
|
||||
if (caller_.is_null()) {
|
||||
mode_ = SKIP_FIRST;
|
||||
skip_next_frame_ = true;
|
||||
} else if (caller_->IsJSFunction()) {
|
||||
mode_ = SKIP_UNTIL_SEEN;
|
||||
skip_next_frame_ = true;
|
||||
} else {
|
||||
mode_ = SKIP_NONE;
|
||||
skip_next_frame_ = false;
|
||||
}
|
||||
encountered_strict_function_ = false;
|
||||
sloppy_frames_ = 0;
|
||||
}
|
||||
@ -356,26 +378,34 @@ class StackTraceHelper {
|
||||
// Determines whether the given stack frame should be displayed in a stack
|
||||
// trace.
|
||||
bool IsVisibleInStackTrace(JSFunction* fun) {
|
||||
return IsAfterCaller(fun) && IsNotInNativeScript(fun) &&
|
||||
return ShouldIncludeFrame(fun) && IsNotInNativeScript(fun) &&
|
||||
IsInSameSecurityContext(fun);
|
||||
}
|
||||
|
||||
int sloppy_frames() const { return sloppy_frames_; }
|
||||
|
||||
private:
|
||||
// The caller is the error constructor that asked
|
||||
// for the stack trace to be collected. The first time a construct
|
||||
// call to this function is encountered it is skipped. The seen_caller
|
||||
// in/out parameter is used to remember if the caller has been seen
|
||||
// yet.
|
||||
bool IsAfterCaller(JSFunction* fun) {
|
||||
if ((fun == *caller_) && !(seen_caller_)) {
|
||||
seen_caller_ = true;
|
||||
return false;
|
||||
// This mechanism excludes a number of uninteresting frames from the stack
|
||||
// trace. This can be be the first frame (which will be a builtin-exit frame
|
||||
// for the error constructor builtin) or every frame until encountering a
|
||||
// user-specified function.
|
||||
bool ShouldIncludeFrame(JSFunction* fun) {
|
||||
switch (mode_) {
|
||||
case SKIP_NONE:
|
||||
return true;
|
||||
case SKIP_FIRST:
|
||||
if (!skip_next_frame_) return true;
|
||||
skip_next_frame_ = false;
|
||||
return false;
|
||||
case SKIP_UNTIL_SEEN:
|
||||
if (skip_next_frame_ && (fun == *caller_)) {
|
||||
skip_next_frame_ = false;
|
||||
return false;
|
||||
}
|
||||
return !skip_next_frame_;
|
||||
}
|
||||
// Skip all frames until we've seen the caller.
|
||||
if (!seen_caller_) return false;
|
||||
return true;
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsNotInNativeScript(JSFunction* fun) {
|
||||
@ -394,9 +424,11 @@ class StackTraceHelper {
|
||||
}
|
||||
|
||||
Isolate* isolate_;
|
||||
Handle<Object> caller_;
|
||||
|
||||
bool seen_caller_;
|
||||
FrameSkipMode mode_;
|
||||
Handle<Object> caller_;
|
||||
bool skip_next_frame_;
|
||||
|
||||
int sloppy_frames_;
|
||||
bool encountered_strict_function_;
|
||||
};
|
||||
@ -531,8 +563,9 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace(
|
||||
Handle<JSArray> stack_trace = CaptureCurrentStackTrace(
|
||||
stack_trace_for_uncaught_exceptions_frame_limit_,
|
||||
stack_trace_for_uncaught_exceptions_options_);
|
||||
// TODO(jgruber): Set back to STRICT once we have eagerly formatted traces.
|
||||
RETURN_ON_EXCEPTION(
|
||||
this, JSReceiver::SetProperty(error_object, key, stack_trace, STRICT),
|
||||
this, JSReceiver::SetProperty(error_object, key, stack_trace, SLOPPY),
|
||||
JSReceiver);
|
||||
}
|
||||
return error_object;
|
||||
@ -543,8 +576,9 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetSimpleStackTrace(
|
||||
// Capture stack trace for simple stack trace string formatting.
|
||||
Handle<Name> key = factory()->stack_trace_symbol();
|
||||
Handle<Object> stack_trace = CaptureSimpleStackTrace(error_object, caller);
|
||||
// TODO(jgruber): Set back to STRICT once we have eagerly formatted traces.
|
||||
RETURN_ON_EXCEPTION(
|
||||
this, JSReceiver::SetProperty(error_object, key, stack_trace, STRICT),
|
||||
this, JSReceiver::SetProperty(error_object, key, stack_trace, SLOPPY),
|
||||
JSReceiver);
|
||||
return error_object;
|
||||
}
|
||||
|
@ -700,7 +700,8 @@ class Isolate {
|
||||
MaybeHandle<JSReceiver> CaptureAndSetDetailedStackTrace(
|
||||
Handle<JSReceiver> error_object);
|
||||
MaybeHandle<JSReceiver> CaptureAndSetSimpleStackTrace(
|
||||
Handle<JSReceiver> error_object, Handle<Object> caller);
|
||||
Handle<JSReceiver> error_object,
|
||||
Handle<Object> caller = Handle<Object>());
|
||||
Handle<JSArray> GetDetailedStackTrace(Handle<JSObject> error_object);
|
||||
|
||||
// Returns if the given context may access the given global object. If
|
||||
|
@ -30,9 +30,14 @@ var callSiteWasmObjectSymbol =
|
||||
var callSiteWasmFunctionIndexSymbol =
|
||||
utils.ImportNow("call_site_wasm_func_index_symbol");
|
||||
var Float32x4ToString;
|
||||
var formattedStackTraceSymbol =
|
||||
utils.ImportNow("formatted_stack_trace_symbol");
|
||||
var GlobalObject = global.Object;
|
||||
var GlobalError = global.Error;
|
||||
var GlobalEvalError = global.EvalError;
|
||||
var GlobalRangeError = global.RangeError;
|
||||
var GlobalReferenceError = global.ReferenceError;
|
||||
var GlobalSyntaxError = global.SyntaxError;
|
||||
var GlobalTypeError = global.TypeError;
|
||||
var GlobalURIError = global.URIError;
|
||||
var Int16x8ToString;
|
||||
var Int32x4ToString;
|
||||
var Int8x16ToString;
|
||||
@ -66,13 +71,6 @@ utils.Import(function(from) {
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
var GlobalError;
|
||||
var GlobalTypeError;
|
||||
var GlobalRangeError;
|
||||
var GlobalURIError;
|
||||
var GlobalSyntaxError;
|
||||
var GlobalReferenceError;
|
||||
var GlobalEvalError;
|
||||
|
||||
|
||||
function NoSideEffectsObjectToString() {
|
||||
@ -603,92 +601,6 @@ function GetTypeName(receiver, requireConstructor) {
|
||||
return %GetConstructorName(receiver);
|
||||
}
|
||||
|
||||
|
||||
// Format the stack trace if not yet done, and return it.
|
||||
// Cache the formatted stack trace on the holder.
|
||||
var StackTraceGetter = function() {
|
||||
var formatted_stack_trace = UNDEFINED;
|
||||
var holder = this;
|
||||
while (holder) {
|
||||
var formatted_stack_trace =
|
||||
GET_PRIVATE(holder, formattedStackTraceSymbol);
|
||||
if (IS_UNDEFINED(formatted_stack_trace)) {
|
||||
// No formatted stack trace available.
|
||||
var stack_trace = GET_PRIVATE(holder, stackTraceSymbol);
|
||||
if (IS_UNDEFINED(stack_trace)) {
|
||||
// Neither formatted nor structured stack trace available.
|
||||
// Look further up the prototype chain.
|
||||
holder = %object_get_prototype_of(holder);
|
||||
continue;
|
||||
}
|
||||
formatted_stack_trace = FormatStackTrace(holder, stack_trace);
|
||||
SET_PRIVATE(holder, stackTraceSymbol, UNDEFINED);
|
||||
SET_PRIVATE(holder, formattedStackTraceSymbol, formatted_stack_trace);
|
||||
}
|
||||
return formatted_stack_trace;
|
||||
}
|
||||
return UNDEFINED;
|
||||
};
|
||||
|
||||
|
||||
// If the receiver equals the holder, set the formatted stack trace that the
|
||||
// getter returns.
|
||||
var StackTraceSetter = function(v) {
|
||||
if (IsErrorObject(this)) {
|
||||
SET_PRIVATE(this, stackTraceSymbol, UNDEFINED);
|
||||
SET_PRIVATE(this, formattedStackTraceSymbol, v);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Use a dummy function since we do not actually want to capture a stack trace
|
||||
// when constructing the initial Error prototytpes.
|
||||
var captureStackTrace = function() {};
|
||||
|
||||
|
||||
// Set up special error type constructors.
|
||||
function SetUpError(error_function) {
|
||||
%FunctionSetInstanceClassName(error_function, 'Error');
|
||||
var name = error_function.name;
|
||||
var prototype = new GlobalObject();
|
||||
if (name !== 'Error') {
|
||||
%InternalSetPrototype(error_function, GlobalError);
|
||||
%InternalSetPrototype(prototype, GlobalError.prototype);
|
||||
}
|
||||
%FunctionSetPrototype(error_function, prototype);
|
||||
|
||||
%AddNamedProperty(error_function.prototype, 'name', name, DONT_ENUM);
|
||||
%AddNamedProperty(error_function.prototype, 'message', '', DONT_ENUM);
|
||||
%AddNamedProperty(
|
||||
error_function.prototype, 'constructor', error_function, DONT_ENUM);
|
||||
|
||||
%SetCode(error_function, function(m) {
|
||||
if (IS_UNDEFINED(new.target)) return new error_function(m);
|
||||
|
||||
try { captureStackTrace(this, error_function); } catch (e) { }
|
||||
// Define all the expected properties directly on the error
|
||||
// object. This avoids going through getters and setters defined
|
||||
// on prototype objects.
|
||||
if (!IS_UNDEFINED(m)) {
|
||||
%AddNamedProperty(this, 'message', TO_STRING(m), DONT_ENUM);
|
||||
}
|
||||
});
|
||||
|
||||
%SetNativeFlag(error_function);
|
||||
return error_function;
|
||||
};
|
||||
|
||||
GlobalError = SetUpError(global.Error);
|
||||
GlobalEvalError = SetUpError(global.EvalError);
|
||||
GlobalRangeError = SetUpError(global.RangeError);
|
||||
GlobalReferenceError = SetUpError(global.ReferenceError);
|
||||
GlobalSyntaxError = SetUpError(global.SyntaxError);
|
||||
GlobalTypeError = SetUpError(global.TypeError);
|
||||
GlobalURIError = SetUpError(global.URIError);
|
||||
|
||||
utils.InstallFunctions(GlobalError.prototype, DONT_ENUM,
|
||||
['toString', ErrorToString]);
|
||||
|
||||
function ErrorToString() {
|
||||
if (!IS_RECEIVER(this)) {
|
||||
throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString");
|
||||
@ -728,21 +640,9 @@ function MakeURIError() {
|
||||
// Boilerplate for exceptions for stack overflows. Used from
|
||||
// Isolate::StackOverflow().
|
||||
var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
|
||||
utils.InstallGetterSetter(StackOverflowBoilerplate, 'stack',
|
||||
StackTraceGetter, StackTraceSetter)
|
||||
|
||||
// Define actual captureStackTrace function after everything has been set up.
|
||||
captureStackTrace = function captureStackTrace(obj, cons_opt) {
|
||||
// Define accessors first, as this may fail and throw.
|
||||
%object_define_property(obj, 'stack', { get: StackTraceGetter,
|
||||
set: StackTraceSetter,
|
||||
configurable: true });
|
||||
%CollectStackTrace(obj, cons_opt ? cons_opt : captureStackTrace);
|
||||
};
|
||||
|
||||
GlobalError.captureStackTrace = captureStackTrace;
|
||||
|
||||
%InstallToContext([
|
||||
"error_format_stack_trace", FormatStackTrace,
|
||||
"get_stack_trace_line_fun", GetStackTraceLine,
|
||||
"make_error_function", MakeGenericError,
|
||||
"make_range_error", MakeRangeError,
|
||||
|
@ -365,26 +365,6 @@ RUNTIME_FUNCTION(Runtime_AllocateSeqTwoByteString) {
|
||||
return *result;
|
||||
}
|
||||
|
||||
// Collect the raw data for a stack trace. Returns an array of 4
|
||||
// element segments each containing a receiver, function, code and
|
||||
// native code offset.
|
||||
RUNTIME_FUNCTION(Runtime_CollectStackTrace) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, error_object, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1);
|
||||
|
||||
if (!isolate->bootstrapper()->IsActive()) {
|
||||
// Optionally capture a more detailed stack trace for the message.
|
||||
RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, isolate->CaptureAndSetDetailedStackTrace(error_object));
|
||||
// Capture a simple stack trace for the stack property.
|
||||
RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, isolate->CaptureAndSetSimpleStackTrace(error_object, caller));
|
||||
}
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) {
|
||||
SealHandleScope shs(isolate);
|
||||
|
@ -307,7 +307,6 @@ namespace internal {
|
||||
F(AllocateInTargetSpace, 2, 1) \
|
||||
F(AllocateSeqOneByteString, 1, 1) \
|
||||
F(AllocateSeqTwoByteString, 1, 1) \
|
||||
F(CollectStackTrace, 2, 1) \
|
||||
F(MessageGetStartPosition, 1, 1) \
|
||||
F(MessageGetScript, 1, 1) \
|
||||
F(FormatMessageString, 4, 1) \
|
||||
|
@ -491,6 +491,7 @@
|
||||
'builtins/builtins-boolean.cc',
|
||||
'builtins/builtins-dataview.cc',
|
||||
'builtins/builtins-date.cc',
|
||||
'builtins/builtins-error.cc',
|
||||
'builtins/builtins-function.cc',
|
||||
'builtins/builtins-global.cc',
|
||||
'builtins/builtins-internal.cc',
|
||||
|
@ -517,8 +517,7 @@ TEST(ErrorObjectAfterTermination) {
|
||||
v8::Context::Scope context_scope(context);
|
||||
isolate->TerminateExecution();
|
||||
v8::Local<v8::Value> error = v8::Exception::Error(v8_str("error"));
|
||||
// TODO(yangguo): crbug/403509. Check for empty handle instead.
|
||||
CHECK(error->IsUndefined());
|
||||
CHECK(error->IsNativeError());
|
||||
}
|
||||
|
||||
|
||||
|
@ -33,18 +33,18 @@ function assertNotIn(thrower, error) {
|
||||
}
|
||||
|
||||
Realm.eval(realms[1], script);
|
||||
assertSame(3, Realm.shared.error_0.length);
|
||||
assertSame(4, Realm.shared.error_1.length);
|
||||
assertSame(2, Realm.shared.error_0.length);
|
||||
assertSame(3, Realm.shared.error_1.length);
|
||||
|
||||
assertTrue(Realm.shared.thrower_1 === Realm.shared.error_1[2].getFunction());
|
||||
assertTrue(Realm.shared.thrower_1 === Realm.shared.error_1[1].getFunction());
|
||||
assertNotIn(Realm.shared.thrower_0, Realm.shared.error_0);
|
||||
assertNotIn(Realm.shared.thrower_0, Realm.shared.error_1);
|
||||
|
||||
Realm.eval(realms[0], script);
|
||||
assertSame(5, Realm.shared.error_0.length);
|
||||
assertSame(4, Realm.shared.error_1.length);
|
||||
assertSame(4, Realm.shared.error_0.length);
|
||||
assertSame(3, Realm.shared.error_1.length);
|
||||
|
||||
assertTrue(Realm.shared.thrower_0 === Realm.shared.error_0[2].getFunction());
|
||||
assertTrue(Realm.shared.thrower_0 === Realm.shared.error_0[1].getFunction());
|
||||
assertNotIn(Realm.shared.thrower_1, Realm.shared.error_0);
|
||||
assertNotIn(Realm.shared.thrower_1, Realm.shared.error_1);
|
||||
|
||||
|
@ -155,6 +155,3 @@ function CheckNoScopeVisible(f) {
|
||||
CheckNoScopeVisible(Number);
|
||||
|
||||
CheckNoScopeVisible(Function.toString);
|
||||
|
||||
// This getter is known to be implemented as closure.
|
||||
CheckNoScopeVisible(new Error().__lookupGetter__("stack"));
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
// See: http://code.google.com/p/v8/issues/detail?id=1980
|
||||
|
||||
var msg = "Method Error.prototype.toString called on incompatible receiver ";
|
||||
|
||||
var invalid_this = [ "invalid", 23, undefined, null ];
|
||||
for (var i = 0; i < invalid_this.length; i++) {
|
||||
var exception = false;
|
||||
@ -34,7 +36,7 @@ for (var i = 0; i < invalid_this.length; i++) {
|
||||
Error.prototype.toString.call(invalid_this[i]);
|
||||
} catch (e) {
|
||||
exception = true;
|
||||
assertEquals("Error.prototype.toString called on non-object", e.message);
|
||||
assertEquals(msg + invalid_this[i], e.message);
|
||||
}
|
||||
assertTrue(exception);
|
||||
}
|
||||
|
@ -7,5 +7,5 @@ try {
|
||||
var p = new Proxy({}, o);
|
||||
Error.captureStackTrace(p);
|
||||
} catch(e) {
|
||||
assertEquals("Cannot pass private property name to proxy trap", e.message);
|
||||
assertEquals("invalid_argument", e.message);
|
||||
}
|
||||
|
@ -75,9 +75,9 @@ try {
|
||||
function testErrorPrototype(prototype) {
|
||||
var object = {};
|
||||
object.__proto__ = prototype;
|
||||
object.stack = "123"; // Overwriting stack property fails.
|
||||
assertEquals(prototype.stack, object.stack);
|
||||
assertTrue("123" != prototype.stack);
|
||||
object.stack = "123"; // Overwriting stack property succeeds.
|
||||
assertTrue(prototype.stack != object.stack);
|
||||
assertEquals("123", object.stack);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -366,3 +366,17 @@ my_error = new Error();
|
||||
var stolen_getter = Object.getOwnPropertyDescriptor(my_error, 'stack').get;
|
||||
Object.defineProperty(fake_error, 'stack', { get: stolen_getter });
|
||||
assertEquals(undefined, fake_error.stack);
|
||||
|
||||
// Check that overwriting the stack property during stack trace formatting
|
||||
// does not crash.
|
||||
error = new Error();
|
||||
error.__defineGetter__("name", function() { error.stack = "abc"; });
|
||||
assertEquals("abc", error.stack);
|
||||
|
||||
error = new Error();
|
||||
error.__defineGetter__("name", function() { delete error.stack; });
|
||||
assertEquals(undefined, error.stack);
|
||||
|
||||
// Check that repeated trace collection does not crash.
|
||||
error = new Error();
|
||||
Error.captureStackTrace(error);
|
||||
|
Loading…
Reference in New Issue
Block a user