Commit 44d6ef37 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Reland "Fix stack trace accessor behavior."

BUG=v8:3404
LOG=N
R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/349033007

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22166 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b0956fb1
...@@ -5588,7 +5588,7 @@ class Internals { ...@@ -5588,7 +5588,7 @@ class Internals {
static const int kNullValueRootIndex = 7; static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8; static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9; static const int kFalseValueRootIndex = 9;
static const int kEmptyStringRootIndex = 161; static const int kEmptyStringRootIndex = 163;
// The external allocation limit should be below 256 MB on all architectures // The external allocation limit should be below 256 MB on all architectures
// to avoid that resource-constrained embedders run low on memory. // to avoid that resource-constrained embedders run low on memory.
......
...@@ -2221,6 +2221,17 @@ bool Genesis::InstallSpecialObjects(Handle<Context> native_context) { ...@@ -2221,6 +2221,17 @@ bool Genesis::InstallSpecialObjects(Handle<Context> native_context) {
false); false);
} }
// Expose the stack trace symbol to native JS.
RETURN_ON_EXCEPTION_VALUE(
isolate,
JSObject::SetOwnPropertyIgnoreAttributes(
handle(native_context->builtins(), isolate),
factory->InternalizeOneByteString(
STATIC_ASCII_VECTOR("stack_trace_symbol")),
factory->stack_trace_symbol(),
NONE),
false);
// Expose the debug global object in global if a name for it is specified. // Expose the debug global object in global if a name for it is specified.
if (FLAG_expose_debug_as != NULL && strlen(FLAG_expose_debug_as) != 0) { if (FLAG_expose_debug_as != NULL && strlen(FLAG_expose_debug_as) != 0) {
// If loading fails we just bail out without installing the // If loading fails we just bail out without installing the
......
...@@ -2935,6 +2935,8 @@ void Heap::CreateInitialObjects() { ...@@ -2935,6 +2935,8 @@ void Heap::CreateInitialObjects() {
set_uninitialized_symbol(*factory->NewPrivateSymbol()); set_uninitialized_symbol(*factory->NewPrivateSymbol());
set_megamorphic_symbol(*factory->NewPrivateSymbol()); set_megamorphic_symbol(*factory->NewPrivateSymbol());
set_observed_symbol(*factory->NewPrivateSymbol()); set_observed_symbol(*factory->NewPrivateSymbol());
set_stack_trace_symbol(*factory->NewPrivateSymbol());
set_detailed_stack_trace_symbol(*factory->NewPrivateSymbol());
Handle<SeededNumberDictionary> slow_element_dictionary = Handle<SeededNumberDictionary> slow_element_dictionary =
SeededNumberDictionary::New(isolate(), 0, TENURED); SeededNumberDictionary::New(isolate(), 0, TENURED);
......
...@@ -194,6 +194,8 @@ namespace internal { ...@@ -194,6 +194,8 @@ namespace internal {
V(Symbol, observed_symbol, ObservedSymbol) \ V(Symbol, observed_symbol, ObservedSymbol) \
V(Symbol, uninitialized_symbol, UninitializedSymbol) \ V(Symbol, uninitialized_symbol, UninitializedSymbol) \
V(Symbol, megamorphic_symbol, MegamorphicSymbol) \ V(Symbol, megamorphic_symbol, MegamorphicSymbol) \
V(Symbol, stack_trace_symbol, StackTraceSymbol) \
V(Symbol, detailed_stack_trace_symbol, DetailedStackTraceSymbol) \
V(FixedArray, materialized_objects, MaterializedObjects) \ V(FixedArray, materialized_objects, MaterializedObjects) \
V(FixedArray, allocation_sites_scratchpad, AllocationSitesScratchpad) \ V(FixedArray, allocation_sites_scratchpad, AllocationSitesScratchpad) \
V(FixedArray, microtask_queue, MicrotaskQueue) V(FixedArray, microtask_queue, MicrotaskQueue)
...@@ -344,7 +346,6 @@ namespace internal { ...@@ -344,7 +346,6 @@ namespace internal {
V(strict_compare_ic_string, "===") \ V(strict_compare_ic_string, "===") \
V(infinity_string, "Infinity") \ V(infinity_string, "Infinity") \
V(minus_infinity_string, "-Infinity") \ V(minus_infinity_string, "-Infinity") \
V(hidden_stack_trace_string, "v8::hidden_stack_trace") \
V(query_colon_string, "(?:)") \ V(query_colon_string, "(?:)") \
V(Generator_string, "Generator") \ V(Generator_string, "Generator") \
V(throw_string, "throw") \ V(throw_string, "throw") \
......
...@@ -352,10 +352,23 @@ static bool IsVisibleInStackTrace(JSFunction* fun, ...@@ -352,10 +352,23 @@ static bool IsVisibleInStackTrace(JSFunction* fun,
} }
Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
Handle<Object> caller, Handle<Object> caller) {
int limit) { // Get stack trace limit.
Handle<Object> error = Object::GetProperty(
this, js_builtins_object(), "$Error").ToHandleChecked();
if (!error->IsJSObject()) return factory()->undefined_value();
Handle<String> stackTraceLimit =
factory()->InternalizeUtf8String("stackTraceLimit");
ASSERT(!stackTraceLimit.is_null());
Handle<Object> stack_trace_limit =
JSObject::GetDataProperty(Handle<JSObject>::cast(error),
stackTraceLimit);
if (!stack_trace_limit->IsNumber()) return factory()->undefined_value();
int limit = FastD2IChecked(stack_trace_limit->Number());
limit = Max(limit, 0); // Ensure that limit is not negative. limit = Max(limit, 0); // Ensure that limit is not negative.
int initial_size = Min(limit, 10); int initial_size = Min(limit, 10);
Handle<FixedArray> elements = Handle<FixedArray> elements =
factory()->NewFixedArrayWithHoles(initial_size * 4 + 1); factory()->NewFixedArrayWithHoles(initial_size * 4 + 1);
...@@ -425,15 +438,25 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, ...@@ -425,15 +438,25 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
void Isolate::CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object) { void Isolate::CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object) {
if (capture_stack_trace_for_uncaught_exceptions_) { if (capture_stack_trace_for_uncaught_exceptions_) {
// Capture stack trace for a detailed exception message. // Capture stack trace for a detailed exception message.
Handle<String> key = factory()->hidden_stack_trace_string(); Handle<Name> key = factory()->detailed_stack_trace_symbol();
Handle<JSArray> stack_trace = CaptureCurrentStackTrace( Handle<JSArray> stack_trace = CaptureCurrentStackTrace(
stack_trace_for_uncaught_exceptions_frame_limit_, stack_trace_for_uncaught_exceptions_frame_limit_,
stack_trace_for_uncaught_exceptions_options_); stack_trace_for_uncaught_exceptions_options_);
JSObject::SetHiddenProperty(error_object, key, stack_trace); JSObject::SetProperty(
error_object, key, stack_trace, NONE, STRICT).Assert();
} }
} }
void Isolate::CaptureAndSetSimpleStackTrace(Handle<JSObject> error_object,
Handle<Object> caller) {
// Capture stack trace for simple stack trace string formatting.
Handle<Name> key = factory()->stack_trace_symbol();
Handle<Object> stack_trace = CaptureSimpleStackTrace(error_object, caller);
JSObject::SetProperty(error_object, key, stack_trace, NONE, STRICT).Assert();
}
Handle<JSArray> Isolate::CaptureCurrentStackTrace( Handle<JSArray> Isolate::CaptureCurrentStackTrace(
int frame_limit, StackTrace::StackTraceOptions options) { int frame_limit, StackTrace::StackTraceOptions options) {
// Ensure no negative values. // Ensure no negative values.
...@@ -775,25 +798,7 @@ Object* Isolate::StackOverflow() { ...@@ -775,25 +798,7 @@ Object* Isolate::StackOverflow() {
Handle<JSObject> exception = factory()->CopyJSObject(boilerplate); Handle<JSObject> exception = factory()->CopyJSObject(boilerplate);
DoThrow(*exception, NULL); DoThrow(*exception, NULL);
// Get stack trace limit. CaptureAndSetSimpleStackTrace(exception, factory()->undefined_value());
Handle<Object> error = Object::GetProperty(
this, js_builtins_object(), "$Error").ToHandleChecked();
if (!error->IsJSObject()) return heap()->exception();
Handle<String> stackTraceLimit =
factory()->InternalizeUtf8String("stackTraceLimit");
ASSERT(!stackTraceLimit.is_null());
Handle<Object> stack_trace_limit =
JSObject::GetDataProperty(Handle<JSObject>::cast(error),
stackTraceLimit);
if (!stack_trace_limit->IsNumber()) return heap()->exception();
int limit = FastD2IChecked(stack_trace_limit->Number());
if (limit < 0) limit = 0;
Handle<JSArray> stack_trace = CaptureSimpleStackTrace(
exception, factory()->undefined_value(), limit);
JSObject::SetHiddenProperty(exception,
factory()->hidden_stack_trace_string(),
stack_trace);
return heap()->exception(); return heap()->exception();
} }
...@@ -1049,13 +1054,16 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) { ...@@ -1049,13 +1054,16 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) {
if (capture_stack_trace_for_uncaught_exceptions_) { if (capture_stack_trace_for_uncaught_exceptions_) {
if (IsErrorObject(exception_handle)) { if (IsErrorObject(exception_handle)) {
// We fetch the stack trace that corresponds to this error object. // We fetch the stack trace that corresponds to this error object.
Handle<String> key = factory()->hidden_stack_trace_string(); Handle<Name> key = factory()->detailed_stack_trace_symbol();
Object* stack_property = // Look up as own property. If the lookup fails, the exception is
JSObject::cast(*exception_handle)->GetHiddenProperty(key); // probably not a valid Error object. In that case, we fall through
// Property lookup may have failed. In this case it's probably not // and capture the stack trace at this throw site.
// a valid Error object. LookupIterator lookup(
if (stack_property->IsJSArray()) { exception_handle, key, LookupIterator::CHECK_OWN_REAL);
stack_trace_object = Handle<JSArray>(JSArray::cast(stack_property)); Handle<Object> stack_trace_property;
if (Object::GetProperty(&lookup).ToHandle(&stack_trace_property) &&
stack_trace_property->IsJSArray()) {
stack_trace_object = Handle<JSArray>::cast(stack_trace_property);
} }
} }
if (stack_trace_object.is_null()) { if (stack_trace_object.is_null()) {
......
...@@ -702,11 +702,11 @@ class Isolate { ...@@ -702,11 +702,11 @@ class Isolate {
Handle<JSArray> CaptureCurrentStackTrace( Handle<JSArray> CaptureCurrentStackTrace(
int frame_limit, int frame_limit,
StackTrace::StackTraceOptions options); StackTrace::StackTraceOptions options);
Handle<Object> CaptureSimpleStackTrace(Handle<JSObject> error_object,
Handle<JSArray> CaptureSimpleStackTrace(Handle<JSObject> error_object, Handle<Object> caller);
Handle<Object> caller,
int limit);
void CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object); void CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object);
void CaptureAndSetSimpleStackTrace(Handle<JSObject> error_object,
Handle<Object> caller);
// Returns if the top context may access the given global object. If // Returns if the top context may access the given global object. If
// the result is false, the pending exception is guaranteed to be // the result is false, the pending exception is guaranteed to be
......
...@@ -1053,7 +1053,8 @@ function GetStackFrames(raw_stack) { ...@@ -1053,7 +1053,8 @@ function GetStackFrames(raw_stack) {
var formatting_custom_stack_trace = false; var formatting_custom_stack_trace = false;
function FormatStackTrace(obj, error_string, frames) { function FormatStackTrace(obj, raw_stack) {
var frames = GetStackFrames(raw_stack);
if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) { if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) {
var array = []; var array = [];
%MoveArrayContents(frames, array); %MoveArrayContents(frames, array);
...@@ -1070,7 +1071,7 @@ function FormatStackTrace(obj, error_string, frames) { ...@@ -1070,7 +1071,7 @@ function FormatStackTrace(obj, error_string, frames) {
} }
var lines = new InternalArray(); var lines = new InternalArray();
lines.push(error_string); lines.push(FormatErrorString(obj));
for (var i = 0; i < frames.length; i++) { for (var i = 0; i < frames.length; i++) {
var frame = frames[i]; var frame = frames[i];
var line; var line;
...@@ -1105,45 +1106,47 @@ function GetTypeName(receiver, requireConstructor) { ...@@ -1105,45 +1106,47 @@ function GetTypeName(receiver, requireConstructor) {
} }
function captureStackTrace(obj, cons_opt) { var stack_trace_symbol; // Set during bootstrapping.
var stackTraceLimit = $Error.stackTraceLimit; var formatted_stack_trace_symbol = NEW_PRIVATE("formatted stack trace");
if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
stackTraceLimit = 10000; // Format the stack trace if not yet done, and return it.
} // Cache the formatted stack trace on the holder.
var stack = %CollectStackTrace(obj, var StackTraceGetter = function() {
cons_opt ? cons_opt : captureStackTrace, var formatted_stack_trace = GET_PRIVATE(this, formatted_stack_trace_symbol);
stackTraceLimit); if (IS_UNDEFINED(formatted_stack_trace)) {
var holder = this;
var error_string = FormatErrorString(obj); while (!HAS_PRIVATE(holder, stack_trace_symbol)) {
holder = %GetPrototype(holder);
// Set the 'stack' property on the receiver. If the receiver is the same as if (!holder) return UNDEFINED;
// holder of this setter, the accessor pair is turned into a data property.
var setter = function(v) {
// Set data property on the receiver (not necessarily holder).
%DefineDataPropertyUnchecked(this, 'stack', v, NONE);
if (this === obj) {
// Release context values if holder is the same as the receiver.
stack = error_string = UNDEFINED;
} }
}; var stack_trace = GET_PRIVATE(holder, stack_trace_symbol);
if (IS_UNDEFINED(stack_trace)) return UNDEFINED;
formatted_stack_trace = FormatStackTrace(holder, stack_trace);
SET_PRIVATE(holder, stack_trace_symbol, UNDEFINED);
SET_PRIVATE(holder, formatted_stack_trace_symbol, formatted_stack_trace);
}
return formatted_stack_trace;
};
// The holder of this getter ('obj') may not be the receiver ('this').
// When this getter is called the first time, we use the context values to
// format a stack trace string and turn this accessor pair into a data
// property (on the holder).
var getter = function() {
// Stack is still a raw array awaiting to be formatted.
var result = FormatStackTrace(obj, error_string, GetStackFrames(stack));
// Replace this accessor to return result directly.
%DefineAccessorPropertyUnchecked(
obj, 'stack', function() { return result }, setter, DONT_ENUM);
// Release context values.
stack = error_string = UNDEFINED;
return result;
};
%DefineAccessorPropertyUnchecked(obj, 'stack', getter, setter, DONT_ENUM); // If the receiver equals the holder, set the formatted stack trace that the
// getter returns.
var StackTraceSetter = function(v) {
if (HAS_PRIVATE(this, stack_trace_symbol)) {
SET_PRIVATE(this, stack_trace_symbol, UNDEFINED);
SET_PRIVATE(this, formatted_stack_trace_symbol, 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 captureStackTrace(obj, cons_opt) {
// Define accessors first, as this may fail and throw.
ObjectDefineProperty(obj, 'stack', { get: StackTraceGetter,
set: StackTraceSetter});
%CollectStackTrace(obj, cons_opt ? cons_opt : captureStackTrace);
} }
...@@ -1279,40 +1282,8 @@ InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]); ...@@ -1279,40 +1282,8 @@ InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
function SetUpStackOverflowBoilerplate() { function SetUpStackOverflowBoilerplate() {
var boilerplate = MakeRangeError('stack_overflow', []); var boilerplate = MakeRangeError('stack_overflow', []);
var error_string = boilerplate.name + ": " + boilerplate.message;
// Set the 'stack' property on the receiver. If the receiver is the same as
// holder of this setter, the accessor pair is turned into a data property.
var setter = function(v) {
%DefineDataPropertyUnchecked(this, 'stack', v, NONE);
// Tentatively clear the hidden property. If the receiver is the same as
// holder, we release the raw stack trace this way.
%GetAndClearOverflowedStackTrace(this);
};
// The raw stack trace is stored as a hidden property on the holder of this
// getter, which may not be the same as the receiver. Find the holder to
// retrieve the raw stack trace and then turn this accessor pair into a
// data property.
var getter = function() {
var holder = this;
while (!IS_ERROR(holder)) {
holder = %GetPrototype(holder);
if (IS_NULL(holder)) return MakeSyntaxError('illegal_access', []);
}
var stack = %GetAndClearOverflowedStackTrace(holder);
// We may not have captured any stack trace.
if (IS_UNDEFINED(stack)) return stack;
var result = FormatStackTrace(holder, error_string, GetStackFrames(stack));
// Replace this accessor to return result directly.
%DefineAccessorPropertyUnchecked(
holder, 'stack', function() { return result }, setter, DONT_ENUM);
return result;
};
%DefineAccessorPropertyUnchecked( %DefineAccessorPropertyUnchecked(
boilerplate, 'stack', getter, setter, DONT_ENUM); boilerplate, 'stack', StackTraceGetter, StackTraceSetter, DONT_ENUM);
return boilerplate; return boilerplate;
} }
......
...@@ -14446,30 +14446,17 @@ RUNTIME_FUNCTION(Runtime_GetScript) { ...@@ -14446,30 +14446,17 @@ RUNTIME_FUNCTION(Runtime_GetScript) {
// native code offset. // native code offset.
RUNTIME_FUNCTION(Runtime_CollectStackTrace) { RUNTIME_FUNCTION(Runtime_CollectStackTrace) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 3); ASSERT(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1); CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1);
CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
// Optionally capture a more detailed stack trace for the message.
isolate->CaptureAndSetDetailedStackTrace(error_object);
// Capture a simple stack trace for the stack property.
return *isolate->CaptureSimpleStackTrace(error_object, caller, limit);
}
// Retrieve the stack trace. This is the raw stack trace that yet has to if (!isolate->bootstrapper()->IsActive()) {
// be formatted. Since we only need this once, clear it afterwards. // Optionally capture a more detailed stack trace for the message.
RUNTIME_FUNCTION(Runtime_GetAndClearOverflowedStackTrace) { isolate->CaptureAndSetDetailedStackTrace(error_object);
HandleScope scope(isolate); // Capture a simple stack trace for the stack property.
ASSERT(args.length() == 1); isolate->CaptureAndSetSimpleStackTrace(error_object, caller);
CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); }
Handle<String> key = isolate->factory()->hidden_stack_trace_string(); return isolate->heap()->undefined_value();
Handle<Object> result(error_object->GetHiddenProperty(key), isolate);
if (result->IsTheHole()) return isolate->heap()->undefined_value();
RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined());
JSObject::DeleteHiddenProperty(error_object, key);
return *result;
} }
......
...@@ -196,8 +196,7 @@ namespace internal { ...@@ -196,8 +196,7 @@ namespace internal {
F(FunctionIsAPIFunction, 1, 1) \ F(FunctionIsAPIFunction, 1, 1) \
F(FunctionIsBuiltin, 1, 1) \ F(FunctionIsBuiltin, 1, 1) \
F(GetScript, 1, 1) \ F(GetScript, 1, 1) \
F(CollectStackTrace, 3, 1) \ F(CollectStackTrace, 2, 1) \
F(GetAndClearOverflowedStackTrace, 1, 1) \
F(GetV8Version, 0, 1) \ F(GetV8Version, 0, 1) \
\ \
F(SetCode, 2, 1) \ F(SetCode, 2, 1) \
......
...@@ -4324,7 +4324,7 @@ TEST(ArrayShiftSweeping) { ...@@ -4324,7 +4324,7 @@ TEST(ArrayShiftSweeping) {
CHECK(heap->InOldPointerSpace(o->elements())); CHECK(heap->InOldPointerSpace(o->elements()));
CHECK(heap->InOldPointerSpace(*o)); CHECK(heap->InOldPointerSpace(*o));
Page* page = Page::FromAddress(o->elements()->address()); Page* page = Page::FromAddress(o->elements()->address());
CHECK(page->WasSwept() || CHECK(page->parallel_sweeping() <= MemoryChunk::PARALLEL_SWEEPING_FINALIZE ||
Marking::IsBlack(Marking::MarkBitFrom(o->elements()))); Marking::IsBlack(Marking::MarkBitFrom(o->elements())));
} }
......
// Copyright 2014 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.
function testError(error) {
// Reconfigure e.stack to be non-configurable
var desc1 = Object.getOwnPropertyDescriptor(error, "stack");
Object.defineProperty(error, "stack",
{get: desc1.get, set: desc1.set, configurable: false});
var desc2 = Object.getOwnPropertyDescriptor(error, "stack");
assertFalse(desc2.configurable);
assertEquals(desc1.get, desc2.get);
assertEquals(desc2.get, desc2.get);
}
function stackOverflow() {
function f() { f(); }
try { f() } catch (e) { return e; }
}
function referenceError() {
try { g() } catch (e) { return e; }
}
testError(referenceError());
testError(stackOverflow());
...@@ -3,5 +3,4 @@ ...@@ -3,5 +3,4 @@
// Flags: --allow-natives-syntax --harmony // Flags: --allow-natives-syntax --harmony
var _error_object = new Object(); var _error_object = new Object();
var _caller = new Object(); var _caller = new Object();
var _limit = 32; %CollectStackTrace(_error_object, _caller);
%CollectStackTrace(_error_object, _caller, _limit);
// Copyright 2014 the V8 project authors. All rights reserved.
// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
// Flags: --allow-natives-syntax --harmony
var _error_object = new Object();
%GetAndClearOverflowedStackTrace(_error_object);
...@@ -63,8 +63,8 @@ try { ...@@ -63,8 +63,8 @@ try {
function testErrorPrototype(prototype) { function testErrorPrototype(prototype) {
var object = {}; var object = {};
object.__proto__ = prototype; object.__proto__ = prototype;
object.stack = "123"; object.stack = "123"; // Overwriting stack property fails.
assertEquals("123", object.stack); assertEquals(prototype.stack, object.stack);
assertTrue("123" != prototype.stack); assertTrue("123" != prototype.stack);
} }
...@@ -128,6 +128,8 @@ try { ...@@ -128,6 +128,8 @@ try {
rec1(0); rec1(0);
} catch (e) { } catch (e) {
assertEquals(undefined, e.stack); assertEquals(undefined, e.stack);
e.stack = "abc";
assertEquals("abc", e.stack);
} }
Error.stackTraceLimit = 3; Error.stackTraceLimit = 3;
......
...@@ -331,3 +331,23 @@ Error.prepareStackTrace = function() { Error.prepareStackTrace = "custom"; }; ...@@ -331,3 +331,23 @@ Error.prepareStackTrace = function() { Error.prepareStackTrace = "custom"; };
new Error().stack; new Error().stack;
assertEquals("custom", Error.prepareStackTrace); assertEquals("custom", Error.prepareStackTrace);
// Check that the formatted stack trace can be set to undefined.
error = new Error();
error.stack = undefined;
assertEquals(undefined, error.stack);
// Check that the stack trace accessors are not forcibly set.
var my_error = {};
Object.freeze(my_error);
assertThrows(function() { Error.captureStackTrace(my_error); });
my_error = {};
Object.preventExtensions(my_error);
assertThrows(function() { Error.captureStackTrace(my_error); });
var fake_error = {};
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);
...@@ -47,11 +47,11 @@ EXPAND_MACROS = [ ...@@ -47,11 +47,11 @@ EXPAND_MACROS = [
# that the parser doesn't bit-rot. Change the values as needed when you add, # that the parser doesn't bit-rot. Change the values as needed when you add,
# remove or change runtime functions, but make sure we don't lose our ability # remove or change runtime functions, but make sure we don't lose our ability
# to parse them! # to parse them!
EXPECTED_FUNCTION_COUNT = 417 EXPECTED_FUNCTION_COUNT = 416
EXPECTED_FUZZABLE_COUNT = 332 EXPECTED_FUZZABLE_COUNT = 331
EXPECTED_CCTEST_COUNT = 6 EXPECTED_CCTEST_COUNT = 6
EXPECTED_UNKNOWN_COUNT = 4 EXPECTED_UNKNOWN_COUNT = 4
EXPECTED_BUILTINS_COUNT = 809 EXPECTED_BUILTINS_COUNT = 808
# Don't call these at all. # Don't call these at all.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment