[wasm][stack-switching] Support rejected promises

If the returned promise rejects, we switch to the suspender's stack and
throw the value.
Re-purpose the WasmOnFulfilled data to also represent the rejecting
case and rename it to WasmResumeData.

R=ahaas@chromium.org
CC=fgm@chromium.org

Bug: v8:12191
Change-Id: I91a301c3c6d9d243efbfabe7263555e11f0d9277
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3706606
Reviewed-by: Omer Katz <omerkatz@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81325}
This commit is contained in:
Thibaud Michaud 2022-06-21 16:52:09 +02:00 committed by V8 LUCI CQ
parent 6b4850484f
commit e35039e773
27 changed files with 150 additions and 59 deletions

View File

@ -2784,6 +2784,11 @@ void Builtins::Generate_WasmResume(MacroAssembler* masm) {
__ Trap(); __ Trap();
} }
void Builtins::Generate_WasmReject(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) { void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64. // Only needed on x64.
__ Trap(); __ Trap();

View File

@ -3175,6 +3175,11 @@ void Builtins::Generate_WasmResume(MacroAssembler* masm) {
__ Trap(); __ Trap();
} }
void Builtins::Generate_WasmReject(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) { void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64. // Only needed on x64.
__ Trap(); __ Trap();

View File

@ -966,6 +966,7 @@ namespace internal {
IF_WASM(ASM, WasmReturnPromiseOnSuspend, WasmDummy) \ IF_WASM(ASM, WasmReturnPromiseOnSuspend, WasmDummy) \
IF_WASM(ASM, WasmSuspend, WasmSuspend) \ IF_WASM(ASM, WasmSuspend, WasmSuspend) \
IF_WASM(ASM, WasmResume, WasmDummy) \ IF_WASM(ASM, WasmResume, WasmDummy) \
IF_WASM(ASM, WasmReject, WasmDummy) \
IF_WASM(ASM, WasmCompileLazy, WasmDummy) \ IF_WASM(ASM, WasmCompileLazy, WasmDummy) \
IF_WASM(ASM, WasmDebugBreak, WasmDummy) \ IF_WASM(ASM, WasmDebugBreak, WasmDummy) \
IF_WASM(ASM, WasmOnStackReplace, WasmDummy) \ IF_WASM(ASM, WasmOnStackReplace, WasmDummy) \

View File

@ -3032,6 +3032,11 @@ void Builtins::Generate_WasmResume(MacroAssembler* masm) {
__ Trap(); __ Trap();
} }
void Builtins::Generate_WasmReject(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) { void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64. // Only needed on x64.
__ Trap(); __ Trap();

View File

@ -4116,8 +4116,12 @@ void Builtins::Generate_WasmSuspend(MacroAssembler* masm) {
__ ret(0); __ ret(0);
} }
// Resume the suspender stored in the closure. namespace {
void Builtins::Generate_WasmResume(MacroAssembler* masm) { // Resume the suspender stored in the closure. We generate two variants of this
// builtin: the onFulfilled variant resumes execution at the saved PC and
// forwards the value, the onRejected variant throws the value.
void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) {
__ EnterFrame(StackFrame::STACK_SWITCH); __ EnterFrame(StackFrame::STACK_SWITCH);
Register param_count = rax; Register param_count = rax;
@ -4152,8 +4156,7 @@ void Builtins::Generate_WasmResume(MacroAssembler* masm) {
FieldOperand(sfi, SharedFunctionInfo::kFunctionDataOffset)); FieldOperand(sfi, SharedFunctionInfo::kFunctionDataOffset));
Register suspender = rax; Register suspender = rax;
__ LoadAnyTaggedField( __ LoadAnyTaggedField(
suspender, suspender, FieldOperand(function_data, WasmResumeData::kSuspenderOffset));
FieldOperand(function_data, WasmOnFulfilledData::kSuspenderOffset));
// Check the suspender state. // Check the suspender state.
Label suspender_is_suspended; Label suspender_is_suspended;
Register state = rdx; Register state = rdx;
@ -4232,12 +4235,30 @@ void Builtins::Generate_WasmResume(MacroAssembler* masm) {
// Move resolved value to return register. // Move resolved value to return register.
__ movq(kReturnRegister0, Operand(rbp, 3 * kSystemPointerSize)); __ movq(kReturnRegister0, Operand(rbp, 3 * kSystemPointerSize));
__ Move(GCScanSlotPlace, 0); __ Move(GCScanSlotPlace, 0);
LoadJumpBuffer(masm, target_jmpbuf, true); if (on_resume == wasm::OnResume::kThrow) {
// Switch to the continuation's stack without restoring the PC.
LoadJumpBuffer(masm, target_jmpbuf, false);
// Forward the onRejected value to kThrow.
__ pushq(kReturnRegister0);
__ CallRuntime(Runtime::kThrow);
} else {
// Resume the continuation normally.
LoadJumpBuffer(masm, target_jmpbuf, true);
}
__ Trap(); __ Trap();
__ bind(&suspend); __ bind(&suspend);
__ LeaveFrame(StackFrame::STACK_SWITCH); __ LeaveFrame(StackFrame::STACK_SWITCH);
__ ret(3); __ ret(3);
} }
} // namespace
void Builtins::Generate_WasmResume(MacroAssembler* masm) {
Generate_WasmResumeHelper(masm, wasm::OnResume::kContinue);
}
void Builtins::Generate_WasmReject(MacroAssembler* masm) {
Generate_WasmResumeHelper(masm, wasm::OnResume::kThrow);
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) { void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
MemOperand OSRTargetSlot(rbp, -wasm::kOSRTargetOffset); MemOperand OSRTargetSlot(rbp, -wasm::kOSRTargetOffset);

View File

@ -14740,7 +14740,7 @@ TNode<CodeT> CodeStubAssembler::GetSharedFunctionInfoCode(
WASM_EXPORTED_FUNCTION_DATA_TYPE, WASM_EXPORTED_FUNCTION_DATA_TYPE,
WASM_JS_FUNCTION_DATA_TYPE, WASM_JS_FUNCTION_DATA_TYPE,
ASM_WASM_DATA_TYPE, ASM_WASM_DATA_TYPE,
WASM_ON_FULFILLED_DATA_TYPE, WASM_RESUME_DATA_TYPE,
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
}; };
Label check_is_bytecode_array(this); Label check_is_bytecode_array(this);
@ -14750,7 +14750,7 @@ TNode<CodeT> CodeStubAssembler::GetSharedFunctionInfoCode(
Label check_is_function_template_info(this); Label check_is_function_template_info(this);
Label check_is_interpreter_data(this); Label check_is_interpreter_data(this);
Label check_is_wasm_function_data(this); Label check_is_wasm_function_data(this);
Label check_is_wasm_on_fulfilled(this); Label check_is_wasm_resume(this);
Label* case_labels[] = { Label* case_labels[] = {
&check_is_bytecode_array, &check_is_bytecode_array,
&check_is_baseline_data, &check_is_baseline_data,
@ -14764,7 +14764,7 @@ TNode<CodeT> CodeStubAssembler::GetSharedFunctionInfoCode(
&check_is_wasm_function_data, &check_is_wasm_function_data,
&check_is_wasm_function_data, &check_is_wasm_function_data,
&check_is_asm_wasm_data, &check_is_asm_wasm_data,
&check_is_wasm_on_fulfilled, &check_is_wasm_resume,
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
}; };
static_assert(arraysize(case_values) == arraysize(case_labels)); static_assert(arraysize(case_values) == arraysize(case_labels));
@ -14819,8 +14819,8 @@ TNode<CodeT> CodeStubAssembler::GetSharedFunctionInfoCode(
sfi_code = HeapConstant(BUILTIN_CODE(isolate(), InstantiateAsmJs)); sfi_code = HeapConstant(BUILTIN_CODE(isolate(), InstantiateAsmJs));
Goto(&done); Goto(&done);
// IsWasmOnFulfilledData: Resume the suspended wasm continuation. // IsWasmResumeData: Resume the suspended wasm continuation.
BIND(&check_is_wasm_on_fulfilled); BIND(&check_is_wasm_resume);
sfi_code = HeapConstant(BUILTIN_CODE(isolate(), WasmResume)); sfi_code = HeapConstant(BUILTIN_CODE(isolate(), WasmResume));
Goto(&done); Goto(&done);
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY

View File

@ -950,7 +950,7 @@ void SharedFunctionInfo::SharedFunctionInfoVerify(ReadOnlyRoots roots) {
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
bool is_wasm = HasWasmExportedFunctionData() || HasAsmWasmData() || bool is_wasm = HasWasmExportedFunctionData() || HasAsmWasmData() ||
HasWasmJSFunctionData() || HasWasmCapiFunctionData() || HasWasmJSFunctionData() || HasWasmCapiFunctionData() ||
HasWasmOnFulfilledData(); HasWasmResumeData();
#else #else
bool is_wasm = false; bool is_wasm = false;
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY

View File

@ -2053,8 +2053,8 @@ void WasmJSFunctionData::WasmJSFunctionDataPrint(std::ostream& os) {
os << "\n"; os << "\n";
} }
void WasmOnFulfilledData::WasmOnFulfilledDataPrint(std::ostream& os) { void WasmResumeData::WasmResumeDataPrint(std::ostream& os) {
PrintHeader(os, "WasmOnFulfilledData"); PrintHeader(os, "WasmResumeData");
os << "\n - suspender: " << Brief(suspender()); os << "\n - suspender: " << Brief(suspender());
os << '\n'; os << '\n';
} }

View File

@ -1600,14 +1600,14 @@ Handle<WasmJSFunctionData> Factory::NewWasmJSFunctionData(
return handle(result, isolate()); return handle(result, isolate());
} }
Handle<WasmOnFulfilledData> Factory::NewWasmOnFulfilledData( Handle<WasmResumeData> Factory::NewWasmResumeData(
Handle<WasmSuspenderObject> suspender) { Handle<WasmSuspenderObject> suspender, wasm::OnResume on_resume) {
Map map = *wasm_onfulfilled_data_map(); Map map = *wasm_resume_data_map();
WasmOnFulfilledData result = WasmResumeData result = WasmResumeData::cast(AllocateRawWithImmortalMap(
WasmOnFulfilledData::cast(AllocateRawWithImmortalMap( map.instance_size(), AllocationType::kOld, map));
map.instance_size(), AllocationType::kOld, map));
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
result.set_suspender(*suspender); result.set_suspender(*suspender);
result.set_on_resume(static_cast<int>(on_resume));
return handle(result, isolate()); return handle(result, isolate());
} }
@ -1776,8 +1776,8 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForWasmJSFunction(
return NewSharedFunctionInfo(name, data, Builtin::kNoBuiltinId); return NewSharedFunctionInfo(name, data, Builtin::kNoBuiltinId);
} }
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForWasmOnFulfilled( Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForWasmResume(
Handle<WasmOnFulfilledData> data) { Handle<WasmResumeData> data) {
return NewSharedFunctionInfo({}, data, Builtin::kNoBuiltinId); return NewSharedFunctionInfo({}, data, Builtin::kNoBuiltinId);
} }

View File

@ -78,6 +78,7 @@ class ArrayType;
class StructType; class StructType;
struct WasmElemSegment; struct WasmElemSegment;
class WasmValue; class WasmValue;
enum class OnResume : int;
} // namespace wasm } // namespace wasm
#endif #endif
@ -638,8 +639,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
int parameter_count, Handle<PodArray<wasm::ValueType>> serialized_sig, int parameter_count, Handle<PodArray<wasm::ValueType>> serialized_sig,
Handle<CodeT> wrapper_code, Handle<Map> rtt, Handle<CodeT> wrapper_code, Handle<Map> rtt,
Handle<HeapObject> suspender); Handle<HeapObject> suspender);
Handle<WasmOnFulfilledData> NewWasmOnFulfilledData( Handle<WasmResumeData> NewWasmResumeData(
Handle<WasmSuspenderObject> suspender); Handle<WasmSuspenderObject> suspender, wasm::OnResume on_resume);
Handle<WasmStruct> NewWasmStruct(const wasm::StructType* type, Handle<WasmStruct> NewWasmStruct(const wasm::StructType* type,
wasm::WasmValue* args, Handle<Map> map); wasm::WasmValue* args, Handle<Map> map);
Handle<WasmArray> NewWasmArrayFromElements( Handle<WasmArray> NewWasmArrayFromElements(
@ -657,8 +658,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
Handle<String> name, Handle<WasmExportedFunctionData> data); Handle<String> name, Handle<WasmExportedFunctionData> data);
Handle<SharedFunctionInfo> NewSharedFunctionInfoForWasmJSFunction( Handle<SharedFunctionInfo> NewSharedFunctionInfoForWasmJSFunction(
Handle<String> name, Handle<WasmJSFunctionData> data); Handle<String> name, Handle<WasmJSFunctionData> data);
Handle<SharedFunctionInfo> NewSharedFunctionInfoForWasmOnFulfilled( Handle<SharedFunctionInfo> NewSharedFunctionInfoForWasmResume(
Handle<WasmOnFulfilledData> data); Handle<WasmResumeData> data);
Handle<SharedFunctionInfo> NewSharedFunctionInfoForWasmCapiFunction( Handle<SharedFunctionInfo> NewSharedFunctionInfoForWasmCapiFunction(
Handle<WasmCapiFunctionData> data); Handle<WasmCapiFunctionData> data);
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY

