Skip to content

Commit

Permalink
feat: Argon can now evaluate code synchronously, specifically for eva…
Browse files Browse the repository at this point in the history
…luating certain magic methods (e.g., comparison functions)
  • Loading branch information
jacopodl committed May 31, 2024
1 parent bd38e15 commit 123b96d
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 18 deletions.
2 changes: 1 addition & 1 deletion argon/vm/areval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ bool PopExecutedFrame(Fiber *fiber, const Code **out_code, Frame **out_frame, Ar

FrameDel(FiberPopFrame(fiber));

if (fiber->frame == nullptr) {
if (fiber->frame == nullptr || fiber->unwind_limit == cu_frame) {
if (IsPanicking())
Release(ret);

Expand Down
6 changes: 3 additions & 3 deletions argon/vm/datatype/arobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ ArObject *argon::vm::datatype::Repr(ArObject *object) {

args[0] = object;

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

Release(rfunc);

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

args[0] = object;

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

Release(sfunc);

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

args[0] = object;

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

Release(hfunc);

Expand Down
2 changes: 1 addition & 1 deletion argon/vm/datatype/struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ ArObject *struct_compare(Struct *self, ArObject *other, CompareMode mode) {
args[0] = (ArObject *) self;
args[1] = other;

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

Release(meth);

Expand Down
7 changes: 7 additions & 0 deletions argon/vm/fiber.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <argon/vm/datatype/function.h>
#include <argon/vm/datatype/namespace.h>

#include <argon/vm/sync/mcond.h>
#include <argon/vm/sync/sync.h>

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

/// Pointer to a stack allocated MCond object (see EvalSync).
sync::MCond *sync_cv;

sync::NotifyQueueTicket ticket;

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

/// Pointer to the frame allocated by the last EvalSync call.
void *unwind_limit;

void *stack_cur;

void *stack_end;
Expand Down
48 changes: 47 additions & 1 deletion argon/vm/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <argon/vm/datatype/future.h>

#include <argon/vm/loop2/evloop.h>
#include <argon/vm/sync/mcond.h>

#include <argon/vm/setup.h>

Expand Down Expand Up @@ -582,7 +583,7 @@ void Scheduler(OSThread *self) {
void VCoreRelease(OSThread *ost) {
auto *current = ost->current;

if (ost->current == nullptr)
if (current == nullptr)
return;

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

argon::vm::datatype::ArObject *argon::vm::EvalSync(Function *func, ArObject **argv, ArSize argc, OpCodeCallMode mode) {
if (func->IsNative())
return FunctionInvokeNative(func, argv, argc, ENUMBITMASK_ISTRUE(mode, OpCodeCallMode::KW_PARAMS));

auto *fiber = GetFiber();

assert(fiber != nullptr);

auto *prev_cond = fiber->sync_cv;
auto *prev_limit = fiber->unwind_limit;

auto *frame = FrameNew(fiber, func, argv, argc, mode);
if (frame == nullptr)
return nullptr;

sync::MCond cond{};

FiberPushFrame(fiber, frame);

fiber->sync_cv = &cond;
fiber->unwind_limit = frame;

auto *res = Eval(fiber);
while (res == nullptr && GetFiberStatus() != FiberStatus::RUNNING) {
cond.wait([fiber]() {
return fiber->status == FiberStatus::RUNNABLE;
});

SetFiberStatus(FiberStatus::RUNNING);

res = Eval(fiber);
}

fiber->sync_cv = prev_cond;
fiber->unwind_limit = prev_limit;

return res;
}

ArObject *argon::vm::GetLastError() {
Fiber *fiber = nullptr;
ArObject *error;
Expand Down Expand Up @@ -1032,6 +1072,12 @@ void argon::vm::SetFiberStatus(FiberStatus status) {
void argon::vm::Spawn(argon::vm::Fiber *fiber) {
fiber->status = FiberStatus::RUNNABLE;

if (fiber->unwind_limit != nullptr) {
fiber->sync_cv->Notify();

return;
}

fiber_global.Enqueue(fiber);

OSTWakeRun();
Expand Down
37 changes: 25 additions & 12 deletions argon/vm/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,42 @@ namespace argon::vm {
constexpr const unsigned short kVCoreDefault = 4;
constexpr const unsigned short kVCoreQueueLengthMax = 256;

argon::vm::datatype::ArObject *EvalRaiseError(datatype::Function *func, datatype::ArObject **argv,
datatype::ArSize argc, OpCodeCallMode mode);
argon::vm::datatype::ArObject *EvalRaiseError(datatype::Function *func,
datatype::ArObject **argv,
datatype::ArSize argc,
OpCodeCallMode mode);

argon::vm::datatype::ArObject *EvalSync(datatype::Function *func,
datatype::ArObject **argv,
datatype::ArSize argc,
OpCodeCallMode mode);

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

argon::vm::datatype::Future *EvalAsync(Context *context, datatype::Function *func, datatype::ArObject **argv,
datatype::ArSize argc, OpCodeCallMode mode);
argon::vm::datatype::Future *EvalAsync(Context *context,
datatype::Function *func,
datatype::ArObject **argv,
datatype::ArSize argc,
OpCodeCallMode mode);

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

argon::vm::datatype::Result *Eval(datatype::Function *func, datatype::ArObject **argv,
datatype::ArSize argc, OpCodeCallMode mode);
argon::vm::datatype::Result *Eval(datatype::Function *func,
datatype::ArObject **argv,
datatype::ArSize argc,
OpCodeCallMode mode);

inline argon::vm::datatype::Result *
Eval(datatype::Function *func, datatype::ArObject **argv, datatype::ArSize argc) {
inline argon::vm::datatype::Result *Eval(datatype::Function *func,
datatype::ArObject **argv,
datatype::ArSize argc) {
return Eval(func, argv, argc, OpCodeCallMode::FASTCALL);
}

argon::vm::datatype::Result *EvalFile(Context *context, const char *name,
const char *path, datatype::Namespace *ns);
argon::vm::datatype::Result *EvalFile(Context *context, const char *name, const char *path,
datatype::Namespace *ns);

argon::vm::datatype::Result *EvalString(Context *context, const char *name,
const char *source, datatype::Namespace *ns);
argon::vm::datatype::Result *EvalString(Context *context, const char *name, const char *source,
datatype::Namespace *ns);

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

Expand Down
30 changes: 30 additions & 0 deletions argon/vm/sync/mcond.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// This source file is part of the Argon project.
//
// Licensed under the Apache License v2.0

#ifndef ARGON_VM_SYNC_MCOND_H_
#define ARGON_VM_SYNC_MCOND_H_

#include <condition_variable>
#include <mutex>

namespace argon::vm::sync {
class MCond {
std::mutex lock_;
std::condition_variable cond_;

public:
void Notify() {
this->cond_.notify_one();
}

template<typename Predicate>
void wait(Predicate pred) {
std::unique_lock lck(this->lock_);
this->cond_.wait(lck, pred);
}
};

} // namespace argon::vm::sync

#endif // !ARGON_VM_SYNC_MCOND_H_

0 comments on commit 123b96d

Please sign in to comment.