Skip to content

Commit

Permalink
Rename opcodes
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Jul 27, 2023
1 parent 52cb2f6 commit d2b2a1a
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 244 deletions.
33 changes: 0 additions & 33 deletions boa_engine/src/builtins/async_generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,37 +692,4 @@ impl AsyncGenerator {
}
}
}

// Step 3.e-g in [AsyncGeneratorStart](https://tc39.es/ecma262/#sec-asyncgeneratorstart)
pub(crate) fn close_return(context: &mut Context<'_>) {
let generator_object = context
.vm
.frame()
.async_generator
.clone()
.expect("There should be a object");

let mut generator_object_mut = generator_object.borrow_mut();
let generator = generator_object_mut
.as_async_generator_mut()
.expect("must be async generator");

generator.state = AsyncGeneratorState::Completed;
generator.context = None;

let next = generator
.queue
.pop_front()
.expect("must have item in queue");
drop(generator_object_mut);

let return_value = std::mem::take(&mut context.vm.frame_mut().return_value);

if let Some(error) = context.vm.pending_exception.take() {
Self::complete_step(&next, Err(error), true, None, context);
} else {
Self::complete_step(&next, Ok(return_value), true, None, context);
}
Self::drain_queue(&generator_object, context);
}
}
4 changes: 2 additions & 2 deletions boa_engine/src/bytecompiler/jump_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ impl JumpRecord {
JumpRecordKind::Continue => compiler.patch_jump_with_target(self.label, start_address),
JumpRecordKind::Return => {
match (compiler.in_async(), compiler.in_generator()) {
(true, true) => compiler.emit_opcode(Opcode::AsyncGeneratorReturn),
(true, false) => compiler.emit_opcode(Opcode::PromiseCapability),
(true, true) => compiler.emit_opcode(Opcode::AsyncGeneratorClose),
(true, false) => compiler.emit_opcode(Opcode::CompletePromiseCapability),
(_, _) => {}
}
compiler.emit_opcode(Opcode::Return);
Expand Down
4 changes: 2 additions & 2 deletions boa_engine/src/vm/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,9 +570,9 @@ impl CodeBlock {
| Opcode::This
| Opcode::Super
| Opcode::Return
| Opcode::AsyncGeneratorReturn
| Opcode::PromiseCapability
| Opcode::AsyncGeneratorClose
| Opcode::CreatePromiseCapability
| Opcode::CompletePromiseCapability
| Opcode::PopEnvironment
| Opcode::IncrementLoopIteration
| Opcode::CreateForInIterator
Expand Down
4 changes: 2 additions & 2 deletions boa_engine/src/vm/flowgraph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,9 +523,9 @@ impl CodeBlock {
| Opcode::PushNewArray
| Opcode::GeneratorYield
| Opcode::AsyncGeneratorYield
| Opcode::AsyncGeneratorReturn
| Opcode::PromiseCapability
| Opcode::AsyncGeneratorClose
| Opcode::CreatePromiseCapability
| Opcode::CompletePromiseCapability
| Opcode::GeneratorNext
| Opcode::PushClassField
| Opcode::SuperCallDerived
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,71 @@ impl Operation for Await {
Ok(CompletionType::Yield)
}
}

/// `CreatePromiseCapability` implements the Opcode Operation for `Opcode::CreatePromiseCapability`
///
/// Operation:
/// - Create a promise capacity for an async function, if not already set.
#[derive(Debug, Clone, Copy)]
pub(crate) struct CreatePromiseCapability;

impl Operation for CreatePromiseCapability {
const NAME: &'static str = "CreatePromiseCapability";
const INSTRUCTION: &'static str = "INST - CreatePromiseCapability";

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
if context.vm.frame().promise_capability.is_some() {
return Ok(CompletionType::Normal);
}

let promise_capability = crate::builtins::promise::PromiseCapability::new(
&context.intrinsics().constructors().promise().constructor(),
context,
)
.expect("cannot fail per spec");

context.vm.frame_mut().promise_capability = Some(promise_capability);
Ok(CompletionType::Normal)
}
}

/// `CompletePromiseCapability` implements the Opcode Operation for `Opcode::CompletePromiseCapability`
///
/// Operation:
/// - Resolves or rejects the promise capability, depending if the pending exception is set.
#[derive(Debug, Clone, Copy)]
pub(crate) struct CompletePromiseCapability;

impl Operation for CompletePromiseCapability {
const NAME: &'static str = "CompletePromiseCapability";
const INSTRUCTION: &'static str = "INST - CompletePromiseCapability";

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// If the current executing function is an async function we have to resolve/reject it's promise at the end.
// The relevant spec section is 3. in [AsyncBlockStart](https://tc39.es/ecma262/#sec-asyncblockstart).
let Some(promise_capability) = context.vm.frame_mut().promise_capability.take() else {
return if context.vm.pending_exception.is_some() {
Ok(CompletionType::Throw)
} else {
Ok(CompletionType::Normal)
};
};

if let Some(error) = context.vm.pending_exception.take() {
promise_capability
.reject()
.call(&JsValue::undefined(), &[error.to_opaque(context)], context)
.expect("cannot fail per spec");
} else {
let return_value = context.vm.frame().return_value.clone();
promise_capability
.resolve()
.call(&JsValue::undefined(), &[return_value], context)
.expect("cannot fail per spec");
};

context.vm.frame_mut().return_value = promise_capability.promise().clone().into();

Ok(CompletionType::Normal)
}
}
File renamed without changes.
2 changes: 2 additions & 0 deletions boa_engine/src/vm/opcode/control_flow/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub(crate) mod jump;
pub(crate) mod r#return;
pub(crate) mod throw;

pub(crate) use jump::*;
pub(crate) use r#return::*;
pub(crate) use throw::*;
194 changes: 2 additions & 192 deletions boa_engine/src/vm/opcode/control_flow/return.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
use std::collections::VecDeque;

use crate::{
builtins::{
async_generator::{AsyncGenerator, AsyncGeneratorState},
generator::{GeneratorContext, GeneratorState},
},
environments::EnvironmentStack,
object::{ObjectData, PROTOTYPE},
vm::{opcode::Operation, CallFrame, CompletionType},
Context, JsObject, JsResult, JsValue,
vm::{opcode::Operation, CompletionType},
Context, JsResult,
};

/// `Return` implements the Opcode Operation for `Opcode::Return`
Expand All @@ -27,188 +19,6 @@ impl Operation for Return {
}
}