View File

@ -67,7 +67,7 @@ namespace internal {
IF_WASM(V, WasmJSFunctionData) \ IF_WASM(V, WasmJSFunctionData) \
IF_WASM(V, WasmStruct) \ IF_WASM(V, WasmStruct) \
IF_WASM(V, WasmSuspenderObject) \ IF_WASM(V, WasmSuspenderObject) \
IF_WASM(V, WasmOnFulfilledData) \ IF_WASM(V, WasmResumeData) \
IF_WASM(V, WasmTypeInfo) IF_WASM(V, WasmTypeInfo)
#define FORWARD_DECLARE(TypeName) class TypeName; #define FORWARD_DECLARE(TypeName) class TypeName;

View File

@ -517,8 +517,8 @@ bool Heap::CreateInitialMaps() {
WasmInternalFunction::kSize, wasm_internal_function) WasmInternalFunction::kSize, wasm_internal_function)
IF_WASM(ALLOCATE_MAP, WASM_JS_FUNCTION_DATA_TYPE, WasmJSFunctionData::kSize, IF_WASM(ALLOCATE_MAP, WASM_JS_FUNCTION_DATA_TYPE, WasmJSFunctionData::kSize,
wasm_js_function_data) wasm_js_function_data)
IF_WASM(ALLOCATE_MAP, WASM_ON_FULFILLED_DATA_TYPE, IF_WASM(ALLOCATE_MAP, WASM_RESUME_DATA_TYPE, WasmResumeData::kSize,
WasmOnFulfilledData::kSize, wasm_onfulfilled_data) wasm_resume_data)
IF_WASM(ALLOCATE_MAP, WASM_TYPE_INFO_TYPE, kVariableSizeSentinel, IF_WASM(ALLOCATE_MAP, WASM_TYPE_INFO_TYPE, kVariableSizeSentinel,
wasm_type_info) wasm_type_info)

