Skip to content

Commit 8be07af

Browse files
committed
fix(vm/opcode/push,environment,templates,generator,await,new): convert panics to EngineError::Panic using js_expect
1 parent 1d0d8cb commit 8be07af

File tree

11 files changed

+141
-93
lines changed

11 files changed

+141
-93
lines changed

core/engine/src/vm/opcode/await/mod.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{
55
Promise, async_generator::AsyncGenerator, generator::GeneratorContext,
66
promise::PromiseCapability,
77
},
8+
error::PanicError,
89
js_string,
910
native_function::NativeFunction,
1011
object::FunctionObjectBuilder,
@@ -34,9 +35,15 @@ impl Await {
3435
value.clone(),
3536
context,
3637
) {
37-
Ok(promise) => promise
38-
.downcast::<Promise>()
39-
.expect("%Promise% constructor must return a `Promise` object"),
38+
Ok(promise) => match promise.downcast::<Promise>().ok() {
39+
Some(v) => v,
40+
None => {
41+
return context.handle_error(
42+
PanicError::new("%Promise% constructor must return a `Promise` object")
43+
.into(),
44+
);
45+
}
46+
},
4047
Err(err) => return context.handle_error(err),
4148
};
4249

@@ -61,7 +68,7 @@ impl Await {
6168
// b. Suspend prevContext.
6269
// c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
6370
// d. Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended it.
64-
let mut r#gen = captures.take().expect("should only run once");
71+
let mut r#gen = captures.take().js_expect("should only run once")?;
6572

6673
// NOTE: We need to get the object before resuming, since it could clear the stack.
6774
let async_generator = r#gen.async_generator_object()?;
@@ -75,7 +82,7 @@ impl Await {
7582
if let Some(async_generator) = async_generator {
7683
async_generator
7784
.downcast_mut::<AsyncGenerator>()
78-
.expect("must be async generator")
85+
.js_expect("must be async generator")?
7986
.context = Some(r#gen);
8087
}
8188

@@ -102,7 +109,7 @@ impl Await {
102109
// d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that suspended it.
103110
// e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
104111
// f. Return undefined.
105-
let mut r#gen = captures.take().expect("should only run once");
112+
let mut r#gen = captures.take().js_expect("should only run once")?;
106113

107114
// NOTE: We need to get the object before resuming, since it could clear the stack.
108115
let async_generator = r#gen.async_generator_object()?;
@@ -116,7 +123,7 @@ impl Await {
116123
if let Some(async_generator) = async_generator {
117124
async_generator
118125
.downcast_mut::<AsyncGenerator>()
119-
.expect("must be async generator")
126+
.js_expect("must be async generator")?
120127
.context = Some(r#gen);
121128
}
122129

core/engine/src/vm/opcode/environment/mod.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl This {
7171
.unwrap_or(context.realm().global_this().clone().into());
7272
context.vm.frame_mut().flags |= CallFrameFlags::THIS_VALUE_CACHED;
7373
context.vm.stack.set_this(
74-
context.vm.frames.last().expect("frame must exist"),
74+
context.vm.frames.last().js_expect("frame must exist")?,
7575
this.clone(),
7676
);
7777
context.vm.set_register(dst.into(), this);
@@ -141,13 +141,13 @@ impl SuperCall {
141141
.environments
142142
.get_this_environment(frame.realm.environment())
143143
.as_function()
144-
.expect("super call must be in function environment")
144+
.js_expect("super call must be in function environment")?
145145
};
146146

147147
let new_target = this_env
148148
.slots()
149149
.new_target()
150-
.expect("must have new.target")
150+
.js_expect("must have new.target")?
151151
.clone();
152152

153153
context.vm.stack.push(new_target);
@@ -179,12 +179,12 @@ impl SuperCallSpread {
179179
let arguments_array = context.vm.stack.pop();
180180
let arguments_array_object = arguments_array
181181
.as_object()
182-
.expect("arguments array in call spread function must be an object");
182+
.js_expect("arguments array in call spread function must be an object")?;
183183
let arguments = arguments_array_object
184184
.borrow()
185185
.properties()
186186
.to_dense_indexed_properties()
187-
.expect("arguments array in call spread function must be dense");
187+
.js_expect("arguments array in call spread function must be dense")?;
188188

189189
let super_constructor = context.vm.stack.pop();
190190

@@ -207,13 +207,13 @@ impl SuperCallSpread {
207207
.environments
208208
.get_this_environment(frame.realm.environment())
209209
.as_function()
210-
.expect("super call must be in function environment")
210+
.js_expect("super call must be in function environment")?
211211
};
212212

213213
let new_target = this_env
214214
.slots()
215215
.new_target()
216-
.expect("must have new.target")
216+
.js_expect("must have new.target")?
217217
.clone();
218218

219219
context.vm.stack.push(new_target);
@@ -247,18 +247,18 @@ impl SuperCallDerived {
247247
.environments
248248
.get_this_environment(frame.realm.environment())
249249
.as_function()
250-
.expect("super call must be in function environment")
250+
.js_expect("super call must be in function environment")?
251251
};
252252
let new_target = this_env
253253
.slots()
254254
.new_target()
255-
.expect("must have new target")
255+
.js_expect("must have new target")?
256256
.clone();
257257
let active_function = this_env.slots().function_object().clone();
258258
let super_constructor = active_function
259259
.__get_prototype_of__(&mut InternalMethodPropertyContext::new(context))
260-
.expect("function object must have prototype")
261-
.expect("function object must have prototype");
260+
.js_expect("function object must have prototype")?
261+
.js_expect("function object must have prototype")?;
262262

263263
if !super_constructor.is_constructor() {
264264
return Err(JsNativeError::typ()
@@ -304,7 +304,7 @@ impl BindThisValue {
304304
.vm
305305
.get_register(value.into())
306306
.as_object()
307-
.expect("construct result should be an object")
307+
.js_expect("construct result should be an object")?
308308
.clone();
309309

310310
// 7. Let thisER be GetThisEnvironment().
@@ -314,7 +314,7 @@ impl BindThisValue {
314314
.environments
315315
.get_this_environment(frame.realm.environment())
316316
.as_function()
317-
.expect("super call must be in function environment")
317+
.js_expect("super call must be in function environment")?
318318
};
319319

320320
// 8. Perform ? thisER.BindThisValue(result).

core/engine/src/vm/opcode/generator/mod.rs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
pub(crate) mod yield_stm;
22

33
use crate::{
4-
Context, JsObject, JsResult,
4+
Context, JsExpect, JsObject, JsResult,
55
builtins::{
66
async_generator::{AsyncGenerator as NativeAsyncGenerator, AsyncGeneratorState},
77
generator::{Generator as NativeGenerator, GeneratorContext, GeneratorState},
88
},
9+
error::PanicError,
910
object::PROTOTYPE,
1011
vm::{CompletionRecord, opcode::Operation},
1112
};
@@ -23,14 +24,19 @@ pub(crate) struct Generator;
2324
impl Generator {
2425
#[inline(always)]
2526
pub(super) fn operation((): (), context: &mut Context) -> ControlFlow<CompletionRecord> {
26-
let active_function = context.vm.stack.get_function(context.vm.frame());
27-
let this_function_object =
28-
active_function.expect("active function should be set to the generator");
27+
let this_function_object = match context.vm.stack.get_function(context.vm.frame()) {
28+
Some(v) => v,
29+
None => {
30+
return context.handle_error(
31+
PanicError::new("active function should be set to the generator").into(),
32+
);
33+
}
34+
};
2935

3036
let proto = this_function_object
3137
.get(PROTOTYPE, context)
32-
.expect("generator must have a prototype property")
33-
.as_object()
38+
.ok()
39+
.and_then(|v| v.as_object())
3440
.unwrap_or_else(|| context.intrinsics().objects().generator());
3541

3642
let generator = JsObject::from_proto_and_data_with_shared_shape(
@@ -67,14 +73,19 @@ pub(crate) struct AsyncGenerator;
6773
impl AsyncGenerator {
6874
#[inline(always)]
6975
pub(super) fn operation((): (), context: &mut Context) -> ControlFlow<CompletionRecord> {
70-
let active_function = context.vm.stack.get_function(context.vm.frame());
71-
let this_function_object =
72-
active_function.expect("active function should be set to the generator");
76+
let this_function_object = match context.vm.stack.get_function(context.vm.frame()) {
77+
Some(v) => v,
78+
None => {
79+
return context.handle_error(
80+
PanicError::new("active function should be set to the generator").into(),
81+
);
82+
}
83+
};
7384

7485
let proto = this_function_object
7586
.get(PROTOTYPE, context)
76-
.expect("generator must have a prototype property")
77-
.as_object()
87+
.ok()
88+
.and_then(|v| v.as_object())
7889
.unwrap_or_else(|| context.intrinsics().objects().async_generator());
7990

8091
let generator = JsObject::from_proto_and_data_with_shared_shape(
@@ -115,9 +126,10 @@ impl AsyncGeneratorClose {
115126
let generator = context
116127
.vm
117128
.async_generator_object()
118-
.expect("There should be a object")
129+
.js_expect("There should be a object")?
119130
.downcast::<NativeAsyncGenerator>()
120-
.expect("must be async generator");
131+
.ok()
132+
.js_expect("must be async generator")?;
121133

122134
let mut r#gen = generator.borrow_mut();
123135

core/engine/src/vm/opcode/generator/yield_stm.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::ops::ControlFlow;
33
use crate::{
44
Context, JsValue,
55
builtins::async_generator::{AsyncGenerator, AsyncGeneratorState},
6+
error::PanicError,
67
vm::{
78
CompletionRecord, GeneratorResumeKind,
89
opcode::{Operation, RegisterOperand},
@@ -54,13 +55,24 @@ impl AsyncGeneratorYield {
5455
// 2. Assert: genContext is the execution context of a generator.
5556
// 3. Let generator be the value of the Generator component of genContext.
5657
// 4. Assert: GetGeneratorKind() is async.
57-
let async_generator_object = context
58-
.vm
59-
.async_generator_object()
60-
.expect("`AsyncGeneratorYield` must only be called inside async generators");
61-
let async_generator_object = async_generator_object
62-
.downcast::<AsyncGenerator>()
63-
.expect("must be async generator object");
58+
let async_generator_object = match context.vm.async_generator_object() {
59+
Some(v) => v,
60+
None => {
61+
return context.handle_error(
62+
PanicError::new(
63+
"`AsyncGeneratorYield` must only be called inside async generators",
64+
)
65+
.into(),
66+
);
67+
}
68+
};
69+
let async_generator_object = match async_generator_object.downcast::<AsyncGenerator>() {
70+
Ok(v) => v,
71+
Err(_) => {
72+
return context
73+
.handle_error(PanicError::new("must be async generator object").into());
74+
}
75+
};
6476

6577
// 5. Let completion be NormalCompletion(value).
6678
let value = context.vm.get_register(value.into());

core/engine/src/vm/opcode/new/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::IndexOperand;
2-
use crate::{Context, JsResult, error::JsNativeError, vm::opcode::Operation};
2+
use crate::{Context, JsExpect, JsResult, error::JsNativeError, vm::opcode::Operation};
33

44
/// `New` implements the Opcode Operation for `Opcode::New`
55
///
@@ -48,12 +48,12 @@ impl NewSpread {
4848
let arguments_array = context.vm.stack.pop();
4949
let arguments_array_object = arguments_array
5050
.as_object()
51-
.expect("arguments array in call spread function must be an object");
51+
.js_expect("arguments array in call spread function must be an object")?;
5252
let arguments = arguments_array_object
5353
.borrow()
5454
.properties()
5555
.to_dense_indexed_properties()
56-
.expect("arguments array in call spread function must be dense");
56+
.js_expect("arguments array in call spread function must be dense")?;
5757

5858
let func = context.vm.stack.pop();
5959

core/engine/src/vm/opcode/push/array.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
Context, JsResult, JsValue,
2+
Context, JsExpect, JsResult, JsValue,
33
builtins::Array,
44
string::StaticJsStrings,
55
vm::opcode::{Operation, RegisterOperand},
@@ -42,13 +42,13 @@ impl PushValueToArray {
4242
pub(crate) fn operation(
4343
(value, array): (RegisterOperand, RegisterOperand),
4444
context: &mut Context,
45-
) {
45+
) -> JsResult<()> {
4646
let value = context.vm.get_register(value.into()).clone();
4747
let o = context
4848
.vm
4949
.get_register(array.into())
5050
.as_object()
51-
.expect("should be an object");
51+
.js_expect("should be an object")?;
5252

5353
// Fast path: push directly to dense indexed storage.
5454
{
@@ -58,16 +58,17 @@ impl PushValueToArray {
5858
&& o_mut.properties_mut().indexed_properties.push_dense(&value)
5959
{
6060
o_mut.properties_mut().storage[0] = JsValue::new(len + 1);
61-
return;
61+
return Ok(());
6262
}
6363
}
6464

6565
// Slow path: fall through to the generic property machinery.
6666
let len = o
6767
.length_of_array_like(context)
68-
.expect("should have 'length' property");
68+
.js_expect("should have 'length' property")?;
6969
o.create_data_property_or_throw(len, value, context)
70-
.expect("should be able to create new data property");
70+
.js_expect("should be able to create new data property")?;
71+
Ok(())
7172
}
7273
}
7374

@@ -88,10 +89,10 @@ impl PushElisionToArray {
8889
#[inline(always)]
8990
pub(crate) fn operation(array: RegisterOperand, context: &mut Context) -> JsResult<()> {
9091
let array = context.vm.get_register(array.into()).clone();
91-
let o = array.as_object().expect("should always be an object");
92+
let o = array.as_object().js_expect("should always be an object")?;
9293
let len = o
9394
.length_of_array_like(context)
94-
.expect("arrays should always have a 'length' property");
95+
.js_expect("arrays should always have a 'length' property")?;
9596
o.set(StaticJsStrings::LENGTH, len + 1, true, context)?;
9697
o.borrow_mut()
9798
.properties_mut()
@@ -123,7 +124,7 @@ impl PushIteratorToArray {
123124
.frame_mut()
124125
.iterators
125126
.pop()
126-
.expect("iterator stack should have at least an iterator");
127+
.js_expect("iterator stack should have at least an iterator")?;
127128
while let Some(next) = iterator.step_value(context)? {
128129
Array::push(&array, &[next], context)?;
129130
}

0 commit comments

Comments
 (0)