/// `AsyncGeneratorReturn` implements the Opcode Operation for `Opcode::AsyncGeneratorReturn`
///
/// Operation:
/// - Return from an async generator function.
#[derive(Debug, Clone, Copy)]
pub(crate) struct AsyncGeneratorReturn;

impl Operation for AsyncGeneratorReturn {
const NAME: &'static str = "AsyncGeneratorReturn";
const INSTRUCTION: &'static str = "INST - AsyncGeneratorReturn";

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
AsyncGenerator::close_return(context);
Ok(CompletionType::Normal)
}
}

/// `CreatePromiseCapability` implements the Opcode Operation for `Opcode::CreatePromiseCapability`
///
/// Operation:
/// - Create a promise capacity for an async function.
#[derive(Debug, Clone, Copy)]
pub(crate) struct CreatePromiseCapability;

impl Operation for CreatePromiseCapability {
const NAME: &'static str = "CreatePromiseCapability";
const INSTRUCTION: &'static str = "INST - CreatePromiseCapability";

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
if context.vm.frame().promise_capability.is_some() {
return Ok(CompletionType::Normal);
}

let promise_capability = crate::builtins::promise::PromiseCapability::new(
&context.intrinsics().constructors().promise().constructor(),
context,
)
.expect("cannot fail per spec");

context.vm.frame_mut().promise_capability = Some(promise_capability);
Ok(CompletionType::Normal)
}
}

