summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common.gypi2
-rw-r--r--deps/v8/include/v8.h4
-rw-r--r--deps/v8/src/builtins/builtins-promise-gen.cc34
-rw-r--r--deps/v8/src/builtins/builtins-promise-gen.h7
-rw-r--r--deps/v8/src/compiler/js-call-reducer.cc4
-rw-r--r--deps/v8/src/isolate.cc3
-rw-r--r--deps/v8/src/runtime/runtime-promise.cc20
-rw-r--r--deps/v8/src/runtime/runtime.h4
-rw-r--r--deps/v8/test/cctest/test-api.cc116
9 files changed, 149 insertions, 45 deletions
diff --git a/common.gypi b/common.gypi
index 17948b9da3..447ff992b4 100644
--- a/common.gypi
+++ b/common.gypi
@@ -28,7 +28,7 @@
# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
- 'v8_embedder_string': '-node.16',
+ 'v8_embedder_string': '-node.17',
# Enable disassembler for `--print-code` v8 options
'v8_enable_disassembler': 1,
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h
index fe8f5a3839..389a7c01b0 100644
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -6394,7 +6394,9 @@ typedef void (*PromiseHook)(PromiseHookType type, Local<Promise> promise,
// --- Promise Reject Callback ---
enum PromiseRejectEvent {
kPromiseRejectWithNoHandler = 0,
- kPromiseHandlerAddedAfterReject = 1
+ kPromiseHandlerAddedAfterReject = 1,
+ kPromiseRejectAfterResolved = 2,
+ kPromiseResolveAfterResolved = 3,
};
class PromiseRejectMessage {
diff --git a/deps/v8/src/builtins/builtins-promise-gen.cc b/deps/v8/src/builtins/builtins-promise-gen.cc
index 868b45a831..0a94139fed 100644
--- a/deps/v8/src/builtins/builtins-promise-gen.cc
+++ b/deps/v8/src/builtins/builtins-promise-gen.cc
@@ -247,6 +247,8 @@ Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
Node* const context =
CreatePromiseContext(native_context, kPromiseContextLength);
StoreContextElementNoWriteBarrier(context, kPromiseSlot, promise);
+ StoreContextElementNoWriteBarrier(context, kAlreadyResolvedSlot,
+ FalseConstant());
StoreContextElementNoWriteBarrier(context, kDebugEventSlot, debug_event);
return context;
}
@@ -733,17 +735,27 @@ TF_BUILTIN(PromiseCapabilityDefaultReject, PromiseBuiltinsAssembler) {
Node* const promise = LoadContextElement(context, kPromiseSlot);
// 3. Let alreadyResolved be F.[[AlreadyResolved]].
+ Label if_already_resolved(this, Label::kDeferred);
+ Node* const already_resolved =
+ LoadContextElement(context, kAlreadyResolvedSlot);
+
// 4. If alreadyResolved.[[Value]] is true, return undefined.
- // We use undefined as a marker for the [[AlreadyResolved]] state.
- ReturnIf(IsUndefined(promise), UndefinedConstant());
+ GotoIf(IsTrue(already_resolved), &if_already_resolved);
// 5. Set alreadyResolved.[[Value]] to true.
- StoreContextElementNoWriteBarrier(context, kPromiseSlot, UndefinedConstant());
+ StoreContextElementNoWriteBarrier(context, kAlreadyResolvedSlot,
+ TrueConstant());
// 6. Return RejectPromise(promise, reason).
Node* const debug_event = LoadContextElement(context, kDebugEventSlot);
Return(CallBuiltin(Builtins::kRejectPromise, context, promise, reason,
debug_event));
+
+ BIND(&if_already_resolved);
+ {
+ Return(CallRuntime(Runtime::kPromiseRejectAfterResolved, context, promise,
+ reason));
+ }
}
// ES #sec-promise-resolve-functions
@@ -755,16 +767,26 @@ TF_BUILTIN(PromiseCapabilityDefaultResolve, PromiseBuiltinsAssembler) {
Node* const promise = LoadContextElement(context, kPromiseSlot);
// 3. Let alreadyResolved be F.[[AlreadyResolved]].
+ Label if_already_resolved(this, Label::kDeferred);
+ Node* const already_resolved =
+ LoadContextElement(context, kAlreadyResolvedSlot);
+
// 4. If alreadyResolved.[[Value]] is true, return undefined.
- // We use undefined as a marker for the [[AlreadyResolved]] state.
- ReturnIf(IsUndefined(promise), UndefinedConstant());
+ GotoIf(IsTrue(already_resolved), &if_already_resolved);
// 5. Set alreadyResolved.[[Value]] to true.
- StoreContextElementNoWriteBarrier(context, kPromiseSlot, UndefinedConstant());
+ StoreContextElementNoWriteBarrier(context, kAlreadyResolvedSlot,
+ TrueConstant());
// The rest of the logic (and the catch prediction) is
// encapsulated in the dedicated ResolvePromise builtin.
Return(CallBuiltin(Builtins::kResolvePromise, context, promise, resolution));
+
+ BIND(&if_already_resolved);
+ {
+ Return(CallRuntime(Runtime::kPromiseResolveAfterResolved, context, promise,
+ resolution));
+ }
}
TF_BUILTIN(PromiseConstructorLazyDeoptContinuation, PromiseBuiltinsAssembler) {
diff --git a/deps/v8/src/builtins/builtins-promise-gen.h b/deps/v8/src/builtins/builtins-promise-gen.h
index 694cea28c0..0920c33cf8 100644
--- a/deps/v8/src/builtins/builtins-promise-gen.h
+++ b/deps/v8/src/builtins/builtins-promise-gen.h
@@ -17,11 +17,12 @@ typedef compiler::CodeAssemblerState CodeAssemblerState;
class PromiseBuiltinsAssembler : public CodeStubAssembler {
public:
enum PromiseResolvingFunctionContextSlot {
- // The promise which resolve/reject callbacks fulfill. If this is
- // undefined, then we've already visited this callback and it
- // should be a no-op.
+ // The promise which resolve/reject callbacks fulfill.
kPromiseSlot = Context::MIN_CONTEXT_SLOTS,
+ // Whether the callback was already invoked.
+ kAlreadyResolvedSlot,
+
// Whether to trigger a debug event or not. Used in catch
// prediction.
kDebugEventSlot,
diff --git a/deps/v8/src/compiler/js-call-reducer.cc b/deps/v8/src/compiler/js-call-reducer.cc
index 8e5034cde0..f226c7bd5d 100644
--- a/deps/v8/src/compiler/js-call-reducer.cc
+++ b/deps/v8/src/compiler/js-call-reducer.cc
@@ -5347,6 +5347,10 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
promise_context, promise, effect, control);
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForContextSlot(
+ PromiseBuiltinsAssembler::kAlreadyResolvedSlot)),
+ promise_context, jsgraph()->FalseConstant(), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForContextSlot(
PromiseBuiltinsAssembler::kDebugEventSlot)),
promise_context, jsgraph()->TrueConstant(), effect, control);
diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc
index 7ef0214f4a..849e4ba5be 100644
--- a/deps/v8/src/isolate.cc
+++ b/deps/v8/src/isolate.cc
@@ -3875,10 +3875,9 @@ void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
void Isolate::ReportPromiseReject(Handle<JSPromise> promise,
Handle<Object> value,
v8::PromiseRejectEvent event) {
- DCHECK_EQ(v8::Promise::kRejected, promise->status());
if (promise_reject_callback_ == nullptr) return;
Handle<FixedArray> stack_trace;
- if (event == v8::kPromiseRejectWithNoHandler && value->IsJSObject()) {
+ if (event != v8::kPromiseHandlerAddedAfterReject && value->IsJSObject()) {
stack_trace = GetDetailedStackTrace(Handle<JSObject>::cast(value));
}
promise_reject_callback_(v8::PromiseRejectMessage(
diff --git a/deps/v8/src/runtime/runtime-promise.cc b/deps/v8/src/runtime/runtime-promise.cc
index f5b9db3c02..6c4f7d69eb 100644
--- a/deps/v8/src/runtime/runtime-promise.cc
+++ b/deps/v8/src/runtime/runtime-promise.cc
@@ -38,6 +38,26 @@ RUNTIME_FUNCTION(Runtime_PromiseRejectEventFromStack) {
return isolate->heap()->undefined_value();
}
+RUNTIME_FUNCTION(Runtime_PromiseRejectAfterResolved) {
+ DCHECK_EQ(2, args.length());
+ HandleScope scope(isolate);
+ CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1);
+ isolate->ReportPromiseReject(promise, reason,
+ v8::kPromiseRejectAfterResolved);
+ return isolate->heap()->undefined_value();
+}
+
+RUNTIME_FUNCTION(Runtime_PromiseResolveAfterResolved) {
+ DCHECK_EQ(2, args.length());
+ HandleScope scope(isolate);
+ CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, resolution, 1);
+ isolate->ReportPromiseReject(promise, resolution,
+ v8::kPromiseResolveAfterResolved);
+ return isolate->heap()->undefined_value();
+}
+
RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) {
DCHECK_EQ(1, args.length());
HandleScope scope(isolate);
diff --git a/deps/v8/src/runtime/runtime.h b/deps/v8/src/runtime/runtime.h
index 37ce74e825..184b9c5ca4 100644
--- a/deps/v8/src/runtime/runtime.h
+++ b/deps/v8/src/runtime/runtime.h
@@ -433,7 +433,9 @@ namespace internal {
F(PromiseRevokeReject, 1, 1) \
F(PromiseStatus, 1, 1) \
F(RejectPromise, 3, 1) \
- F(ResolvePromise, 2, 1)
+ F(ResolvePromise, 2, 1) \
+ F(PromiseRejectAfterResolved, 2, 1) \
+ F(PromiseResolveAfterResolved, 2, 1)
#define FOR_EACH_INTRINSIC_PROXY(F) \
F(CheckProxyGetSetTrapResult, 2, 1) \
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc
index 637dc7d206..793711fa80 100644
--- a/deps/v8/test/cctest/test-api.cc
+++ b/deps/v8/test/cctest/test-api.cc
@@ -17625,6 +17625,8 @@ TEST(RethrowBogusErrorStackTrace) {
v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
int promise_reject_counter = 0;
int promise_revoke_counter = 0;
+int promise_reject_after_resolved_counter = 0;
+int promise_resolve_after_resolved_counter = 0;
int promise_reject_msg_line_number = -1;
int promise_reject_msg_column_number = -1;
int promise_reject_line_number = -1;
@@ -17634,40 +17636,56 @@ int promise_reject_frame_count = -1;
void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
v8::Local<v8::Object> global = CcTest::global();
v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
- CHECK_EQ(v8::Promise::PromiseState::kRejected,
+ CHECK_NE(v8::Promise::PromiseState::kPending,
reject_message.GetPromise()->State());
- if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
- promise_reject_counter++;
- global->Set(context, v8_str("rejected"), reject_message.GetPromise())
- .FromJust();
- global->Set(context, v8_str("value"), reject_message.GetValue()).FromJust();
- v8::Local<v8::Message> message = v8::Exception::CreateMessage(
- CcTest::isolate(), reject_message.GetValue());
- v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
-
- promise_reject_msg_line_number = message->GetLineNumber(context).FromJust();
- promise_reject_msg_column_number =
- message->GetStartColumn(context).FromJust() + 1;
-
- if (!stack_trace.IsEmpty()) {
- promise_reject_frame_count = stack_trace->GetFrameCount();
- if (promise_reject_frame_count > 0) {
- CHECK(stack_trace->GetFrame(0)
- ->GetScriptName()
- ->Equals(context, v8_str("pro"))
- .FromJust());
- promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
- promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
- } else {
- promise_reject_line_number = -1;
- promise_reject_column_number = -1;
+ switch (reject_message.GetEvent()) {
+ case v8::kPromiseRejectWithNoHandler: {
+ promise_reject_counter++;
+ global->Set(context, v8_str("rejected"), reject_message.GetPromise())
+ .FromJust();
+ global->Set(context, v8_str("value"), reject_message.GetValue())
+ .FromJust();
+ v8::Local<v8::Message> message = v8::Exception::CreateMessage(
+ CcTest::isolate(), reject_message.GetValue());
+ v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
+
+ promise_reject_msg_line_number =
+ message->GetLineNumber(context).FromJust();
+ promise_reject_msg_column_number =
+ message->GetStartColumn(context).FromJust() + 1;
+
+ if (!stack_trace.IsEmpty()) {
+ promise_reject_frame_count = stack_trace->GetFrameCount();
+ if (promise_reject_frame_count > 0) {
+ CHECK(stack_trace->GetFrame(0)
+ ->GetScriptName()
+ ->Equals(context, v8_str("pro"))
+ .FromJust());
+ promise_reject_line_number =
+ stack_trace->GetFrame(0)->GetLineNumber();
+ promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
+ } else {
+ promise_reject_line_number = -1;
+ promise_reject_column_number = -1;
+ }
}
+ break;
+ }
+ case v8::kPromiseHandlerAddedAfterReject: {
+ promise_revoke_counter++;
+ global->Set(context, v8_str("revoked"), reject_message.GetPromise())
+ .FromJust();
+ CHECK(reject_message.GetValue().IsEmpty());
+ break;
+ }
+ case v8::kPromiseRejectAfterResolved: {
+ promise_reject_after_resolved_counter++;
+ break;
+ }
+ case v8::kPromiseResolveAfterResolved: {
+ promise_resolve_after_resolved_counter++;
+ break;
}
- } else {
- promise_revoke_counter++;
- global->Set(context, v8_str("revoked"), reject_message.GetPromise())
- .FromJust();
- CHECK(reject_message.GetValue().IsEmpty());
}
}
@@ -17690,6 +17708,8 @@ v8::Local<v8::Value> RejectValue() {
void ResetPromiseStates() {
promise_reject_counter = 0;
promise_revoke_counter = 0;
+ promise_reject_after_resolved_counter = 0;
+ promise_resolve_after_resolved_counter = 0;
promise_reject_msg_line_number = -1;
promise_reject_msg_column_number = -1;
promise_reject_line_number = -1;
@@ -17915,6 +17935,40 @@ TEST(PromiseRejectCallback) {
CHECK_EQ(0, promise_revoke_counter);
CHECK(RejectValue()->Equals(env.local(), v8_str("sss")).FromJust());
+ ResetPromiseStates();
+
+ // Swallowed exceptions in the Promise constructor.
+ CompileRun(
+ "var v0 = new Promise(\n"
+ " function(res, rej) {\n"
+ " res(1);\n"
+ " throw new Error();\n"
+ " }\n"
+ ");\n");
+ CHECK(!GetPromise("v0")->HasHandler());
+ CHECK_EQ(0, promise_reject_counter);
+ CHECK_EQ(0, promise_revoke_counter);
+ CHECK_EQ(1, promise_reject_after_resolved_counter);
+ CHECK_EQ(0, promise_resolve_after_resolved_counter);
+
+ ResetPromiseStates();
+
+ // Duplication resolve.
+ CompileRun(
+ "var r;\n"
+ "var y0 = new Promise(\n"
+ " function(res, rej) {\n"
+ " r = res;\n"
+ " throw new Error();\n"
+ " }\n"
+ ");\n"
+ "r(1);\n");
+ CHECK(!GetPromise("y0")->HasHandler());
+ CHECK_EQ(1, promise_reject_counter);
+ CHECK_EQ(0, promise_revoke_counter);
+ CHECK_EQ(0, promise_reject_after_resolved_counter);
+ CHECK_EQ(1, promise_resolve_after_resolved_counter);
+
// Test stack frames.
env->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);