c8206043e1
When a stack trace is captured, it is stored in a private symbol on the respective Error object. The first access to "Error.stack" will then format the stack trace, with a possible call into user JS via the Error.prepareStackTrace callback. Until now, the accessor converted ".stack" to a normal data property containing the formatted stack trace. This causes a new Map with a new DescriptorArray to be created, which will not be shared with anything else (also not other error objects with formated stack traces). This CL changes the accessor to store the formatted stack trace in the same symbol (stack_trace_symbol) as the structured data. The result is that an error object will have the same Map before and after "Error.stack" is accessed. Bug: v8:9115 Change-Id: I7d6bf49be76d63b57fbbaf904cc6ed7dbdbfb96b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1564061 Commit-Queue: Simon Zünd <szuend@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#60865}
76 lines
2.2 KiB
JavaScript
76 lines
2.2 KiB
JavaScript
// Copyright 2019 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.
|
|
//
|
|
// Flags: --allow-natives-syntax
|
|
|
|
(function TestErrorObjectsRetainMap() {
|
|
const error1 = new Error("foo");
|
|
const error2 = new Error("bar");
|
|
|
|
assertTrue(%HaveSameMap(error1, error2));
|
|
|
|
// Trigger serialization of the stack-trace.
|
|
error1.stack;
|
|
assertTrue(%HaveSameMap(error1, error2));
|
|
|
|
error2.stack;
|
|
assertTrue(%HaveSameMap(error1, error2));
|
|
})();
|
|
|
|
(function TestPrepareStackTraceCallback() {
|
|
Error.prepareStackTrace = (error, frame) => {
|
|
return "custom stack trace No. 42";
|
|
};
|
|
|
|
const error = new Error("foo");
|
|
|
|
// Check it twice, so both code paths in the accessor are exercised.
|
|
assertEquals(error.stack, "custom stack trace No. 42");
|
|
assertEquals(error.stack, "custom stack trace No. 42");
|
|
})();
|
|
|
|
(function TestPrepareStackTraceCallbackMessesWithProperty() {
|
|
Error.prepareStackTrace = (error, frames) => {
|
|
error.stack = "Yes, we can write to this!";
|
|
return 42;
|
|
};
|
|
|
|
const error = new Error("foo");
|
|
|
|
// Check it twice. The first returns the formatting result,
|
|
// the second the value of the private symbol.
|
|
assertEquals(error.stack, 42);
|
|
assertEquals(error.stack, 42);
|
|
})();
|
|
|
|
(function TestPrepareStackTraceCallbackInstallsGetter() {
|
|
Error.prepareStackTrace = (error, frames) => {
|
|
Object.defineProperty(error, "stack", { get: () => 42 });
|
|
return "<formatted stack trace>";
|
|
};
|
|
|
|
const error = new Error("foo");
|
|
|
|
// Check it twice. The second time the accessor should be used.
|
|
assertEquals(error.stack, "<formatted stack trace>");
|
|
assertEquals(error.stack, 42);
|
|
})();
|
|
|
|
(function TestPrepareStackTraceCallbackInstallsSetter() {
|
|
Error.prepareStackTrace = (error, frames) => {
|
|
Object.defineProperty(error, "stack", { set: (x) => {
|
|
error[42] = x;
|
|
}});
|
|
return "<formatted stack trace>";
|
|
};
|
|
|
|
const error = new Error("foo");
|
|
// Cause the accessor to get installed.
|
|
error.stack;
|
|
|
|
error.stack = "Who needs stack traces anyway?";
|
|
assertEquals(error[42], "Who needs stack traces anyway?");
|
|
assertEquals(error.stack, undefined); // No getter.
|
|
})();
|