From 93b8e764b555d665aa7fe0f322e614922a2f3181 Mon Sep 17 00:00:00 2001 From: Caleb Meredith Date: Wed, 25 Jul 2018 16:13:03 -0700 Subject: [PATCH] Add message to error stack (#2311) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Because of an ordering bug messages weren’t being added to the error stacks thrown by Prepack. This made debugging runtime issues in generated Prepack code difficult. ```js throw new Error("foo"); ``` ```js (function() { var $$0 = { enumerable: false, configurable: true, writable: true, }; var _$0 = this; var _$1 = _$0.Error; var _$2 = _$1.prototype; var _$3 = _$0.Object; var _$4 = _$3.defineProperty; var __constructor = function() {}; var _0 = ((__constructor.prototype = _$2), new __constructor()); ($$0.value = "Error\n at /Users/calebmer/prepack/fb-www/input.js:4:7"), _$4(_0, "stack", $$0); ($$0.value = "foo"), _$4(_0, "message", $$0); throw _0; }.call(this)); ``` ```js (function() { var $$0 = { enumerable: false, configurable: true, writable: true, }; var _$0 = this; var _$1 = _$0.Error; var _$2 = _$1.prototype; var _$3 = _$0.Object; var _$4 = _$3.defineProperty; var __constructor = function() {}; var _0 = ((__constructor.prototype = _$2), new __constructor()); ($$0.value = "foo"), _$4(_0, "message", $$0); ($$0.value = "Error: foo\n at /Users/calebmer/prepack/fb-www/input.js:4:7"), _$4(_0, "stack", $$0); throw _0; }.call(this)); ``` Pull Request resolved: https://github.com/facebook/prepack/pull/2311 Differential Revision: D9005517 Pulled By: calebmer fbshipit-source-id: 8567624a67a78085d4072560541785e412cd6645 --- src/intrinsics/ecma262/Error.js | 57 +++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/intrinsics/ecma262/Error.js b/src/intrinsics/ecma262/Error.js index 4d8afbfa8..9f2af66a8 100644 --- a/src/intrinsics/ecma262/Error.js +++ b/src/intrinsics/ecma262/Error.js @@ -11,10 +11,18 @@ import type { Realm } from "../../realm.js"; import type { LexicalEnvironment } from "../../environment.js"; -import { ObjectValue, FunctionValue, NativeFunctionValue, StringValue } from "../../values/index.js"; +import { + AbstractValue, + ObjectValue, + FunctionValue, + NativeFunctionValue, + StringValue, + Value, +} from "../../values/index.js"; import { Get } from "../../methods/index.js"; import { Create, Properties, To } from "../../singletons.js"; import invariant from "../../invariant.js"; +import buildExpressionTemplate from "../../utils/builder.js"; import type { BabelNodeSourceLocation } from "@babel/types"; export default function(realm: Realm): NativeFunctionValue { @@ -76,23 +84,23 @@ export function describeLocation( return location; } -function buildStack(realm: Realm, context: ObjectValue) { +const buildStackTemplateSrc = 'A + (B ? ": " + B : "") + C'; +const buildStackTemplate = buildExpressionTemplate(buildStackTemplateSrc); + +function buildStack(realm: Realm, context: ObjectValue): Value { invariant(context.$ErrorData); let stack = context.$ErrorData.contextStack; if (!stack) return realm.intrinsics.undefined; let lines = []; - let header = ""; + let header = To.ToStringPartial(realm, Get(realm, context, "name")); - header += To.ToStringPartial(realm, Get(realm, context, "name")); - - let msg = Get(realm, context, "message"); - if (!msg.mightBeUndefined()) { - msg = To.ToStringPartial(realm, msg); - if (msg) header += `: ${msg}`; + let message = Get(realm, context, "message"); + if (!message.mightBeUndefined()) { + message = To.ToStringValue(realm, message); } else { - msg.throwIfNotConcrete(); + message.throwIfNotConcrete(); } for (let executionContext of stack.reverse()) { @@ -106,8 +114,17 @@ function buildStack(realm: Realm, context: ObjectValue) { ); if (locString !== undefined) lines.push(locString); } + let footer = `\n ${lines.join("\n ")}`; - return new StringValue(realm, `${header}\n ${lines.join("\n ")}`); + return message instanceof StringValue + ? new StringValue(realm, `${header}${message.value ? `: ${message.value}` : ""}${footer}`) + : AbstractValue.createFromTemplate( + realm, + buildStackTemplate, + StringValue, + [new StringValue(realm, header), message, new StringValue(realm, footer)], + buildStackTemplateSrc + ); } export function build(name: string, realm: Realm, inheritError?: boolean = true): NativeFunctionValue { @@ -122,15 +139,6 @@ export function build(name: string, realm: Realm, inheritError?: boolean = true) locationData: undefined, }; - // Build a text description of the stack. - let stackDesc = { - value: buildStack(realm, O), - enumerable: false, - configurable: true, - writable: true, - }; - Properties.DefinePropertyOrThrow(realm, O, "stack", stackDesc); - // 3. If message is not undefined, then if (!message.mightBeUndefined()) { // a. Let msg be ? ToString(message). @@ -150,6 +158,15 @@ export function build(name: string, realm: Realm, inheritError?: boolean = true) message.throwIfNotConcrete(); } + // Build a text description of the stack. + let stackDesc = { + value: buildStack(realm, O), + enumerable: false, + configurable: true, + writable: true, + }; + Properties.DefinePropertyOrThrow(realm, O, "stack", stackDesc); + // 4. Return O. return O; });