View File

@ -393,8 +393,8 @@ VisitorId Map::GetVisitorId(Map map) {
return kVisitWasmInternalFunction; return kVisitWasmInternalFunction;
case WASM_JS_FUNCTION_DATA_TYPE: case WASM_JS_FUNCTION_DATA_TYPE:
return kVisitWasmJSFunctionData; return kVisitWasmJSFunctionData;
case WASM_ON_FULFILLED_DATA_TYPE: case WASM_RESUME_DATA_TYPE:
return kVisitWasmOnFulfilledData; return kVisitWasmResumeData;
case WASM_API_FUNCTION_REF_TYPE: case WASM_API_FUNCTION_REF_TYPE:
return kVisitWasmApiFunctionRef; return kVisitWasmApiFunctionRef;
case WASM_EXPORTED_FUNCTION_DATA_TYPE: case WASM_EXPORTED_FUNCTION_DATA_TYPE:

View File

@ -83,7 +83,7 @@ enum InstanceType : uint16_t;
IF_WASM(V, WasmInstanceObject) \ IF_WASM(V, WasmInstanceObject) \
IF_WASM(V, WasmInternalFunction) \ IF_WASM(V, WasmInternalFunction) \
IF_WASM(V, WasmJSFunctionData) \ IF_WASM(V, WasmJSFunctionData) \
IF_WASM(V, WasmOnFulfilledData) \ IF_WASM(V, WasmResumeData) \
IF_WASM(V, WasmStruct) \ IF_WASM(V, WasmStruct) \
IF_WASM(V, WasmSuspenderObject) \ IF_WASM(V, WasmSuspenderObject) \
IF_WASM(V, WasmTypeInfo) \ IF_WASM(V, WasmTypeInfo) \

View File

@ -258,7 +258,7 @@ class ZoneForwardList;
IF_WASM(V, WasmMemoryObject) \ IF_WASM(V, WasmMemoryObject) \
IF_WASM(V, WasmModuleObject) \ IF_WASM(V, WasmModuleObject) \
IF_WASM(V, WasmObject) \ IF_WASM(V, WasmObject) \
IF_WASM(V, WasmOnFulfilledData) \ IF_WASM(V, WasmResumeData) \
IF_WASM(V, WasmStruct) \ IF_WASM(V, WasmStruct) \
IF_WASM(V, WasmTypeInfo) \ IF_WASM(V, WasmTypeInfo) \
IF_WASM(V, WasmTableObject) \ IF_WASM(V, WasmTableObject) \

View File

@ -1172,8 +1172,8 @@ auto BodyDescriptorApply(InstanceType type, Args&&... args) {
return CALL_APPLY(WasmInternalFunction); return CALL_APPLY(WasmInternalFunction);
case WASM_JS_FUNCTION_DATA_TYPE: case WASM_JS_FUNCTION_DATA_TYPE:
return CALL_APPLY(WasmJSFunctionData); return CALL_APPLY(WasmJSFunctionData);
case WASM_ON_FULFILLED_DATA_TYPE: case WASM_RESUME_DATA_TYPE:
return CALL_APPLY(WasmOnFulfilledData); return CALL_APPLY(WasmResumeData);
case WASM_STRUCT_TYPE: case WASM_STRUCT_TYPE:
return CALL_APPLY(WasmStruct); return CALL_APPLY(WasmStruct);
case WASM_TYPE_INFO_TYPE: case WASM_TYPE_INFO_TYPE:

View File

@ -711,8 +711,8 @@ bool SharedFunctionInfo::HasWasmCapiFunctionData() const {
return function_data(kAcquireLoad).IsWasmCapiFunctionData(); return function_data(kAcquireLoad).IsWasmCapiFunctionData();
} }
bool SharedFunctionInfo::HasWasmOnFulfilledData() const { bool SharedFunctionInfo::HasWasmResumeData() const {
return function_data(kAcquireLoad).IsWasmOnFulfilledData(); return function_data(kAcquireLoad).IsWasmResumeData();
} }
AsmWasmData SharedFunctionInfo::asm_wasm_data() const { AsmWasmData SharedFunctionInfo::asm_wasm_data() const {

View File

@ -108,8 +108,13 @@ CodeT SharedFunctionInfo::GetCode() const {
if (data.IsWasmCapiFunctionData()) { if (data.IsWasmCapiFunctionData()) {
return wasm_capi_function_data().wrapper_code(); return wasm_capi_function_data().wrapper_code();
} }
if (data.IsWasmOnFulfilledData()) { if (data.IsWasmResumeData()) {
return isolate->builtins()->code(Builtin::kWasmResume); if (static_cast<wasm::OnResume>(wasm_resume_data().on_resume()) ==
wasm::OnResume::kContinue) {
return isolate->builtins()->code(Builtin::kWasmResume);
} else {
return isolate->builtins()->code(Builtin::kWasmReject);
}
} }
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
if (data.IsUncompiledData()) { if (data.IsUncompiledData()) {
@ -147,6 +152,11 @@ WasmCapiFunctionData SharedFunctionInfo::wasm_capi_function_data() const {
DCHECK(HasWasmCapiFunctionData()); DCHECK(HasWasmCapiFunctionData());
return WasmCapiFunctionData::cast(function_data(kAcquireLoad)); return WasmCapiFunctionData::cast(function_data(kAcquireLoad));
} }
WasmResumeData SharedFunctionInfo::wasm_resume_data() const {
DCHECK(HasWasmResumeData());
return WasmResumeData::cast(function_data(kAcquireLoad));
}
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
SharedFunctionInfo::ScriptIterator::ScriptIterator(Isolate* isolate, SharedFunctionInfo::ScriptIterator::ScriptIterator(Isolate* isolate,

View File

@ -40,6 +40,7 @@ class Signature;
class WasmCapiFunctionData; class WasmCapiFunctionData;
class WasmExportedFunctionData; class WasmExportedFunctionData;
class WasmJSFunctionData; class WasmJSFunctionData;
class WasmResumeData;
namespace wasm { namespace wasm {
struct WasmModule; struct WasmModule;
@ -347,7 +348,7 @@ class SharedFunctionInfo
inline bool HasWasmExportedFunctionData() const; inline bool HasWasmExportedFunctionData() const;
inline bool HasWasmJSFunctionData() const; inline bool HasWasmJSFunctionData() const;
inline bool HasWasmCapiFunctionData() const; inline bool HasWasmCapiFunctionData() const;
inline bool HasWasmOnFulfilledData() const; inline bool HasWasmResumeData() const;
inline AsmWasmData asm_wasm_data() const; inline AsmWasmData asm_wasm_data() const;
inline void set_asm_wasm_data(AsmWasmData data); inline void set_asm_wasm_data(AsmWasmData data);
@ -355,6 +356,7 @@ class SharedFunctionInfo
wasm_exported_function_data() const; wasm_exported_function_data() const;
WasmJSFunctionData wasm_js_function_data() const; WasmJSFunctionData wasm_js_function_data() const;
WasmCapiFunctionData wasm_capi_function_data() const; WasmCapiFunctionData wasm_capi_function_data() const;
WasmResumeData wasm_resume_data() const;
inline const wasm::WasmModule* wasm_module() const; inline const wasm::WasmModule* wasm_module() const;
inline const wasm::FunctionSig* wasm_function_signature() const; inline const wasm::FunctionSig* wasm_function_signature() const;

View File

@ -120,7 +120,7 @@ class Symbol;
WasmExportedFunctionDataMap) \ WasmExportedFunctionDataMap) \
IF_WASM(V, Map, wasm_internal_function_map, WasmInternalFunctionMap) \ IF_WASM(V, Map, wasm_internal_function_map, WasmInternalFunctionMap) \
IF_WASM(V, Map, wasm_js_function_data_map, WasmJSFunctionDataMap) \ IF_WASM(V, Map, wasm_js_function_data_map, WasmJSFunctionDataMap) \
IF_WASM(V, Map, wasm_onfulfilled_data_map, WasmOnFulfilledDataMap) \ IF_WASM(V, Map, wasm_resume_data_map, WasmResumeDataMap) \
IF_WASM(V, Map, wasm_type_info_map, WasmTypeInfoMap) \ IF_WASM(V, Map, wasm_type_info_map, WasmTypeInfoMap) \
V(Map, weak_fixed_array_map, WeakFixedArrayMap) \ V(Map, weak_fixed_array_map, WeakFixedArrayMap) \
V(Map, weak_array_list_map, WeakArrayListMap) \ V(Map, weak_array_list_map, WeakArrayListMap) \

View File

@ -832,15 +832,16 @@ RUNTIME_FUNCTION(Runtime_WasmSyncStackLimit) {
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
// Takes a promise and a suspender, and returns promise.then(onFulfilled), where // Takes a promise and a suspender, and returns
// onFulfilled resumes the suspender. // promise.then(suspender.resume(), suspender.reject());
RUNTIME_FUNCTION(Runtime_WasmCreateResumePromise) { RUNTIME_FUNCTION(Runtime_WasmCreateResumePromise) {
CHECK(FLAG_experimental_wasm_stack_switching); CHECK(FLAG_experimental_wasm_stack_switching);
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<Object> promise = args.at(0); Handle<Object> promise = args.at(0);
Handle<WasmSuspenderObject> suspender = args.at<WasmSuspenderObject>(1); Handle<WasmSuspenderObject> suspender = args.at<WasmSuspenderObject>(1);
i::Handle<i::Object> argv[] = {handle(suspender->resume(), isolate)}; i::Handle<i::Object> argv[] = {handle(suspender->resume(), isolate),
handle(suspender->reject(), isolate)};
i::Handle<i::Object> result; i::Handle<i::Object> result;
bool has_pending_exception = bool has_pending_exception =
!i::Execution::CallBuiltin(isolate, isolate->promise_then(), promise, !i::Execution::CallBuiltin(isolate, isolate->promise_then(), promise,

View File

@ -55,7 +55,7 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(WasmStruct)
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmArray) TQ_OBJECT_CONSTRUCTORS_IMPL(WasmArray)
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmContinuationObject) TQ_OBJECT_CONSTRUCTORS_IMPL(WasmContinuationObject)
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmSuspenderObject) TQ_OBJECT_CONSTRUCTORS_IMPL(WasmSuspenderObject)
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmOnFulfilledData) TQ_OBJECT_CONSTRUCTORS_IMPL(WasmResumeData)
CAST_ACCESSOR(WasmInstanceObject) CAST_ACCESSOR(WasmInstanceObject)

View File

@ -1807,15 +1807,22 @@ Handle<WasmSuspenderObject> WasmSuspenderObject::New(Isolate* isolate) {
suspender->set_state(kInactive); suspender->set_state(kInactive);
// Instantiate the callable object which resumes this Suspender. This will be // Instantiate the callable object which resumes this Suspender. This will be
// used implicitly as the onFulfilled callback of the returned JS promise. // used implicitly as the onFulfilled callback of the returned JS promise.
Handle<WasmOnFulfilledData> function_data = Handle<WasmResumeData> resume_data = isolate->factory()->NewWasmResumeData(
isolate->factory()->NewWasmOnFulfilledData(suspender); suspender, wasm::OnResume::kContinue);
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo> resume_sfi =
isolate->factory()->NewSharedFunctionInfoForWasmOnFulfilled( isolate->factory()->NewSharedFunctionInfoForWasmResume(resume_data);
function_data);
Handle<Context> context(isolate->native_context()); Handle<Context> context(isolate->native_context());
Handle<JSObject> resume = Handle<JSObject> resume =
Factory::JSFunctionBuilder{isolate, shared, context}.Build(); Factory::JSFunctionBuilder{isolate, resume_sfi, context}.Build();
Handle<WasmResumeData> reject_data =
isolate->factory()->NewWasmResumeData(suspender, wasm::OnResume::kThrow);
Handle<SharedFunctionInfo> reject_sfi =
isolate->factory()->NewSharedFunctionInfoForWasmResume(reject_data);
Handle<JSObject> reject =
Factory::JSFunctionBuilder{isolate, reject_sfi, context}.Build();
suspender->set_resume(*resume); suspender->set_resume(*resume);
suspender->set_reject(*reject);
return suspender; return suspender;
} }

View File

@ -787,14 +787,17 @@ class WasmCapiFunctionData
TQ_OBJECT_CONSTRUCTORS(WasmCapiFunctionData) TQ_OBJECT_CONSTRUCTORS(WasmCapiFunctionData)
}; };
class WasmOnFulfilledData namespace wasm {
: public TorqueGeneratedWasmOnFulfilledData<WasmOnFulfilledData, enum class OnResume : int { kContinue, kThrow };
HeapObject> { }
class WasmResumeData
: public TorqueGeneratedWasmResumeData<WasmResumeData, HeapObject> {
public: public:
using BodyDescriptor = using BodyDescriptor =
FlexibleBodyDescriptor<WasmOnFulfilledData::kStartOfStrongFieldsOffset>; FlexibleBodyDescriptor<WasmResumeData::kStartOfStrongFieldsOffset>;
DECL_PRINTER(WasmOnFulfilledData) DECL_PRINTER(WasmResumeData)
TQ_OBJECT_CONSTRUCTORS(WasmOnFulfilledData) TQ_OBJECT_CONSTRUCTORS(WasmResumeData)
}; };
class WasmScript : public AllStatic { class WasmScript : public AllStatic {

View File

@ -80,8 +80,9 @@ extern class WasmCapiFunctionData extends WasmFunctionData {
serialized_signature: PodArrayOfWasmValueType; serialized_signature: PodArrayOfWasmValueType;
} }
extern class WasmOnFulfilledData extends HeapObject { extern class WasmResumeData extends HeapObject {
suspender: WasmSuspenderObject; suspender: WasmSuspenderObject;
on_resume: Smi; // See wasm::OnResume enum.
} }
extern class WasmIndirectFunctionTable extends Struct { extern class WasmIndirectFunctionTable extends Struct {
@ -104,6 +105,7 @@ extern class WasmSuspenderObject extends JSObject {
continuation: WasmContinuationObject|Undefined; continuation: WasmContinuationObject|Undefined;
parent: WasmSuspenderObject|Undefined; parent: WasmSuspenderObject|Undefined;
resume: JSObject|Undefined; resume: JSObject|Undefined;
reject: JSObject|Undefined;
state: Smi; // 0: Inactive, 1: Active, 2: Suspended. state: Smi; // 0: Inactive, 1: Active, 2: Suspended.
} }

View File

@ -295,3 +295,31 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let combined_promise = wrapped_export(); let combined_promise = wrapped_export();
assertThrowsAsync(combined_promise, WebAssembly.Exception); assertThrowsAsync(combined_promise, WebAssembly.Exception);
})(); })();
(function TestStackSwitchPromiseReject() {
print(arguments.callee.name);
let tag = new WebAssembly.Tag({parameters: ['i32']});
let builder = new WasmModuleBuilder();
import_index = builder.addImport('m', 'import', kSig_i_v);
tag_index = builder.addImportedTag('m', 'tag', kSig_v_i);
builder.addFunction("test", kSig_i_v)
.addBody([
kExprTry, kWasmI32,
kExprCallFunction, import_index,
kExprCatch, tag_index,
kExprEnd,
]).exportFunc();
let suspender = new WebAssembly.Suspender();
function js_import() {
return Promise.reject(new WebAssembly.Exception(tag, [42]));
};
let wasm_js_import = new WebAssembly.Function(
{parameters: [], results: ['externref']}, js_import);
let suspending_wasm_js_import =
suspender.suspendOnReturnedPromise(wasm_js_import);
let instance = builder.instantiate({m: {import: suspending_wasm_js_import, tag: tag}});
let wrapped_export = suspender.returnPromiseOnSuspend(instance.exports.test);
let combined_promise = wrapped_export();
assertPromiseResult(combined_promise, v => assertEquals(v, 42));
})();

View File

@ -167,7 +167,7 @@ INSTANCE_TYPES = {
260: "SORT_STATE_TYPE", 260: "SORT_STATE_TYPE",
261: "SWISS_NAME_DICTIONARY_TYPE", 261: "SWISS_NAME_DICTIONARY_TYPE",
262: "WASM_API_FUNCTION_REF_TYPE", 262: "WASM_API_FUNCTION_REF_TYPE",
263: "WASM_ON_FULFILLED_DATA_TYPE", 263: "WASM_RESUME_DATA_TYPE",
264: "WEAK_ARRAY_LIST_TYPE", 264: "WEAK_ARRAY_LIST_TYPE",
265: "WEAK_CELL_TYPE", 265: "WEAK_CELL_TYPE",
266: "WASM_ARRAY_TYPE", 266: "WASM_ARRAY_TYPE",
@ -353,7 +353,7 @@ KNOWN_MAPS = {
("read_only_space", 0x02f51): (223, "WasmExportedFunctionDataMap"), ("read_only_space", 0x02f51): (223, "WasmExportedFunctionDataMap"),
("read_only_space", 0x02f79): (205, "WasmInternalFunctionMap"), ("read_only_space", 0x02f79): (205, "WasmInternalFunctionMap"),
("read_only_space", 0x02fa1): (224, "WasmJSFunctionDataMap"), ("read_only_space", 0x02fa1): (224, "WasmJSFunctionDataMap"),
("read_only_space", 0x02fc9): (263, "WasmOnFulfilledDataMap"), ("read_only_space", 0x02fc9): (263, "WasmResumeDataMap"),
("read_only_space", 0x02ff1): (206, "WasmTypeInfoMap"), ("read_only_space", 0x02ff1): (206, "WasmTypeInfoMap"),
("read_only_space", 0x03019): (235, "WeakFixedArrayMap"), ("read_only_space", 0x03019): (235, "WeakFixedArrayMap"),
("read_only_space", 0x03041): (179, "EphemeronHashTableMap"), ("read_only_space", 0x03041): (179, "EphemeronHashTableMap"),