diff --git a/.gitignore b/.gitignore index d32fe4df470e..7f9c4ce17fd9 100644 --- a/.gitignore +++ b/.gitignore @@ -116,5 +116,7 @@ doc/api/ build/ build-sdk-debug.sh build-sdk.sh +build-fiber-test.sh *.exe -*.aot \ No newline at end of file +*.aot +*.S \ No newline at end of file diff --git a/runtime/lib/fiber.cc b/runtime/lib/fiber.cc index 94af8388eecf..0f6e9e19cebf 100644 --- a/runtime/lib/fiber.cc +++ b/runtime/lib/fiber.cc @@ -2,17 +2,24 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +#include +#include "platform/globals.h" #include "vm/bootstrap_natives.h" #include "vm/compiler/runtime_api.h" #include "vm/native_entry.h" -#include "vm/virtual_memory.h" namespace dart { DEFINE_NATIVE_ENTRY(Coroutine_factory, 0, 3) { GET_NON_NULL_NATIVE_ARGUMENT(Smi, size, arguments->NativeArgAt(1)); GET_NON_NULL_NATIVE_ARGUMENT(Closure, entry, arguments->NativeArgAt(2)); - void* stack = VirtualMemory::Allocate(size.Value() * kWordSize, false, false, "coroutine-stack")->address(); - return Coroutine::New((void**)stack + size.Value(), size.Value(), Function::Handle(entry.function()).ptr()); + intptr_t stack_size = size.Value(); +#if defined(DART_TARGET_OS_WINDOWS) + void** stack_base = (void**)((uintptr_t)VirtualAlloc(nullptr, stack_size * kWordSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)); +#else + void** stack_base = (void**)((uintptr_t)mmap(nullptr, stack_size * kWordSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); +#endif + memset(stack_base, 0, stack_size * kWordSize); + return Coroutine::New(stack_base + stack_size , stack_size, Function::Handle(entry.function()).ptr()); } } // namespace dart diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc index e501c32fb2e1..06bb7d70e7aa 100644 --- a/runtime/vm/compiler/backend/il.cc +++ b/runtime/vm/compiler/backend/il.cc @@ -8575,29 +8575,23 @@ void CoroutineInitializeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ Drop(1); __ LeaveFrame(); - __ PushRegister(FPREG); - __ PushRegister(PP); - __ PushRegister(CODE_REG); - __ PushRegister(FUNCTION_REG); + __ set_constant_pool_allowed(false); + __ EnterDartFrame(0); - __ EnterFrame(0); __ LoadFieldFromOffset(SPREG, kCoroutine, Coroutine::stack_base_offset()); __ PushRegister(FPREG); - __ LoadCompressedFieldFromOffset(FUNCTION_REG, kCoroutine, Coroutine::entry_offset()); - if (!FLAG_precompiled_mode) { - __ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG, Function::code_offset()); - __ LoadImmediate(ARGS_DESC_REG, 0); - } - __ Call(compiler::FieldAddress(FUNCTION_REG, Function::entry_point_offset())); + __ PushRegister(kCoroutine); + compiler->EmitCallToStub(StubCode::CoroutineEntry()); + __ PopRegister(kCoroutine); __ PopRegister(FPREG); - __ LeaveFrame(); + if (!FLAG_precompiled_mode) __ RestoreCodePointer(); + if (FLAG_precompiled_mode) __ movq(PP, compiler::Address(THR, Thread::global_object_pool_offset())); + __ StoreFieldToOffset(SPREG, kCoroutine, Coroutine::stack_base_offset()); - __ PopRegister(FUNCTION_REG); - __ PopRegister(CODE_REG); - __ PopRegister(PP); - __ PopRegister(FPREG); + __ LeaveDartFrame(); + __ set_constant_pool_allowed(true); __ EnterFrame(0); __ PushObject(compiler::NullObject()); @@ -8606,44 +8600,6 @@ void CoroutineInitializeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ LeaveFrame(); } -LocationSummary* CoroutineTransferInstr::MakeLocationSummary( - Zone* zone, - bool opt) const { - const intptr_t kNumInputs = 2; - const intptr_t kNumTemps = 0; - LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); - locs->set_in(0, Location::RegisterLocation(CoroutineTransferABI::kFromCoroutineReg)); - locs->set_in(1, Location::RegisterLocation(CoroutineTransferABI::kToCoroutineReg)); - return locs; -} - -void CoroutineTransferInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - const Register kFromCoroutine = CoroutineTransferABI::kFromCoroutineReg; - const Register kToCoroutine = CoroutineTransferABI::kToCoroutineReg; - const Register kToStackLimit = CoroutineTransferABI::kToStackLimitReg; - -#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64) - SPILLS_LR_TO_FRAME({}); -#endif - __ PushRegister(FPREG); - __ PushRegister(PP); - __ PushRegister(CODE_REG); - __ PushRegister(FUNCTION_REG); - __ StoreFieldToOffset(SPREG, kFromCoroutine, Coroutine::stack_base_offset()); - - __ LoadFieldFromOffset(SPREG, kToCoroutine, Coroutine::stack_base_offset()); - __ PopRegister(FUNCTION_REG); - __ PopRegister(CODE_REG); - __ PopRegister(PP); - __ PopRegister(FPREG); - - __ LoadFieldFromOffset(kToStackLimit, kToCoroutine, Coroutine::stack_limit_offset()); - __ StoreToOffset(kToStackLimit, THR, Thread::stack_limit_offset()); - __ StoreToOffset(kToCoroutine, THR, Thread::coroutine_offset()); - - __ StoreFieldToOffset(kFromCoroutine, kToCoroutine, Coroutine::caller_offset()); -} - LocationSummary* CoroutineForkInstr::MakeLocationSummary( Zone* zone, bool opt) const { @@ -8663,41 +8619,68 @@ void CoroutineForkInstr::EmitNativeCode(FlowGraphCompiler* compiler) { #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64) SPILLS_LR_TO_FRAME({}); #endif - __ PushRegister(FPREG); - __ PushRegister(PP); - __ PushRegister(CODE_REG); - __ PushRegister(FUNCTION_REG); - __ StoreFieldToOffset(SPREG, kCallerCoroutine, Coroutine::stack_base_offset()); - - __ StoreFieldToOffset(kCallerCoroutine, kForkedCoroutine, Coroutine::caller_offset()); + __ StoreCompressedIntoObjectNoBarrier(kForkedCoroutine, compiler::FieldAddress(kForkedCoroutine, Coroutine::caller_offset()), kCallerCoroutine); __ LoadFieldFromOffset(kStackLimit, kForkedCoroutine, Coroutine::stack_limit_offset()); __ StoreToOffset(kStackLimit, THR, Thread::stack_limit_offset()); __ StoreToOffset(kForkedCoroutine, THR, Thread::coroutine_offset()); + __ PushRegister(FPREG); + __ StoreFieldToOffset(SPREG, kCallerCoroutine, Coroutine::stack_base_offset()); + __ LoadFieldFromOffset(SPREG, kForkedCoroutine, Coroutine::stack_base_offset()); + __ PushRegister(kForkedCoroutine); + compiler->EmitCallToStub(StubCode::CoroutineEntry()); + __ PopRegister(kForkedCoroutine); - __ LoadCompressedFieldFromOffset(FUNCTION_REG, kForkedCoroutine, Coroutine::entry_offset()); - if (!FLAG_precompiled_mode) { - __ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG, Function::code_offset()); - __ LoadImmediate(ARGS_DESC_REG, 0); - } - __ Call(compiler::FieldAddress(FUNCTION_REG, Function::entry_point_offset())); + __ StoreFieldToOffset(SPREG, kForkedCoroutine, Coroutine::stack_base_offset()); + __ LoadCompressedFieldFromOffset(kCallerCoroutine, kForkedCoroutine, Coroutine::caller_offset()); - __ PopRegister(kForkedCoroutine); - __ LoadFieldFromOffset(kCallerCoroutine, kForkedCoroutine, Coroutine::caller_offset()); __ LoadFieldFromOffset(SPREG, kCallerCoroutine, Coroutine::stack_base_offset()); - __ PopRegister(FUNCTION_REG); - __ PopRegister(CODE_REG); - __ PopRegister(PP); __ PopRegister(FPREG); + if (!FLAG_precompiled_mode) __ RestoreCodePointer(); + if (FLAG_precompiled_mode) __ movq(PP, compiler::Address(THR, Thread::global_object_pool_offset())); __ LoadFieldFromOffset(kStackLimit, kCallerCoroutine, Coroutine::stack_limit_offset()); __ StoreToOffset(kStackLimit, THR, Thread::stack_limit_offset()); __ StoreToOffset(kCallerCoroutine, THR, Thread::coroutine_offset()); } +LocationSummary* CoroutineTransferInstr::MakeLocationSummary( + Zone* zone, + bool opt) const { + const intptr_t kNumInputs = 2; + const intptr_t kNumTemps = 0; + LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); + locs->set_in(0, Location::RegisterLocation(CoroutineTransferABI::kFromCoroutineReg)); + locs->set_in(1, Location::RegisterLocation(CoroutineTransferABI::kToCoroutineReg)); + return locs; +} + +void CoroutineTransferInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + const Register kFromCoroutine = CoroutineTransferABI::kFromCoroutineReg; + const Register kToCoroutine = CoroutineTransferABI::kToCoroutineReg; + const Register kToStackLimit = CoroutineTransferABI::kToStackLimitReg; + +#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64) + SPILLS_LR_TO_FRAME({}); +#endif + __ PushRegister(FPREG); + __ StoreFieldToOffset(SPREG, kFromCoroutine, Coroutine::stack_base_offset()); + + __ LoadFieldFromOffset(SPREG, kToCoroutine, Coroutine::stack_base_offset()); + __ PopRegister(FPREG); + if (!FLAG_precompiled_mode) __ RestoreCodePointer(); + if (FLAG_precompiled_mode) __ movq(PP, compiler::Address(THR, Thread::global_object_pool_offset())); + + __ LoadFieldFromOffset(kToStackLimit, kToCoroutine, Coroutine::stack_limit_offset()); + __ StoreToOffset(kToStackLimit, THR, Thread::stack_limit_offset()); + __ StoreToOffset(kToCoroutine, THR, Thread::coroutine_offset()); + + __ StoreCompressedIntoObjectNoBarrier(kToCoroutine, compiler::FieldAddress(kToCoroutine, Coroutine::caller_offset()), kFromCoroutine); +} + Definition* SuspendInstr::Canonicalize(FlowGraph* flow_graph) { if (stub_id() == StubId::kAwaitWithTypeCheck && !operand()->Type()->CanBeFuture()) { diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h index f639bf799341..816344916da8 100644 --- a/runtime/vm/compiler/backend/il.h +++ b/runtime/vm/compiler/backend/il.h @@ -11476,7 +11476,7 @@ class Call1ArgStubInstr : public TemplateDefinition<1, Throws> { DISALLOW_COPY_AND_ASSIGN(Call1ArgStubInstr); }; -class CoroutineInitializeInstr : public TemplateInstruction<1, NoThrow> { +class CoroutineInitializeInstr : public TemplateInstruction<1, Throws> { public: CoroutineInitializeInstr(Value* root, intptr_t deopt_id) : TemplateInstruction(InstructionSource(TokenPosition::kNoSource), @@ -11487,7 +11487,7 @@ class CoroutineInitializeInstr : public TemplateInstruction<1, NoThrow> { Value* root() const { return inputs_[0]; } virtual bool CanCallDart() const { return true; } virtual bool ComputeCanDeoptimize() const { return false; } - virtual bool ComputeCanDeoptimizeAfterCall() const { return true; } + virtual bool ComputeCanDeoptimizeAfterCall() const { return !CompilerState::Current().is_aot(); } virtual bool HasUnknownSideEffects() const { return true; } virtual intptr_t NumberOfInputsConsumedBeforeCall() const { return InputCount(); @@ -11501,7 +11501,7 @@ class CoroutineInitializeInstr : public TemplateInstruction<1, NoThrow> { DISALLOW_COPY_AND_ASSIGN(CoroutineInitializeInstr); }; -class CoroutineTransferInstr : public TemplateInstruction<2, NoThrow> { +class CoroutineTransferInstr : public TemplateInstruction<2, Throws> { public: CoroutineTransferInstr(Value* from, Value* to, intptr_t deopt_id) : TemplateInstruction(InstructionSource(TokenPosition::kNoSource), @@ -11515,7 +11515,7 @@ class CoroutineTransferInstr : public TemplateInstruction<2, NoThrow> { virtual bool CanCallDart() const { return true; } virtual bool ComputeCanDeoptimize() const { return false; } - virtual bool ComputeCanDeoptimizeAfterCall() const { return true; } + virtual bool ComputeCanDeoptimizeAfterCall() const { return !CompilerState::Current().is_aot(); } virtual bool HasUnknownSideEffects() const { return true; } virtual intptr_t NumberOfInputsConsumedBeforeCall() const { return InputCount(); @@ -11529,7 +11529,7 @@ class CoroutineTransferInstr : public TemplateInstruction<2, NoThrow> { DISALLOW_COPY_AND_ASSIGN(CoroutineTransferInstr); }; -class CoroutineForkInstr : public TemplateInstruction<2, NoThrow> { +class CoroutineForkInstr : public TemplateInstruction<2, Throws> { public: CoroutineForkInstr(Value* from, Value* to, intptr_t deopt_id) : TemplateInstruction(InstructionSource(TokenPosition::kNoSource), @@ -11543,7 +11543,7 @@ class CoroutineForkInstr : public TemplateInstruction<2, NoThrow> { virtual bool CanCallDart() const { return true; } virtual bool ComputeCanDeoptimize() const { return false; } - virtual bool ComputeCanDeoptimizeAfterCall() const { return true; } + virtual bool ComputeCanDeoptimizeAfterCall() const { return !CompilerState::Current().is_aot(); } virtual bool HasUnknownSideEffects() const { return true; } virtual intptr_t NumberOfInputsConsumedBeforeCall() const { return InputCount(); diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 381e80494587..6f978a3aa0f0 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -1921,17 +1921,17 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod( body += NullConstant(); break; } - case MethodRecognizer::kCoroutineTransfer: { + case MethodRecognizer::kCoroutineFork: { body += LoadLocal(parsed_function_->RawParameterVariable(0)); body += LoadLocal(parsed_function_->RawParameterVariable(1)); - body += CoroutineTransfer(); + body += CoroutineFork(); body += NullConstant(); break; } - case MethodRecognizer::kCoroutineFork: { + case MethodRecognizer::kCoroutineTransfer: { body += LoadLocal(parsed_function_->RawParameterVariable(0)); body += LoadLocal(parsed_function_->RawParameterVariable(1)); - body += CoroutineFork(); + body += CoroutineTransfer(); body += NullConstant(); break; } @@ -4771,18 +4771,18 @@ Fragment FlowGraphBuilder::CoroutineInitialize() { return Fragment(instr); } -Fragment FlowGraphBuilder::CoroutineTransfer() { - CoroutineTransferInstr* instr = - new (Z) CoroutineTransferInstr(Pop(), Pop(), GetNextDeoptId()); - return Fragment(instr); -} - Fragment FlowGraphBuilder::CoroutineFork() { CoroutineForkInstr* instr = new (Z) CoroutineForkInstr(Pop(), Pop(), GetNextDeoptId()); return Fragment(instr); } +Fragment FlowGraphBuilder::CoroutineTransfer() { + CoroutineTransferInstr* instr = + new (Z) CoroutineTransferInstr(Pop(), Pop(), GetNextDeoptId()); + return Fragment(instr); +} + Fragment FlowGraphBuilder::Suspend(TokenPosition position, SuspendInstr::StubId stub_id) { Value* type_args = diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc index 1196e48c9da6..15991dffd868 100644 --- a/runtime/vm/compiler/stub_code_compiler.cc +++ b/runtime/vm/compiler/stub_code_compiler.cc @@ -3232,6 +3232,19 @@ void StubCodeCompiler::GenerateSubtypeTestCacheSearch( } #endif +void StubCodeCompiler::GenerateCoroutineEntryStub() { + const Register kCoroutine = CoroutineEntryABI::kCoroutineReg; + __ EnterStubFrame(); + __ LoadCompressedFieldFromOffset(FUNCTION_REG, kCoroutine, Coroutine::entry_offset()); + if (!FLAG_precompiled_mode) { + __ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG, Function::code_offset()); + __ LoadImmediate(ARGS_DESC_REG, 0); + } + __ Call(compiler::FieldAddress(FUNCTION_REG, Function::entry_point_offset())); + __ LeaveStubFrame(); + __ Ret(); +} + // See comment on [GenerateSubtypeNTestCacheStub]. void StubCodeCompiler::GenerateSubtype1TestCacheStub() { GenerateSubtypeNTestCacheStub(assembler, 1); diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h index c142b12132fa..2c6f29be90a8 100644 --- a/runtime/vm/constants_x64.h +++ b/runtime/vm/constants_x64.h @@ -388,16 +388,22 @@ struct SuspendStubABI { static constexpr intptr_t kResumePcDistance = 5; }; -struct CoroutineInitializeABI { +struct CoroutineEntryABI { static constexpr Register kCoroutineReg = RDI; - static constexpr Register kEntryReg = RCX; +}; + +struct CoroutineInitializeABI { + static constexpr Register kCoroutineReg = CoroutineEntryABI::kCoroutineReg; + static constexpr Register kSourceFrameReg = RBX; + static constexpr Register kStoreFrameReg = RCX; + static constexpr Register kSourceFrameSizeReg = RDX; + static constexpr Register kTempReg = TMP; }; struct CoroutineForkABI { - static constexpr Register kCallerCoroutineReg = RDI; - static constexpr Register kForkedCoroutineReg = RSI; + static constexpr Register kCallerCoroutineReg = RSI; + static constexpr Register kForkedCoroutineReg = CoroutineEntryABI::kCoroutineReg; static constexpr Register kStackLimitReg = RDX; - static constexpr Register kForkedEntryReg = RCX; }; struct CoroutineTransferABI { diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc index 2ca130dcb35c..38abbf353e00 100644 --- a/runtime/vm/exceptions.cc +++ b/runtime/vm/exceptions.cc @@ -109,6 +109,7 @@ static void BuildStackTrace(StackTraceBuilder* builder) { if (!frame->IsDartFrame()) { continue; } + OS::Print("BuildStackTrace\n"); code = frame->LookupDartCode(); ASSERT(code.ContainsInstructionAt(frame->pc())); const uword pc_offset = frame->pc() - code.PayloadStart(); @@ -153,6 +154,7 @@ class ExceptionHandlerFinder : public StackResource { (handler_pc != StubCode::AsyncExceptionHandler().EntryPoint())) { pc_ = frame->pc(); + OS::Print("ExceptionHandlerFinder::find\n"); code_ = &Code::Handle(frame->LookupDartCode()); CatchEntryMovesRefPtr* cached_catch_entry_moves = catch_entry_moves_cache_->Lookup(pc_); diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 1e6f0bd44fdc..6aee43613b8c 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -2784,7 +2784,6 @@ ObjectPtr Object::Allocate(intptr_t cls_id, ASSERT(thread->no_safepoint_scope_depth() == 0); ASSERT(thread->no_callback_scope_depth() == 0); Heap* heap = thread->heap(); - uword address = heap->Allocate(thread, size, space); if (UNLIKELY(address == 0)) { // SuspendLongJumpScope during Dart entry ensures that if a longjmp base is @@ -26632,8 +26631,6 @@ CodePtr SuspendState::GetCodeObject() const { CoroutinePtr Coroutine::New(void** stack_base, uintptr_t stack_size, FunctionPtr entry) { const auto& coroutine = Coroutine::Handle(Object::Allocate(Heap::kOld)); - *(stack_base--) = 0; - NoSafepointScope no_safepoint; coroutine.StoreNonPointer(&coroutine.untag()->stack_base_, (uword)stack_base); coroutine.StoreNonPointer(&coroutine.untag()->stack_limit_, (uword)stack_base - stack_size); coroutine.StoreCompressedPointer(&coroutine.untag()->entry_, entry); @@ -28029,3 +28026,4 @@ ArrayPtr RecordShape::GetFieldNames(Thread* thread) const { } } // namespace dart + diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 31b9fb7d2ccc..83e84afdf512 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -12705,7 +12705,7 @@ class Coroutine : public Instance { static intptr_t InstanceSize() { return RoundedAllocationSize(sizeof(UntaggedCoroutine)); } - static CoroutinePtr New(void** stackb_base, uintptr_t stack_size, FunctionPtr entry); + static CoroutinePtr New(void** stack_base, uintptr_t stack_size, FunctionPtr entry); CoroutinePtr caller() const { return untag()->caller(); } static uword caller_offset() { return OFFSET_OF(UntaggedCoroutine, caller_); } diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc index e033f55a5fb3..4c53088cdaf7 100644 --- a/runtime/vm/profiler.cc +++ b/runtime/vm/profiler.cc @@ -374,7 +374,7 @@ static bool GetAndValidateThreadStackBounds(OSThread* os_thread, #endif // defined(USING_SIMULATOR) if (!use_simulator_stack_bounds) { - if (thread->coroutine() != nullptr) { + if (thread->has_coroutine()) { *stack_lower = thread->coroutine()->untag()->stack_limit(); *stack_upper = thread->coroutine()->untag()->stack_base(); } else { @@ -403,8 +403,7 @@ static bool GetAndValidateCurrentThreadStackBounds(uintptr_t fp, ASSERT(stack_lower != nullptr); ASSERT(stack_upper != nullptr); - if (Thread::Current() != nullptr && - Thread::Current()->coroutine() != nullptr) { + if (Thread::Current() != nullptr && Thread::Current()->has_coroutine()) { *stack_lower = Thread::Current()->coroutine()->untag()->stack_limit(); *stack_upper = Thread::Current()->coroutine()->untag()->stack_base(); } else { diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc index 445d84839b0f..5a425a1cdf66 100644 --- a/runtime/vm/runtime_entry.cc +++ b/runtime/vm/runtime_entry.cc @@ -110,7 +110,7 @@ DEFINE_FLAG(bool, "Enable specializing megamorphic calls from unoptimized code."); DEFINE_FLAG(bool, verbose_stack_overflow, - false, + true, "Print additional details about stack overflow."); DECLARE_FLAG(int, reload_every); diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc index b89c87e1aa60..c0843c706a88 100644 --- a/runtime/vm/stack_frame.cc +++ b/runtime/vm/stack_frame.cc @@ -607,8 +607,7 @@ void StackFrameIterator::FrameSetIterator::Unpoison() { #if !defined(USING_SIMULATOR) if (fp_ == 0) return; // Note that Thread::os_thread_ is cleared when the thread is descheduled. - ASSERT((thread_->coroutine() != nullptr) || - (thread_->os_thread() == nullptr) || + ASSERT((thread_->has_coroutine()) || (thread_->os_thread() == nullptr) || ((thread_->os_thread()->stack_limit() < fp_) && (thread_->os_thread()->stack_base() > fp_))); uword lower; @@ -627,6 +626,16 @@ void StackFrameIterator::FrameSetIterator::Unpoison() { StackFrame* StackFrameIterator::FrameSetIterator::NextFrame(bool validate) { StackFrame* frame; ASSERT(HasNext()); + if (StubCode::InCoroutineEntryStub(stack_frame_.pc_)) { + frame = &stack_frame_; + frame->sp_ = sp_; + frame->fp_ = fp_; + frame->pc_ = pc_; + sp_ = frame->GetCallerSp(); + fp_ = frame->GetCallerFp(); + pc_ = frame->GetCallerPc(); + return NextFrame(validate); + } frame = &stack_frame_; frame->sp_ = sp_; frame->fp_ = fp_; diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc index dd6181eec389..4a41629e6025 100644 --- a/runtime/vm/stub_code.cc +++ b/runtime/vm/stub_code.cc @@ -136,6 +136,13 @@ bool StubCode::InInvocationStub(uword pc) { return (pc >= entry) && (pc < (entry + size)); } +bool StubCode::InCoroutineEntryStub(uword pc) { + ASSERT(HasBeenInitialized()); + uword entry = StubCode::CoroutineEntry().EntryPoint(); + uword size = StubCode::CoroutineEntrySize(); + return (pc >= entry) && (pc < (entry + size)); +} + bool StubCode::InJumpToFrameStub(uword pc) { ASSERT(HasBeenInitialized()); uword entry = StubCode::JumpToFrame().EntryPoint(); diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h index 5430b0e0cc36..e506d8de2c0a 100644 --- a/runtime/vm/stub_code.h +++ b/runtime/vm/stub_code.h @@ -49,6 +49,9 @@ class StubCode : public AllStatic { // transitioning into dart code. static bool InInvocationStub(uword pc); + // Check if specified pc is in the dart coroutine entry stub + static bool InCoroutineEntryStub(uword pc); + // Check if the specified pc is in the jump to frame stub. static bool InJumpToFrameStub(uword pc); diff --git a/runtime/vm/stub_code_list.h b/runtime/vm/stub_code_list.h index 7297fcf70be7..b12018053a31 100644 --- a/runtime/vm/stub_code_list.h +++ b/runtime/vm/stub_code_list.h @@ -177,6 +177,7 @@ namespace dart { V(SuspendSyncStarAtYield) \ V(AsyncExceptionHandler) \ V(CloneSuspendState) \ + V(CoroutineEntry) \ V(FfiAsyncCallbackSend) \ V(UnknownDartCode) diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index 07e84bac606a..81ea7e380665 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -445,6 +445,7 @@ class ObjectPointerVisitor; V(_initAsync, "_initAsync") \ V(_initAsyncStar, "_initAsyncStar") \ V(_initSyncStar, "_initSyncStar") \ + V(_coroutineEntry, "_coroutineEntry") \ V(_coroutineInitialize, "_coroutineInitialize") \ V(_coroutineTransfer, "_coroutineTransfer") \ V(_coroutineFork, "_coroutineFork") \ diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc index d6a90e447777..3b1255e4eb59 100644 --- a/runtime/vm/thread.cc +++ b/runtime/vm/thread.cc @@ -551,7 +551,7 @@ void Thread::ResumeDartMutatorThreadInternal(Thread* thread) { void Thread::SuspendDartMutatorThreadInternal(Thread* thread, VMTag::VMTagId tag) { - if (thread->coroutine() != nullptr) { + if (thread->has_coroutine()) { thread->isolate()->save_coroutine(thread->SaveCoroutine()); SuspendThreadInternal(thread, tag); return; diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h index 62bd7e2be5eb..d84fb9898960 100644 --- a/runtime/vm/thread.h +++ b/runtime/vm/thread.h @@ -397,6 +397,7 @@ class Thread : public ThreadState { CoroutinePtr SaveCoroutine(); void EnterCoroutine(CoroutinePtr coroutine); void ExitCoroutine(); + bool has_coroutine() const { return coroutine_ != nullptr; } CoroutinePtr coroutine() const { return coroutine_; } static intptr_t coroutine_offset() { return OFFSET_OF(Thread, coroutine_); } diff --git a/sdk.code-workspace b/sdk.code-workspace index 20163f56fbdf..d901d2cefe1d 100644 --- a/sdk.code-workspace +++ b/sdk.code-workspace @@ -49,6 +49,9 @@ "clangd.arguments": [ "--compile-commands-dir=out/DebugX64" ], + "files.exclude": { + "**/*.S": true, + }, "dart.analysisExcludedFolders": [ // These "tests" folders include invalid Dart code which // will show as analyzer warnings/errors we don't intend to fix. diff --git a/sdk/lib/_internal/js_dev_runtime/patch/fiber_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/fiber_patch.dart index a6de2b4b515c..d0ed0f458e98 100644 --- a/sdk/lib/_internal/js_dev_runtime/patch/fiber_patch.dart +++ b/sdk/lib/_internal/js_dev_runtime/patch/fiber_patch.dart @@ -7,11 +7,13 @@ class Fiber { FiberState get state => _state; var _state = FiberState.created; @patch - Fiber._({required int size, required void Function() entry, required String name}) : this.name = name {} + Fiber._({required int size, required void Function() entry, required String name}) : this.name = name; @patch void start() { throw UnsupportedError("Fiber.start"); } @patch void transfer(Fiber to) { throw UnsupportedError("Fiber.transfer"); } @patch void fork(Fiber to) { throw UnsupportedError("Fiber.fork"); } + @patch + static void idle() { throw UnsupportedError("Fiber.idle"); } } diff --git a/sdk/lib/_internal/js_runtime/lib/fiber_patch.dart b/sdk/lib/_internal/js_runtime/lib/fiber_patch.dart index a6de2b4b515c..d0ed0f458e98 100644 --- a/sdk/lib/_internal/js_runtime/lib/fiber_patch.dart +++ b/sdk/lib/_internal/js_runtime/lib/fiber_patch.dart @@ -7,11 +7,13 @@ class Fiber { FiberState get state => _state; var _state = FiberState.created; @patch - Fiber._({required int size, required void Function() entry, required String name}) : this.name = name {} + Fiber._({required int size, required void Function() entry, required String name}) : this.name = name; @patch void start() { throw UnsupportedError("Fiber.start"); } @patch void transfer(Fiber to) { throw UnsupportedError("Fiber.transfer"); } @patch void fork(Fiber to) { throw UnsupportedError("Fiber.fork"); } + @patch + static void idle() { throw UnsupportedError("Fiber.idle"); } } diff --git a/sdk/lib/_internal/vm/lib/fiber_patch.dart b/sdk/lib/_internal/vm/lib/fiber_patch.dart index 03f0c3bf1482..169f495e6eaa 100644 --- a/sdk/lib/_internal/vm/lib/fiber_patch.dart +++ b/sdk/lib/_internal/vm/lib/fiber_patch.dart @@ -1,4 +1,4 @@ -import "dart:_internal" show patch; +import "dart:_internal" show patch, VMInternalsForTesting; import "dart:fiber"; import "dart:async" show FutureOr; @@ -35,7 +35,7 @@ class Fiber { @pragma("vm:prefer-inline") Fiber._({required int size, required void Function() entry, required String name}) : this.name = name, - _current = _Coroutine._(size, entry) {} + _current = _Coroutine._(size, entry); @patch @pragma("vm:prefer-inline") @@ -54,4 +54,9 @@ class Fiber { void fork(Fiber to) { _coroutineFork(_current, to._current); } + + @patch + static void idle() { + VMInternalsForTesting.collectAllGarbage(); + } } diff --git a/sdk/lib/_internal/wasm/lib/fiber_patch.dart b/sdk/lib/_internal/wasm/lib/fiber_patch.dart index a6de2b4b515c..d0ed0f458e98 100644 --- a/sdk/lib/_internal/wasm/lib/fiber_patch.dart +++ b/sdk/lib/_internal/wasm/lib/fiber_patch.dart @@ -7,11 +7,13 @@ class Fiber { FiberState get state => _state; var _state = FiberState.created; @patch - Fiber._({required int size, required void Function() entry, required String name}) : this.name = name {} + Fiber._({required int size, required void Function() entry, required String name}) : this.name = name; @patch void start() { throw UnsupportedError("Fiber.start"); } @patch void transfer(Fiber to) { throw UnsupportedError("Fiber.transfer"); } @patch void fork(Fiber to) { throw UnsupportedError("Fiber.fork"); } + @patch + static void idle() { throw UnsupportedError("Fiber.idle"); } } diff --git a/sdk/lib/fiber/fiber.dart b/sdk/lib/fiber/fiber.dart index 7bb23cca9598..36ba7a6a6261 100644 --- a/sdk/lib/fiber/fiber.dart +++ b/sdk/lib/fiber/fiber.dart @@ -15,6 +15,8 @@ class Fiber { final String name; static late Fiber _main; + external static void idle(); + external FiberState get state; external Fiber._({required int size, required void Function() entry, required String name}); factory Fiber.main({int size = _kDefaultStackSize, required void Function() entry}) => Fiber._(size: size, entry: entry, name: "main"); diff --git a/tests/lib/fiber/fiber_test.dart b/tests/lib/fiber/fiber_test.dart index 3d8fc78ea82f..b0ebcdc2341a 100644 --- a/tests/lib/fiber/fiber_test.dart +++ b/tests/lib/fiber/fiber_test.dart @@ -7,25 +7,33 @@ final childFiber = Fiber.child(entry: childEntry, name: "child"); var commonState = ""; void main() { - print("before start"); - mainFiber.start(); - print("after start"); + while (true) { + //print("before idle"); + Fiber.idle(); + //print("after idle"); + commonState = ""; + //print("before start"); + mainFiber.start(); + //print("after start"); + } } void mainEntry() { - print("main: entry"); + //print("main: entry"); commonState += "main -> "; mainFiber.fork(childFiber); + //print("main: after child fork"); commonState += "main -> "; - print("main: after child transfer"); + throw Exception("test"); + //print("main: after child transfer"); mainFiber.transfer(childFiber); print(commonState); } void childEntry() { - print("child: entry"); + //print("child: entry"); commonState += "child -> "; childFiber.transfer(mainFiber); - print("child: after main transfer"); + //print("child: after main transfer"); commonState += "child"; }