Fix problem with stack location entries (#2183)

Summary:
Release note: Improve source location information

Changes to make sure that the source location of the call expression appears in the corresponding execution context record. Also emit execution records with no source location from stack traces. These are due to calls to internal helper methods for iterating over objects and arrays for argument destructuring.

Finally fix a CompilerDiagnostic construction call to include a source location.
Closes https://github.com/facebook/prepack/pull/2183

Differential Revision: D8698271

Pulled By: hermanventer

fbshipit-source-id: 10f77f718db645a4784723c3eca4bd4e06eb43f8
This commit is contained in:
Herman Venter 2018-06-29 11:49:49 -07:00 committed by Facebook Github Bot
parent 0e09f6f986
commit 3deb5e2885
8 changed files with 45 additions and 43 deletions

View File

@ -50,12 +50,16 @@ export default function(
}
// ECMA262 12.3.4.1
realm.setNextExecutionContextLocation(ast.loc);
// 1. Let ref be the result of evaluating MemberExpression.
let ref = env.evaluate(ast.callee, strictCode);
return evaluateReference(ref, ast, strictCode, env, realm);
let previousLoc = realm.setNextExecutionContextLocation(ast.loc);
try {
return evaluateReference(ref, ast, strictCode, env, realm);
} finally {
realm.setNextExecutionContextLocation(previousLoc);
}
}
function evaluateReference(

View File

@ -28,8 +28,6 @@ export default function(
env: LexicalEnvironment,
realm: Realm
): ObjectValue | AbstractObjectValue {
realm.setNextExecutionContextLocation(ast.loc);
// ECMA262 12.3.3.1 We just implement this method inline since it's only called here.
// 1. Return ? EvaluateNew(NewExpression, empty).
@ -62,12 +60,17 @@ export default function(
// b. ReturnIfAbrupt(argList).
}
// If we are in pure scope, attempt to recover from creating the construct if
// it fails by creating a temporal abstract
if (realm.isInPureScope()) {
return tryToEvaluateConstructOrLeaveAsAbstract(constructor, argsList, strictCode, realm);
} else {
return createConstruct(constructor, argsList, realm);
let previousLoc = realm.setNextExecutionContextLocation(ast.loc);
try {
// If we are in pure scope, attempt to recover from creating the construct if
// it fails by creating a temporal abstract
if (realm.isInPureScope()) {
return tryToEvaluateConstructOrLeaveAsAbstract(constructor, argsList, strictCode, realm);
} else {
return createConstruct(constructor, argsList, realm);
}
} finally {
realm.setNextExecutionContextLocation(previousLoc);
}
}

View File

@ -97,6 +97,7 @@ function buildStack(realm: Realm, context: ObjectValue) {
for (let executionContext of stack.reverse()) {
let caller = executionContext.caller;
if (!executionContext.loc) continue; // compiler generated helper for destructuring arguments
let locString = describeLocation(
realm,
caller ? caller.function : undefined,

View File

@ -15,7 +15,6 @@ import { FatalError } from "../errors.js";
import type { Realm } from "../realm.js";
import type { ECMAScriptFunctionValue } from "../values/index.js";
import { Completion, ReturnCompletion, AbruptCompletion, NormalCompletion } from "../completions.js";
import { ExecutionContext } from "../realm.js";
import { GlobalEnvironmentRecord, ObjectEnvironmentRecord } from "../environment.js";
import {
AbstractValue,
@ -1044,7 +1043,7 @@ export class FunctionImplementation {
ctx.suspend();
// 13. Let evalCxt be a new ECMAScript code execution context.
let evalCxt = new ExecutionContext();
let evalCxt = realm.createExecutionContext();
evalCxt.isStrict = strictEval;
// 14. Set the evalCxt's Function to null.

View File

@ -30,8 +30,6 @@ export default function(
env: LexicalEnvironment,
realm: Realm
): [Completion | Value, BabelNodeExpression, Array<BabelNodeStatement>] {
realm.setNextExecutionContextLocation(ast.loc);
// 1. Let ref be the result of evaluating MemberExpression.
let [ref, calleeAst, calleeIO] = env.partiallyEvaluateCompletion(ast.callee, strictCode);
if (ref instanceof AbruptCompletion) return [ref, (calleeAst: any), calleeIO];
@ -70,23 +68,28 @@ export default function(
}
}
let callResult = EvaluateCall(ref, func, ast, argVals, strictCode, env, realm);
if (callResult instanceof AbruptCompletion) {
if (completion instanceof PossiblyNormalCompletion)
completion = Join.stopEffectCaptureJoinApplyAndReturnCompletion(completion, callResult, realm);
else completion = callResult;
let resultAst = t.callExpression((calleeAst: any), partialArgs);
return [completion, resultAst, io];
let previousLoc = realm.setNextExecutionContextLocation(ast.loc);
try {
let callResult = EvaluateCall(ref, func, ast, argVals, strictCode, env, realm);
if (callResult instanceof AbruptCompletion) {
if (completion instanceof PossiblyNormalCompletion)
completion = Join.stopEffectCaptureJoinApplyAndReturnCompletion(completion, callResult, realm);
else completion = callResult;
let resultAst = t.callExpression((calleeAst: any), partialArgs);
return [completion, resultAst, io];
}
let callCompletion;
[callCompletion, callResult] = Join.unbundleNormalCompletion(callResult);
invariant(callResult instanceof Value);
invariant(completion === undefined || completion instanceof PossiblyNormalCompletion);
completion = Join.composeNormalCompletions(completion, callCompletion, callResult, realm);
if (completion instanceof PossiblyNormalCompletion) {
realm.captureEffects(completion);
}
return [completion, t.callExpression((calleeAst: any), partialArgs), io];
} finally {
realm.setNextExecutionContextLocation(previousLoc);
}
let callCompletion;
[callCompletion, callResult] = Join.unbundleNormalCompletion(callResult);
invariant(callResult instanceof Value);
invariant(completion === undefined || completion instanceof PossiblyNormalCompletion);
completion = Join.composeNormalCompletions(completion, callCompletion, callResult, realm);
if (completion instanceof PossiblyNormalCompletion) {
realm.captureEffects(completion);
}
return [completion, t.callExpression((calleeAst: any), partialArgs), io];
}
function callBothFunctionsAndJoinTheirEffects(

View File

@ -1617,26 +1617,18 @@ export class Realm {
createExecutionContext(): ExecutionContext {
let context = new ExecutionContext();
let loc = this.nextContextLocation;
if (loc) {
context.setLocation(loc);
this.nextContextLocation = null;
}
return context;
}
setNextExecutionContextLocation(loc: ?BabelNodeSourceLocation) {
if (!loc) return;
//if (this.nextContextLocation) {
// throw new ThrowCompletion(
// Construct(this, this.intrinsics.TypeError, [new StringValue(this, "Already have a context location that we haven't used yet")])
// );
//} else {
setNextExecutionContextLocation(loc: ?BabelNodeSourceLocation): ?BabelNodeSourceLocation {
let previousValue = this.nextContextLocation;
this.nextContextLocation = loc;
//}
return previousValue;
}
reportIntrospectionError(message?: void | string | StringValue) {

View File

@ -84,7 +84,7 @@ export class Functions {
realm.handleError(
new CompilerDiagnostic(
`Optimized Function Value ${location} is an not a function or react element`,
undefined,
realm.currentLocation,
"PP0033",
"FatalError"
)

View File

@ -1,4 +1,4 @@
// expected errors: [{"location":{"start":{"line":7,"column":16},"end":{"line":7,"column":18},"source":"test/error-handler/FinalObjectCannotBeMutated.js"},"severity":"FatalError","errorCode":"PP0026","callStack":"Error\n at f (unknown)"}]
// expected errors: [{"location":{"start":{"line":7,"column":16},"end":{"line":7,"column":18},"source":"test/error-handler/FinalObjectCannotBeMutated.js"},"severity":"FatalError","errorCode":"PP0026","callStack":"Error\n "}]
(function () {
function f() {
let o = {};