Commit 99005f33 authored by Maya Lekova's avatar Maya Lekova Committed by Commit Bot

Revert "Implement top-level await for REPL mode"

This reverts commit 5bddc0e1.

Reason for revert: Possible culprit for https://bugs.chromium.org/p/chromium/issues/detail?id=1029863

Original change's description:
> Implement top-level await for REPL mode
> 
> Design doc: bit.ly/v8-repl-mode
> 
> This CL allows the usage of 'await' without wrapping code in an async
> function when using REPL mode in global evaluate. REPL mode evaluate
> is changed to *always* return a Promise. The resolve value of the
> promise is the completion value of the REPL script.
> 
> The implementation is based on two existing mechanisms:
>   - Similar to async functions, the content of a REPL script is
>     enclosed in a synthetic 'try' block. Any thrown error
>     is used to reject the Promise of the REPL script.
> 
>   - The content of the synthetic 'try' block is also re-written the
>     same way a normal script is. This is, artificial assignments to
>     a ".result" variable are inserted to simulate a completion
>     value. The difference for REPL scripts is, that ".result" is
>     used to resolve the Promise of the REPL script.
> 
>   - ".result" is not returned directly but wrapped in an object
>     literal: "{ .repl_result: .result}". This is done to prevent
>     resolved promises from being chained and resolved prematurely:
> 
>     > Promse.resolve(42);
> 
>     should evaluate to a promise, not 42.
> 
> Bug: chromium:1021921
> Change-Id: I00a5aafd9126ca7c97d09cd8787a3aec2821a67f
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1900464
> Reviewed-by: Yang Guo <yangguo@chromium.org>
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Commit-Queue: Simon Zünd <szuend@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#65273}

