Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:

jobs:
build:
name: Build and Release
name: Build ${{ matrix.asset-name }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
Expand Down Expand Up @@ -57,20 +57,32 @@ jobs:
mv andromeda ${{ matrix.asset-name }}
fi

- name: Upload Binary to Release
if: github.ref == 'refs/heads/main'
- name: Upload Binary as Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset-name }}
path: target/${{ matrix.rust-target }}/release/${{ matrix.asset-name }}

release:
name: Create Release
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'

steps:
- uses: actions/checkout@v3

- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts

- name: Create Draft Release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: target/${{ matrix.rust-target }}/release/${{ matrix.asset-name }}
asset_name: ${{ matrix.asset-name }}
file: ./artifacts/*/andromeda-*
file_glob: true
draft: true
tag: latest
overwrite: true

- name: Upload Binary as Artifact (Main Branch)
if: github.ref == 'refs/heads/main'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset-name }}
path: target/${{ matrix.rust-target }}/release/${{ matrix.asset-name }}
3 changes: 0 additions & 3 deletions runtime/src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::ext::{interval::IntervalId, timeout::TimeoutId};
use nova_vm::{ecmascript::types::Value, engine::Global};

pub enum RuntimeMacroTask {
/// Run an interval.
Expand All @@ -14,6 +13,4 @@ pub enum RuntimeMacroTask {
RunAndClearTimeout(TimeoutId),
/// Stop a timeout from running no further.
ClearTimeout(TimeoutId),
/// Run a microtask callback
RunMicrotaskCallback(Global<Value<'static>>),
}
52 changes: 1 addition & 51 deletions runtime/src/ext/web/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::RuntimeMacroTask;
use andromeda_core::{Extension, ExtensionOp};
use andromeda_core::{HostData, MacroTask};
use nova_vm::engine::Global;
use nova_vm::{
ecmascript::{
builtins::ArgumentsList,
Expand Down Expand Up @@ -49,13 +46,13 @@ impl WebExt {
Self::internal_performance_time_origin,
0,
),
ExtensionOp::new("queueMicrotask", Self::queue_microtask, 1),
],
storage: None,
files: vec![
include_str!("./event.ts"),
include_str!("./text_encoding.ts"),
include_str!("./performance.ts"),
include_str!("./queueMicrotask.ts"),
],
}
}
Expand Down Expand Up @@ -422,53 +419,6 @@ impl WebExt {
.as_secs_f64()
* 1000.0
});

Ok(Value::from_f64(agent, origin_ms, gc).unbind())
}

/// Implementation of queueMicrotask as per HTML specification:
/// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-queuemicrotask
pub fn queue_microtask<'gc>(
agent: &mut Agent,
_this: Value,
args: ArgumentsList,
gc: GcScope<'gc, '_>,
) -> JsResult<'gc, Value<'gc>> {
let callback = args.get(0);
let _: nova_vm::ecmascript::types::Function = match callback.try_into() {
Ok(function) => function,
Err(_) => {
return Err(agent
.throw_exception(
ExceptionType::TypeError,
"The callback provided as an argument to queueMicrotask must be a function.".to_string(),
gc.nogc(),
)
.unbind());
}
};

// TODO: Implement proper microtask queueing when Nova APIs become available

// Store the callback globally so it can be called later
let root_callback = Global::new(agent, callback.unbind());

// Get host data to access the macro task system
let host_data = agent.get_host_data();
let host_data: &HostData<RuntimeMacroTask> = host_data.downcast_ref().unwrap();
let macro_task_tx = host_data.macro_task_tx();

// Schedule an immediate task to call the callback
// Using spawn_macro_task with an immediately resolving future
host_data.spawn_macro_task(async move {
// Send a macro task to call the callback
macro_task_tx
.send(MacroTask::User(RuntimeMacroTask::RunMicrotaskCallback(
root_callback,
)))
.unwrap();
});

Ok(Value::Undefined)
}
}
22 changes: 22 additions & 0 deletions runtime/src/ext/web/queueMicrotask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

// deno-lint-ignore-file

function queueMicrotask(callback: () => void): void {
if (typeof callback !== "function") {
throw new TypeError(
"The callback provided as an argument to queueMicrotask must be a function.",
);
}

Promise.resolve().then(() => {
try {
callback();
} catch (error) {
console.error("Uncaught error in microtask callback:", error);
throw error;
}
});
}
34 changes: 2 additions & 32 deletions runtime/src/recommended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use andromeda_core::{AndromedaError, ErrorReporter, Extension, HostData};
use nova_vm::{
ecmascript::execution::agent::{GcAgent, RealmRoot},
ecmascript::types::{Function, Value},
};
use andromeda_core::{Extension, HostData};
use nova_vm::ecmascript::execution::agent::{GcAgent, RealmRoot};

use crate::{ConsoleExt, FsExt, HeadersExt, ProcessExt, RuntimeMacroTask, TimeExt, URLExt, WebExt};

Expand Down Expand Up @@ -47,32 +44,5 @@ pub fn recommended_eventloop_handler(
RuntimeMacroTask::ClearTimeout(timeout_id) => {
timeout_id.clear_and_abort(host_data);
}
RuntimeMacroTask::RunMicrotaskCallback(root_callback) => {
// Execute the microtask callback - this is for queueMicrotask implementation
agent.run_in_realm(realm_root, |agent, gc| {
let callback = root_callback.get(agent, gc.nogc());
if let Ok(callback_function) = Function::try_from(callback) {
// Call the callback with no arguments as per HTML spec
// If the callback throws an error, it should be reported but not stop execution
if let Err(error) = callback_function.call(agent, Value::Undefined, &mut [], gc)
{
// Report the error as per Web IDL "invoke a callback function" with "report" error handling
// This is the proper implementation of error reporting for queueMicrotask
report_microtask_error(error);
}
}
});
}
}
}

/// Report a microtask error
/// This is called when a queueMicrotask callback throws an exception.
fn report_microtask_error<E>(error: E)
where
E: std::fmt::Debug,
{
let error_message = format!("Uncaught error in microtask callback: {:?}", error);
let andromeda_error = AndromedaError::runtime_error(error_message);
ErrorReporter::print_error(&andromeda_error);
}
Loading