/// `PromiseCapability` implements the Opcode Operation for `Opcode::PromiseCapability`
///
/// Operation:
/// - Resolves or rejects the promise capability, depending if the pending exception is set.
#[derive(Debug, Clone, Copy)]
pub(crate) struct PromiseCapability;

impl Operation for PromiseCapability {
const NAME: &'static str = "PromiseCapability";
const INSTRUCTION: &'static str = "INST - PromiseCapability";

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// If the current executing function is an async function we have to resolve/reject it's promise at the end.
// The relevant spec section is 3. in [AsyncBlockStart](https://tc39.es/ecma262/#sec-asyncblockstart).
let Some(promise_capability) = context.vm.frame_mut().promise_capability.take() else {
return if context.vm.pending_exception.is_some() {
Ok(CompletionType::Throw)
} else {
Ok(CompletionType::Normal)
};
};

if let Some(error) = context.vm.pending_exception.take() {
promise_capability
.reject()
.call(&JsValue::undefined(), &[error.to_opaque(context)], context)
.expect("cannot fail per spec");
} else {
let return_value = context.vm.frame().return_value.clone();
promise_capability
.resolve()
.call(&JsValue::undefined(), &[return_value], context)
.expect("cannot fail per spec");
};

context.vm.frame_mut().return_value = promise_capability.promise().clone().into();

Ok(CompletionType::Normal)
}
}

/// `Generator` implements the Opcode Operation for `Opcode::Generator`
///
/// Operation:
/// - TODO: doc
#[derive(Debug, Clone, Copy)]
pub(crate) struct Generator;

impl Operation for Generator {
const NAME: &'static str = "Generator";
const INSTRUCTION: &'static str = "INST - Generator";

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let r#async = context.vm.read::<u8>() != 0;

let code_block = context.vm.frame().code_block().clone();
let pc = context.vm.frame().pc;
let mut dummy_call_frame = CallFrame::new(code_block);
dummy_call_frame.pc = pc;
let call_frame = std::mem::replace(context.vm.frame_mut(), dummy_call_frame);

let this_function_object = context
.vm
.active_function
.clone()
.expect("active functoion should be set to the generator");

let proto = this_function_object
.get(PROTOTYPE, context)
.expect("generator must have a prototype property")
.as_object()
.map_or_else(
|| {
if r#async {
context.intrinsics().objects().async_generator()
} else {
context.intrinsics().objects().generator()
}
},
Clone::clone,
);

let global_environement = context.vm.environments.global();
let environments = std::mem::replace(
&mut context.vm.environments,
EnvironmentStack::new(global_environement),
);
let stack = std::mem::take(&mut context.vm.stack);

let data = if r#async {
ObjectData::async_generator(AsyncGenerator {
state: AsyncGeneratorState::SuspendedStart,
context: Some(GeneratorContext::new(
environments,
stack,
context.vm.active_function.clone(),
call_frame,
context.realm().clone(),
)),
queue: VecDeque::new(),
})
} else {
ObjectData::generator(crate::builtins::generator::Generator {
state: GeneratorState::SuspendedStart {
context: GeneratorContext::new(
environments,
stack,
context.vm.active_function.clone(),
call_frame,
context.realm().clone(),
),
},
})
};

let generator =
JsObject::from_proto_and_data_with_shared_shape(context.root_shape(), proto, data);

if r#async {
let gen_clone = generator.clone();
let mut generator_mut = generator.borrow_mut();
let gen = generator_mut
.as_async_generator_mut()
.expect("must be object here");
let gen_context = gen.context.as_mut().expect("must exist");
// TODO: try to move this to the context itself.
gen_context
.call_frame
.as_mut()
.expect("should have a call frame initialized")
.async_generator = Some(gen_clone);
}

context.vm.push(generator);
Ok(CompletionType::Yield)
}
}

/// `GetReturnValue` implements the Opcode Operation for `Opcode::GetReturnValue`
///
/// Operation:
Expand Down
Loading

0 comments on commit d2b2a1a

Please sign in to comment.