Skip to content

Commit 123b96d

Browse files
committed
feat: Argon can now evaluate code synchronously, specifically for evaluating certain magic methods (e.g., comparison functions)
1 parent bd38e15 commit 123b96d

File tree

7 files changed

+114
-18
lines changed

7 files changed

+114
-18
lines changed

argon/vm/areval.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ bool PopExecutedFrame(Fiber *fiber, const Code **out_code, Frame **out_frame, Ar
280280

281281
FrameDel(FiberPopFrame(fiber));
282282

283-
if (fiber->frame == nullptr) {
283+
if (fiber->frame == nullptr || fiber->unwind_limit == cu_frame) {
284284
if (IsPanicking())
285285
Release(ret);
286286

argon/vm/datatype/arobject.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ ArObject *argon::vm::datatype::Repr(ArObject *object) {
519519

520520
args[0] = object;
521521

522-
auto *result = EvalRaiseError(rfunc, args, 1, OpCodeCallMode::FASTCALL);
522+
auto *result = EvalSync(rfunc, args, 1, OpCodeCallMode::FASTCALL);
523523

524524
Release(rfunc);
525525

@@ -563,7 +563,7 @@ ArObject *argon::vm::datatype::Str(ArObject *object) {
563563

564564
args[0] = object;
565565

566-
auto *result = EvalRaiseError(sfunc, args, 1, OpCodeCallMode::FASTCALL);
566+
auto *result = EvalSync(sfunc, args, 1, OpCodeCallMode::FASTCALL);
567567

568568
Release(sfunc);
569569

@@ -874,7 +874,7 @@ bool argon::vm::datatype::Hash(ArObject *object, ArSize *out_hash) {
874874

875875
args[0] = object;
876876

877-
auto *result = EvalRaiseError(hfunc, args, 1, OpCodeCallMode::FASTCALL);
877+
auto *result = EvalSync(hfunc, args, 1, OpCodeCallMode::FASTCALL);
878878

879879
Release(hfunc);
880880

argon/vm/datatype/struct.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ ArObject *struct_compare(Struct *self, ArObject *other, CompareMode mode) {
5959
args[0] = (ArObject *) self;
6060
args[1] = other;
6161

62-
auto *res = argon::vm::EvalRaiseError(meth, args, 2, argon::vm::OpCodeCallMode::FASTCALL);
62+
auto *res = argon::vm::EvalSync(meth, args, 2, argon::vm::OpCodeCallMode::FASTCALL);
6363

6464
Release(meth);
6565

argon/vm/fiber.h

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <argon/vm/datatype/function.h>
1111
#include <argon/vm/datatype/namespace.h>
1212

13+
#include <argon/vm/sync/mcond.h>
1314
#include <argon/vm/sync/sync.h>
1415

1516
#include <argon/vm/context.h>
@@ -30,6 +31,9 @@ namespace argon::vm {
3031
/// Routine status.
3132
FiberStatus status;
3233

34+
/// Pointer to a stack allocated MCond object (see EvalSync).
35+
sync::MCond *sync_cv;
36+
3337
sync::NotifyQueueTicket ticket;
3438

3539
struct {
@@ -55,6 +59,9 @@ namespace argon::vm {
5559
/// Raw pointer to the OSThread running this fiber (only used to check if the fiber is already running on an OSThread).
5660
void *active_ost;
5761

62+
/// Pointer to the frame allocated by the last EvalSync call.
63+
void *unwind_limit;
64+
5865
void *stack_cur;
5966

6067
void *stack_end;

argon/vm/runtime.cpp

+47-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <argon/vm/datatype/future.h>
3030

3131
#include <argon/vm/loop2/evloop.h>
32+
#include <argon/vm/sync/mcond.h>
3233

3334
#include <argon/vm/setup.h>
3435

@@ -582,7 +583,7 @@ void Scheduler(OSThread *self) {
582583
void VCoreRelease(OSThread *ost) {
583584
auto *current = ost->current;
584585

585-
if (ost->current == nullptr)
586+
if (current == nullptr)
586587
return;
587588

588589
ost->old = ost->current;
@@ -628,6 +629,45 @@ ArObject *argon::vm::EvalRaiseError(Function *func, ArObject **argv, ArSize argc
628629
return tmp;
629630
}
630631

632+
argon::vm::datatype::ArObject *argon::vm::EvalSync(Function *func, ArObject **argv, ArSize argc, OpCodeCallMode mode) {
633+
if (func->IsNative())
634+
return FunctionInvokeNative(func, argv, argc, ENUMBITMASK_ISTRUE(mode, OpCodeCallMode::KW_PARAMS));
635+
636+
auto *fiber = GetFiber();
637+
638+
assert(fiber != nullptr);
639+
640+
auto *prev_cond = fiber->sync_cv;
641+
auto *prev_limit = fiber->unwind_limit;
642+
643+
auto *frame = FrameNew(fiber, func, argv, argc, mode);
644+
if (frame == nullptr)
645+
return nullptr;
646+
647+
sync::MCond cond{};
648+
649+
FiberPushFrame(fiber, frame);
650+
651+
fiber->sync_cv = &cond;
652+
fiber->unwind_limit = frame;
653+
654+
auto *res = Eval(fiber);
655+
while (res == nullptr && GetFiberStatus() != FiberStatus::RUNNING) {
656+
cond.wait([fiber]() {
657+
return fiber->status == FiberStatus::RUNNABLE;
658+
});
659+
660+
SetFiberStatus(FiberStatus::RUNNING);
661+
662+
res = Eval(fiber);
663+
}
664+
665+
fiber->sync_cv = prev_cond;
666+
fiber->unwind_limit = prev_limit;
667+
668+
return res;
669+
}
670+
631671
ArObject *argon::vm::GetLastError() {
632672
Fiber *fiber = nullptr;
633673
ArObject *error;
@@ -1032,6 +1072,12 @@ void argon::vm::SetFiberStatus(FiberStatus status) {
10321072
void argon::vm::Spawn(argon::vm::Fiber *fiber) {
10331073
fiber->status = FiberStatus::RUNNABLE;
10341074

1075+
if (fiber->unwind_limit != nullptr) {
1076+
fiber->sync_cv->Notify();
1077+
1078+
return;
1079+
}
1080+
10351081
fiber_global.Enqueue(fiber);
10361082

10371083
OSTWakeRun();

argon/vm/runtime.h

+25-12
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,42 @@ namespace argon::vm {
2222
constexpr const unsigned short kVCoreDefault = 4;
2323
constexpr const unsigned short kVCoreQueueLengthMax = 256;
2424

25-
argon::vm::datatype::ArObject *EvalRaiseError(datatype::Function *func, datatype::ArObject **argv,
26-
datatype::ArSize argc, OpCodeCallMode mode);
25+
argon::vm::datatype::ArObject *EvalRaiseError(datatype::Function *func,
26+
datatype::ArObject **argv,
27+
datatype::ArSize argc,
28+
OpCodeCallMode mode);
29+
30+
argon::vm::datatype::ArObject *EvalSync(datatype::Function *func,
31+
datatype::ArObject **argv,
32+
datatype::ArSize argc,
33+
OpCodeCallMode mode);
2734

2835
argon::vm::datatype::ArObject *GetLastError();
2936

30-
argon::vm::datatype::Future *EvalAsync(Context *context, datatype::Function *func, datatype::ArObject **argv,
31-
datatype::ArSize argc, OpCodeCallMode mode);
37+
argon::vm::datatype::Future *EvalAsync(Context *context,
38+
datatype::Function *func,
39+
datatype::ArObject **argv,
40+
datatype::ArSize argc,
41+
OpCodeCallMode mode);
3242

3343
argon::vm::datatype::Result *Eval(Context *context, datatype::Code *code, datatype::Namespace *ns);
3444

35-
argon::vm::datatype::Result *Eval(datatype::Function *func, datatype::ArObject **argv,
36-
datatype::ArSize argc, OpCodeCallMode mode);
45+
argon::vm::datatype::Result *Eval(datatype::Function *func,
46+
datatype::ArObject **argv,
47+
datatype::ArSize argc,
48+
OpCodeCallMode mode);
3749

38-
inline argon::vm::datatype::Result *
39-
Eval(datatype::Function *func, datatype::ArObject **argv, datatype::ArSize argc) {
50+
inline argon::vm::datatype::Result *Eval(datatype::Function *func,
51+
datatype::ArObject **argv,
52+
datatype::ArSize argc) {
4053
return Eval(func, argv, argc, OpCodeCallMode::FASTCALL);
4154
}
4255

43-
argon::vm::datatype::Result *EvalFile(Context *context, const char *name,
44-
const char *path, datatype::Namespace *ns);
56+
argon::vm::datatype::Result *EvalFile(Context *context, const char *name, const char *path,
57+
datatype::Namespace *ns);
4558

46-
argon::vm::datatype::Result *EvalString(Context *context, const char *name,
47-
const char *source, datatype::Namespace *ns);
59+
argon::vm::datatype::Result *EvalString(Context *context, const char *name, const char *source,
60+
datatype::Namespace *ns);
4861

4962
argon::vm::datatype::String *GetExecutableName();
5063

argon/vm/sync/mcond.h

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// This source file is part of the Argon project.
2+
//
3+
// Licensed under the Apache License v2.0
4+
5+
#ifndef ARGON_VM_SYNC_MCOND_H_
6+
#define ARGON_VM_SYNC_MCOND_H_
7+
8+
#include <condition_variable>
9+
#include <mutex>
10+
11+
namespace argon::vm::sync {
12+
class MCond {
13+
std::mutex lock_;
14+
std::condition_variable cond_;
15+
16+
public:
17+
void Notify() {
18+
this->cond_.notify_one();
19+
}
20+
21+
template<typename Predicate>
22+
void wait(Predicate pred) {
23+
std::unique_lock lck(this->lock_);
24+
this->cond_.wait(lck, pred);
25+
}
26+
};
27+
28+
} // namespace argon::vm::sync
29+
30+
#endif // !ARGON_VM_SYNC_MCOND_H_

0 commit comments

Comments
 (0)