TBR=yangguo@chromium.org,leszeks@chromium.org,verwaest@chromium.org,szuend@chromium.org

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: chromium:1021921
Change-Id: I9eaea584e2e09f3dffcbbca3d75a3c9bcb0a1adf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1948719Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65333}
parent fd33223c
......@@ -213,7 +213,6 @@ class AstBigInt {
F(dot_iterator, ".iterator") \
F(dot_promise, ".promise") \
F(dot_result, ".result") \
F(dot_repl_result, ".repl_result") \
F(dot_switch_tag, ".switch_tag") \
F(dot_catch, ".catch") \
F(empty, "") \
......
......@@ -110,15 +110,10 @@ Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type)
}
DeclarationScope::DeclarationScope(Zone* zone,
AstValueFactory* ast_value_factory,
REPLMode repl_mode)
: Scope(zone),
function_kind_(repl_mode == REPLMode::kYes ? kAsyncFunction
: kNormalFunction),
params_(4, zone) {
AstValueFactory* ast_value_factory)
: Scope(zone), function_kind_(kNormalFunction), params_(4, zone) {
DCHECK_EQ(scope_type_, SCRIPT_SCOPE);
SetDefaults();
is_repl_mode_scope_ = repl_mode == REPLMode::kYes;
receiver_ = DeclareDynamicGlobal(ast_value_factory->this_string(),
THIS_VARIABLE, this);
}
......@@ -673,7 +668,7 @@ Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name,
Variable* DeclarationScope::DeclareGeneratorObjectVar(
const AstRawString* name) {
DCHECK(is_function_scope() || is_module_scope() || is_repl_mode_scope());
DCHECK(is_function_scope() || is_module_scope());
DCHECK_NULL(generator_object_var());
Variable* result = EnsureRareData()->generator_object =
......
......@@ -537,10 +537,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
bool is_debug_evaluate_scope() const { return is_debug_evaluate_scope_; }
bool IsSkippableFunctionScope();
void set_is_repl_mode_scope() { is_repl_mode_scope_ = true; }
bool is_repl_mode_scope() const {
DCHECK_IMPLIES(is_repl_mode_scope_, is_script_scope());
return is_repl_mode_scope_;
}
bool is_repl_mode_scope() const { return is_repl_mode_scope_; }
bool RemoveInnerScope(Scope* inner_scope) {
DCHECK_NOT_NULL(inner_scope);
......@@ -771,8 +768,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
DeclarationScope(Zone* zone, ScopeType scope_type,
Handle<ScopeInfo> scope_info);
// Creates a script scope.
DeclarationScope(Zone* zone, AstValueFactory* ast_value_factory,
REPLMode repl_mode = REPLMode::kNo);
DeclarationScope(Zone* zone, AstValueFactory* ast_value_factory);
FunctionKind function_kind() const { return function_kind_; }
......@@ -958,9 +954,9 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// The variable holding the JSGeneratorObject for generator, async
// and async generator functions, and modules. Only valid for
// function, module and REPL mode script scopes.
// function and module scopes.
Variable* generator_object_var() const {
DCHECK(is_function_scope() || is_module_scope() || is_repl_mode_scope());
DCHECK(is_function_scope() || is_module_scope());
return GetRareVariable(RareVariable::kGeneratorObject);
}
......
......@@ -31,6 +31,7 @@ bool Variable::IsGlobalObjectProperty() const {
}
bool Variable::IsReplGlobalLet() const {
DCHECK_IMPLIES(scope()->is_repl_mode_scope(), scope()->is_script_scope());
return scope()->is_repl_mode_scope() && mode() == VariableMode::kLet;
}
......
......@@ -135,6 +135,12 @@ ScriptOriginOptions OriginOptionsForEval(Object script) {
outer_origin_options.IsOpaque());
}
REPLMode OriginReplMode(Object script) {
if (!script.IsScript()) return REPLMode::kNo;
return Script::cast(script).is_repl_mode() ? REPLMode::kYes : REPLMode::kNo;
}
} // namespace
// ----------------------------------------------------------------------------
......@@ -1549,8 +1555,9 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
allow_eval_cache = true;
} else {
ParseInfo parse_info(isolate);
script = parse_info.CreateScript(
isolate, source, OriginOptionsForEval(outer_info->script()));
script = parse_info.CreateScript(isolate, source,
OriginOptionsForEval(outer_info->script()),
OriginReplMode(outer_info->script()));
script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
script->set_eval_from_shared(*outer_info);
if (eval_position == kNoSourcePosition) {
......
......@@ -174,7 +174,6 @@
V(_, dot_iterator_string, ".iterator") \
V(_, dot_promise_string, ".promise") \
V(_, dot_result_string, ".result") \
V(_, dot_repl_result_string, ".repl_result") \
V(_, dot_string, ".") \
V(_, dot_switch_tag_string, ".switch_tag") \
V(_, dotAll_string, "dotAll") \
......
......@@ -68,8 +68,7 @@ class InjectedScript::ProtocolPromiseHandler {
static bool add(V8InspectorSessionImpl* session,
v8::Local<v8::Context> context, v8::Local<v8::Value> value,
int executionContextId, const String16& objectGroup,
WrapMode wrapMode, bool replMode,
EvaluateCallback* callback) {
WrapMode wrapMode, EvaluateCallback* callback) {
v8::Local<v8::Promise::Resolver> resolver;
if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) {
callback->sendFailure(Response::InternalError());
......@@ -83,18 +82,21 @@ class InjectedScript::ProtocolPromiseHandler {
v8::Local<v8::Promise> promise = resolver->GetPromise();
V8InspectorImpl* inspector = session->inspector();
ProtocolPromiseHandler* handler = new ProtocolPromiseHandler(
session, executionContextId, objectGroup, wrapMode, replMode, callback);
session, executionContextId, objectGroup, wrapMode, callback);
v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate());
v8::Local<v8::Function> thenCallbackFunction =
v8::Function::New(context, thenCallback, wrapper, 0,
v8::ConstructorBehavior::kThrow)
.ToLocalChecked();
if (promise->Then(context, thenCallbackFunction).IsEmpty()) {
callback->sendFailure(Response::InternalError());
return false;
}
v8::Local<v8::Function> catchCallbackFunction =
v8::Function::New(context, catchCallback, wrapper, 0,
v8::ConstructorBehavior::kThrow)
.ToLocalChecked();
if (promise->Then(context, thenCallbackFunction, catchCallbackFunction)
.IsEmpty()) {
if (promise->Catch(context, catchCallbackFunction).IsEmpty()) {
callback->sendFailure(Response::InternalError());
return false;
}
......@@ -102,13 +104,6 @@ class InjectedScript::ProtocolPromiseHandler {
}
private:
static v8::Local<v8::String> GetDotReplResultString(v8::Isolate* isolate) {
// TODO(szuend): Cache the string in a v8::Persistent handle.
return v8::String::NewFromOneByte(
isolate, reinterpret_cast<const uint8_t*>(".repl_result"))
.ToLocalChecked();
}
static void thenCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
ProtocolPromiseHandler* handler = static_cast<ProtocolPromiseHandler*>(
info.Data().As<v8::External>()->Value());
......@@ -135,15 +130,13 @@ class InjectedScript::ProtocolPromiseHandler {
ProtocolPromiseHandler(V8InspectorSessionImpl* session,
int executionContextId, const String16& objectGroup,
WrapMode wrapMode, bool replMode,
EvaluateCallback* callback)
WrapMode wrapMode, EvaluateCallback* callback)
: m_inspector(session->inspector()),
m_sessionId(session->sessionId()),
m_contextGroupId(session->contextGroupId()),
m_executionContextId(executionContextId),
m_objectGroup(objectGroup),
m_wrapMode(wrapMode),
m_replMode(replMode),
m_callback(std::move(callback)),
m_wrapper(m_inspector->isolate(),
v8::External::New(m_inspector->isolate(), this)) {
......@@ -161,40 +154,19 @@ class InjectedScript::ProtocolPromiseHandler {
}
}
void thenCallback(v8::Local<v8::Value> value) {
void thenCallback(v8::Local<v8::Value> result) {
V8InspectorSessionImpl* session =
m_inspector->sessionById(m_contextGroupId, m_sessionId);
if (!session) return;
InjectedScript::ContextScope scope(session, m_executionContextId);
Response response = scope.initialize();
if (!response.isSuccess()) return;
std::unique_ptr<EvaluateCallback> callback =
scope.injectedScript()->takeEvaluateCallback(m_callback);
if (!callback) return;
// In REPL mode the result is additionally wrapped in an object.
// The evaluation result can be found at ".repl_result".
v8::Local<v8::Value> result = value;
if (m_replMode) {
v8::Local<v8::Object> object;
if (!result->ToObject(scope.context()).ToLocal(&object)) {
callback->sendFailure(response);
return;
}
v8::Local<v8::String> name =
GetDotReplResultString(m_inspector->isolate());
if (!object->Get(scope.context(), name).ToLocal(&result)) {
callback->sendFailure(response);
return;
}
}
if (m_objectGroup == "console") {
scope.injectedScript()->setLastEvaluationResult(result);
}
std::unique_ptr<EvaluateCallback> callback =
scope.injectedScript()->takeEvaluateCallback(m_callback);
if (!callback) return;
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
response = scope.injectedScript()->wrapObject(result, m_objectGroup,
m_wrapMode, &wrappedValue);
......@@ -240,18 +212,10 @@ class InjectedScript::ProtocolPromiseHandler {
if (!stack) {
stack = m_inspector->debugger()->captureStackTrace(true);
}
// REPL mode implicitly handles the script like an async function.
// Do not prepend the '(in promise)' prefix for these exceptions since that
// would be confusing for the user. The stringified error is part of the
// exception and does not need to be added in REPL mode, otherwise it would
// be printed twice.
String16 exceptionDetailsText =
m_replMode ? "Uncaught" : "Uncaught (in promise)" + message;
std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
protocol::Runtime::ExceptionDetails::create()
.setExceptionId(m_inspector->nextExceptionId())
.setText(exceptionDetailsText)
.setText("Uncaught (in promise)" + message)
.setLineNumber(stack && !stack->isEmpty() ? stack->topLineNumber()
: 0)
.setColumnNumber(
......@@ -290,7 +254,6 @@ class InjectedScript::ProtocolPromiseHandler {
int m_executionContextId;
String16 m_objectGroup;
WrapMode m_wrapMode;
bool m_replMode;
EvaluateCallback* m_callback;
v8::Global<v8::External> m_wrapper;
};
......@@ -570,7 +533,7 @@ std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
void InjectedScript::addPromiseCallback(
V8InspectorSessionImpl* session, v8::MaybeLocal<v8::Value> value,
const String16& objectGroup, WrapMode wrapMode, bool replMode,
const String16& objectGroup, WrapMode wrapMode,
std::unique_ptr<EvaluateCallback> callback) {
if (value.IsEmpty()) {
callback->sendFailure(Response::InternalError());
......@@ -578,10 +541,9 @@ void InjectedScript::addPromiseCallback(
}
v8::MicrotasksScope microtasksScope(m_context->isolate(),
v8::MicrotasksScope::kRunMicrotasks);
if (ProtocolPromiseHandler::add(session, m_context->context(),
value.ToLocalChecked(),
m_context->contextId(), objectGroup, wrapMode,
replMode, callback.get())) {
if (ProtocolPromiseHandler::add(
session, m_context->context(), value.ToLocalChecked(),
m_context->contextId(), objectGroup, wrapMode, callback.get())) {
m_evaluateCallbacks.insert(callback.release());
}
}
......
......@@ -108,7 +108,6 @@ class InjectedScript final {
void addPromiseCallback(V8InspectorSessionImpl* session,
v8::MaybeLocal<v8::Value> value,
const String16& objectGroup, WrapMode wrapMode,
bool replMode,
std::unique_ptr<EvaluateCallback> callback);
Response findObject(const RemoteObjectId&, v8::Local<v8::Value>*) const;
......
......@@ -196,7 +196,7 @@ void innerCallFunctionOn(
}
scope.injectedScript()->addPromiseCallback(
session, maybeResultValue, objectGroup, wrapMode, false /* replMode */,
session, maybeResultValue, objectGroup, wrapMode,
EvaluateCallbackWrapper<V8RuntimeAgentImpl::CallFunctionOnCallback>::wrap(
std::move(callback)));
}
......@@ -234,8 +234,8 @@ void V8RuntimeAgentImpl::evaluate(
Maybe<bool> includeCommandLineAPI, Maybe<bool> silent,
Maybe<int> executionContextId, Maybe<bool> returnByValue,
Maybe<bool> generatePreview, Maybe<bool> userGesture,
Maybe<bool> maybeAwaitPromise, Maybe<bool> throwOnSideEffect,
Maybe<double> timeout, Maybe<bool> disableBreaks, Maybe<bool> maybeReplMode,
Maybe<bool> awaitPromise, Maybe<bool> throwOnSideEffect,
Maybe<double> timeout, Maybe<bool> disableBreaks, Maybe<bool> replMode,
std::unique_ptr<EvaluateCallback> callback) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
"EvaluateScript");
......@@ -259,8 +259,6 @@ void V8RuntimeAgentImpl::evaluate(
if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
const bool replMode = maybeReplMode.fromMaybe(false);
// Temporarily enable allow evals for inspector.
scope.allowCodeGenerationFromStrings();
v8::MaybeLocal<v8::Value> maybeResultValue;
......@@ -284,8 +282,8 @@ void V8RuntimeAgentImpl::evaluate(
}
const v8::Local<v8::String> source =
toV8String(m_inspector->isolate(), expression);
maybeResultValue = v8::debug::EvaluateGlobal(m_inspector->isolate(), source,
mode, replMode);
maybeResultValue = v8::debug::EvaluateGlobal(
m_inspector->isolate(), source, mode, replMode.fromMaybe(false));
} // Run microtasks before returning result.
// Re-initialize after running client's code, as it could have destroyed
......@@ -299,17 +297,14 @@ void V8RuntimeAgentImpl::evaluate(
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
: WrapMode::kNoPreview;
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
// REPL mode always returns a promise that must be awaited.
const bool await = replMode || maybeAwaitPromise.fromMaybe(false);
if (!await || scope.tryCatch().HasCaught()) {
if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
scope.tryCatch(), objectGroup.fromMaybe(""), mode,
callback.get());
return;
}
scope.injectedScript()->addPromiseCallback(
m_session, maybeResultValue, objectGroup.fromMaybe(""), mode, replMode,
m_session, maybeResultValue, objectGroup.fromMaybe(""), mode,
EvaluateCallbackWrapper<EvaluateCallback>::wrap(std::move(callback)));
}
......@@ -333,7 +328,6 @@ void V8RuntimeAgentImpl::awaitPromise(
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
scope.injectedScript()->addPromiseCallback(
m_session, scope.object(), scope.objectGroupName(), mode,
false /* replMode */,
EvaluateCallbackWrapper<AwaitPromiseCallback>::wrap(std::move(callback)));
}
......@@ -594,7 +588,7 @@ void V8RuntimeAgentImpl::runScript(
}
scope.injectedScript()->addPromiseCallback(
m_session, maybeResultValue.ToLocalChecked(), objectGroup.fromMaybe(""),
mode, false /* replMode */,
mode,
EvaluateCallbackWrapper<RunScriptCallback>::wrap(std::move(callback)));
}
......
......@@ -4413,8 +4413,7 @@ void BytecodeGenerator::BuildAwait(int position) {
// multiple debug events for the same uncaught exception. There is no point
// in the body of an async function where catch prediction is
// HandlerTable::UNCAUGHT.
DCHECK(catch_prediction() != HandlerTable::UNCAUGHT ||
info()->scope()->is_repl_mode_scope());
DCHECK(catch_prediction() != HandlerTable::UNCAUGHT);
{
// Await(operand) and suspend.
......
......@@ -658,9 +658,8 @@ class ParserBase {
return ast_value_factory->GetOneByteString(name.c_str());
}
DeclarationScope* NewScriptScope(REPLMode repl_mode) const {
return new (zone())
DeclarationScope(zone(), ast_value_factory(), repl_mode);
DeclarationScope* NewScriptScope() const {
return new (zone()) DeclarationScope(zone(), ast_value_factory());
}
DeclarationScope* NewVarblockScope() const {
......
......@@ -438,10 +438,10 @@ Parser::Parser(ParseInfo* info)
void Parser::InitializeEmptyScopeChain(ParseInfo* info) {
DCHECK_NULL(original_scope_);
DCHECK_NULL(info->script_scope());
DeclarationScope* script_scope =
NewScriptScope(info->is_repl_mode() ? REPLMode::kYes : REPLMode::kNo);
DeclarationScope* script_scope = NewScriptScope();
info->set_script_scope(script_scope);
original_scope_ = script_scope;
if (info->is_repl_mode()) script_scope->set_is_repl_mode_scope();
}
void Parser::DeserializeScopeChain(
......@@ -612,8 +612,6 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
}
} else if (info->is_wrapped_as_function()) {
ParseWrapped(isolate, info, &body, scope, zone());
} else if (info->is_repl_mode()) {
ParseREPLProgram(info, &body, scope);
} else {
// Don't count the mode in the use counters--give the program a chance
// to enable script-wide strict mode below.
......@@ -714,59 +712,6 @@ void Parser::ParseWrapped(Isolate* isolate, ParseInfo* info,
body->Add(return_statement);
}
void Parser::ParseREPLProgram(ParseInfo* info, ScopedPtrList<Statement>* body,
DeclarationScope* scope) {
// REPL scripts are handled nearly the same way as the body of an async
// function. The difference is the value used to resolve the async
// promise.
// For a REPL script this is the completion value of the
// script instead of the expression of some "return" statement. The
// completion value of the script is obtained by manually invoking
// the {Rewriter} which will return a VariableProxy referencing the
// result.
DCHECK(info->is_repl_mode());
this->scope()->SetLanguageMode(info->language_mode());
PrepareGeneratorVariables();
BlockT block = impl()->NullBlock();
{
StatementListT statements(pointer_buffer());
ParseStatementList(&statements, Token::EOS);
block = factory()->NewBlock(true, statements);
}
base::Optional<VariableProxy*> maybe_result =
Rewriter::RewriteBody(info, scope, block->statements());
Expression* result_value =
(maybe_result && *maybe_result)
? static_cast<Expression*>(*maybe_result)
: factory()->NewUndefinedLiteral(kNoSourcePosition);
impl()->RewriteAsyncFunctionBody(body, block, WrapREPLResult(result_value));
}
Expression* Parser::WrapREPLResult(Expression* value) {
// REPL scripts additionally wrap the ".result" variable in an
// object literal:
//
// return %_AsyncFunctionResolve(
// .generator_object, {.repl_result: .result});
//
// Should ".result" be a resolved promise itself, the async return
// would chain the promises and return the resolve value instead of
// the promise.
Literal* property_name = factory()->NewStringLiteral(
ast_value_factory()->dot_repl_result_string(), kNoSourcePosition);
ObjectLiteralProperty* property =
factory()->NewObjectLiteralProperty(property_name, value, true);
ScopedPtrList<ObjectLiteralProperty> properties(pointer_buffer());
properties.Add(property);
return factory()->NewObjectLiteral(properties, false, kNoSourcePosition,
false);
}
FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
Handle<SharedFunctionInfo> shared_info) {
// It's OK to use the Isolate & counters here, since this function is only
......
......@@ -225,10 +225,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
ScopedPtrList<Statement>* body, DeclarationScope* scope,
Zone* zone);
void ParseREPLProgram(ParseInfo* info, ScopedPtrList<Statement>* body,
DeclarationScope* scope);
Expression* WrapREPLResult(Expression* value);
ZonePtrList<const AstRawString>* PrepareWrappedArguments(Isolate* isolate,
ParseInfo* info,
Zone* zone);
......
......@@ -70,7 +70,7 @@ PreParserIdentifier PreParser::GetIdentifier() const {
PreParser::PreParseResult PreParser::PreParseProgram() {
DCHECK_NULL(scope_);
DeclarationScope* scope = NewScriptScope(REPLMode::kNo);
DeclarationScope* scope = NewScriptScope();
#ifdef DEBUG
scope->set_is_being_lazily_parsed(true);
#endif
......
......@@ -360,6 +360,10 @@ DECLARATION_NODE_LIST(DEF_VISIT)
// Assumes code has been parsed. Mutates the AST, so the AST should not
// continue to be used in the case of failure.
bool Rewriter::Rewrite(ParseInfo* info) {
DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles;
DisallowHandleDereference no_deref;
RuntimeCallTimerScope runtimeTimer(
info->runtime_call_stats(),
RuntimeCallCounterId::kCompileRewriteReturnResult,
......@@ -371,22 +375,12 @@ bool Rewriter::Rewrite(ParseInfo* info) {
DCHECK_NOT_NULL(scope);
DCHECK_EQ(scope, scope->GetClosureScope());
if (scope->is_repl_mode_scope()) return true;
if (!(scope->is_script_scope() || scope->is_eval_scope() ||
scope->is_module_scope())) {
return true;
}
ZonePtrList<Statement>* body = function->body();
return RewriteBody(info, scope, body).has_value();
}
base::Optional<VariableProxy*> Rewriter::RewriteBody(
ParseInfo* info, Scope* scope, ZonePtrList<Statement>* body) {
DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles;
DisallowHandleDereference no_deref;
DCHECK_IMPLIES(scope->is_module_scope(), !body->is_empty());
if (!body->is_empty()) {
Variable* result = scope->AsDeclarationScope()->NewTemporary(
......@@ -398,19 +392,17 @@ base::Optional<VariableProxy*> Rewriter::RewriteBody(
DCHECK_IMPLIES(scope->is_module_scope(), processor.result_assigned());
if (processor.result_assigned()) {
int pos = kNoSourcePosition;
VariableProxy* result_value =
Expression* result_value =
processor.factory()->NewVariableProxy(result, pos);
if (!info->is_repl_mode()) {
Statement* result_statement =
processor.factory()->NewReturnStatement(result_value, pos);
body->Add(result_statement, info->zone());
}
return result_value;
Statement* result_statement =
processor.factory()->NewReturnStatement(result_value, pos);
body->Add(result_statement, info->zone());
}
if (processor.HasStackOverflow()) return base::nullopt;
if (processor.HasStackOverflow()) return false;
}
return nullptr;
return true;
}
} // namespace internal
......
......@@ -6,8 +6,6 @@
#define V8_PARSING_REWRITER_H_
#include "src/base/macros.h"
#include "src/base/optional.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
......@@ -18,8 +16,6 @@ class ParseInfo;
class Parser;
class DeclarationScope;
class Scope;
class Statement;
class VariableProxy;
class Rewriter {
public:
......@@ -30,13 +26,6 @@ class Rewriter {
// Assumes code has been parsed and scopes have been analyzed. Mutates the
// AST, so the AST should not continue to be used in the case of failure.
V8_EXPORT_PRIVATE static bool Rewrite(ParseInfo* info);
// Helper that does the actual re-writing. Extracted so REPL scripts can
// rewrite the body but then use the ".result" VariableProxy to resolve
// the async promise that is the result of running a REPL script.
// Returns base::nullopt in case something went wrong.
static base::Optional<VariableProxy*> RewriteBody(
ParseInfo* info, Scope* scope, ZonePtrList<Statement>* body);
};
......
// 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.
Debug = debug.Debug
const evaluate = Debug.evaluateGlobalREPL;
(async () => {
// Test that the completion value of the REPL script is the resolve value of the
// promise returned by evalute.
let result = evaluate('5;');
assertPromiseResult(result, (value) => {
assertEquals(5, value);
}, assertUnreachable);
// Test that top-level await in REPL mode works.
result = evaluate('let x = await Promise.resolve(42);');
assertPromiseResult(result, (value) => {
assertEquals(undefined, value);
assertEquals(42, x);
}, assertUnreachable);
// Test that a throwing REPL script results in a rejected promise.
result = evaluate('throw new Error("ba dum tsh");');
assertPromiseResult(result, assertUnreachable, (error) => {
assertEquals("ba dum tsh", error.message);
});
// Test that a rejected promise throws.
result = evaluate('await Promise.reject("Reject promise!");');
assertPromiseResult(result, assertUnreachable, (error) => {
assertEquals('Reject promise!', error);
});
// Test that we can bind a promise in REPL mode.
await evaluate('let y = Promise.resolve(21);');
assertPromiseResult(y, (value) => {
assertEquals(21, value);
}, assertUnreachable);
})().then(() => {
print("Async test completed successfully.");
}).catch(e => {
print(e.stack);
%AbortJS("Async test is failing");
});
......@@ -635,9 +635,7 @@ class DebugWrapper {
}
evaluateGlobalREPL(expr) {
return %RuntimeEvaluateREPL(expr).then(value => {
return value[".repl_result"];
});
return %RuntimeEvaluateREPL(expr);
}
eventDataException(params) {
......
......@@ -281,54 +281,54 @@ KNOWN_MAPS = {
("read_only_space", 0x01149): (92, "EnumCacheMap"),
("read_only_space", 0x01199): (86, "ArrayBoilerplateDescriptionMap"),
("read_only_space", 0x01295): (95, "InterceptorInfoMap"),
("read_only_space", 0x032ad): (71, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x032d5): (72, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x032fd): (73, "CallableTaskMap"),
("read_only_space", 0x03325): (74, "CallbackTaskMap"),
("read_only_space", 0x0334d): (75, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x03375): (78, "FunctionTemplateInfoMap"),
("read_only_space", 0x0339d): (79, "ObjectTemplateInfoMap"),
("read_only_space", 0x033c5): (80, "AccessCheckInfoMap"),
("read_only_space", 0x033ed): (81, "AccessorInfoMap"),
("read_only_space", 0x03415): (82, "AccessorPairMap"),
("read_only_space", 0x0343d): (83, "AliasedArgumentsEntryMap"),
("read_only_space", 0x03465): (84, "AllocationMementoMap"),
("read_only_space", 0x0348d): (87, "AsmWasmDataMap"),
("read_only_space", 0x034b5): (88, "AsyncGeneratorRequestMap"),
("read_only_space", 0x034dd): (90, "ClassPositionsMap"),
("read_only_space", 0x03505): (91, "DebugInfoMap"),
("read_only_space", 0x0352d): (94, "FunctionTemplateRareDataMap"),
("read_only_space", 0x03555): (97, "InterpreterDataMap"),
("read_only_space", 0x0357d): (98, "PromiseCapabilityMap"),
("read_only_space", 0x035a5): (99, "PromiseReactionMap"),
("read_only_space", 0x035cd): (100, "PrototypeInfoMap"),
("read_only_space", 0x035f5): (101, "ScriptMap"),
("read_only_space", 0x0361d): (105, "SourcePositionTableWithFrameCacheMap"),
("read_only_space", 0x03645): (106, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x0366d): (107, "StackFrameInfoMap"),
("read_only_space", 0x03695): (108, "StackTraceFrameMap"),
("read_only_space", 0x036bd): (109, "TemplateObjectDescriptionMap"),
("read_only_space", 0x036e5): (110, "Tuple2Map"),
("read_only_space", 0x0370d): (111, "Tuple3Map"),
("read_only_space", 0x03735): (112, "WasmCapiFunctionDataMap"),
("read_only_space", 0x0375d): (113, "WasmDebugInfoMap"),
("read_only_space", 0x03785): (114, "WasmExceptionTagMap"),
("read_only_space", 0x037ad): (115, "WasmExportedFunctionDataMap"),
("read_only_space", 0x037d5): (116, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x037fd): (117, "WasmJSFunctionDataMap"),
("read_only_space", 0x03825): (96, "InternalClassMap"),
("read_only_space", 0x0384d): (103, "SmiPairMap"),
("read_only_space", 0x03875): (102, "SmiBoxMap"),
("read_only_space", 0x0389d): (104, "SortStateMap"),
("read_only_space", 0x038c5): (85, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x038ed): (85, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x03915): (76, "LoadHandler1Map"),
("read_only_space", 0x0393d): (76, "LoadHandler2Map"),
("read_only_space", 0x03965): (76, "LoadHandler3Map"),
("read_only_space", 0x0398d): (77, "StoreHandler0Map"),
("read_only_space", 0x039b5): (77, "StoreHandler1Map"),
("read_only_space", 0x039dd): (77, "StoreHandler2Map"),
("read_only_space", 0x03a05): (77, "StoreHandler3Map"),
("read_only_space", 0x03295): (71, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x032bd): (72, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x032e5): (73, "CallableTaskMap"),
("read_only_space", 0x0330d): (74, "CallbackTaskMap"),
("read_only_space", 0x03335): (75, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x0335d): (78, "FunctionTemplateInfoMap"),
("read_only_space", 0x03385): (79, "ObjectTemplateInfoMap"),
("read_only_space", 0x033ad): (80, "AccessCheckInfoMap"),
("read_only_space", 0x033d5): (81, "AccessorInfoMap"),
("read_only_space", 0x033fd): (82, "AccessorPairMap"),
("read_only_space", 0x03425): (83, "AliasedArgumentsEntryMap"),
("read_only_space", 0x0344d): (84, "AllocationMementoMap"),
("read_only_space", 0x03475): (87, "AsmWasmDataMap"),
("read_only_space", 0x0349d): (88, "AsyncGeneratorRequestMap"),
("read_only_space", 0x034c5): (90, "ClassPositionsMap"),
("read_only_space", 0x034ed): (91, "DebugInfoMap"),
("read_only_space", 0x03515): (94, "FunctionTemplateRareDataMap"),
("read_only_space", 0x0353d): (97, "InterpreterDataMap"),
("read_only_space", 0x03565): (98, "PromiseCapabilityMap"),
("read_only_space", 0x0358d): (99, "PromiseReactionMap"),
("read_only_space", 0x035b5): (100, "PrototypeInfoMap"),
("read_only_space", 0x035dd): (101, "ScriptMap"),
("read_only_space", 0x03605): (105, "SourcePositionTableWithFrameCacheMap"),
("read_only_space", 0x0362d): (106, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x03655): (107, "StackFrameInfoMap"),
("read_only_space", 0x0367d): (108, "StackTraceFrameMap"),
("read_only_space", 0x036a5): (109, "TemplateObjectDescriptionMap"),
("read_only_space", 0x036cd): (110, "Tuple2Map"),
("read_only_space", 0x036f5): (111, "Tuple3Map"),
("read_only_space", 0x0371d): (112, "WasmCapiFunctionDataMap"),
("read_only_space", 0x03745): (113, "WasmDebugInfoMap"),
("read_only_space", 0x0376d): (114, "WasmExceptionTagMap"),
("read_only_space", 0x03795): (115, "WasmExportedFunctionDataMap"),
("read_only_space", 0x037bd): (116, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x037e5): (117, "WasmJSFunctionDataMap"),
("read_only_space", 0x0380d): (96, "InternalClassMap"),
("read_only_space", 0x03835): (103, "SmiPairMap"),
("read_only_space", 0x0385d): (102, "SmiBoxMap"),
("read_only_space", 0x03885): (104, "SortStateMap"),
("read_only_space", 0x038ad): (85, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x038d5): (85, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x038fd): (76, "LoadHandler1Map"),
("read_only_space", 0x03925): (76, "LoadHandler2Map"),
("read_only_space", 0x0394d): (76, "LoadHandler3Map"),
("read_only_space", 0x03975): (77, "StoreHandler0Map"),
("read_only_space", 0x0399d): (77, "StoreHandler1Map"),
("read_only_space", 0x039c5): (77, "StoreHandler2Map"),
("read_only_space", 0x039ed): (77, "StoreHandler3Map"),
("map_space", 0x00119): (1057, "ExternalMap"),
("map_space", 0x00141): (1073, "JSMessageObjectMap"),
}
......
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