mustardscript 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -22
- package/SECURITY.md +1 -1
- package/dist/index.js +2 -0
- package/dist/lib/executor.js +16 -1
- package/dist/lib/policy.js +301 -22
- package/dist/lib/progress.js +499 -113
- package/dist/lib/runtime.js +109 -40
- package/dist/lib/structured.js +327 -11
- package/dist/native-loader.js +11 -12
- package/index.d.ts +54 -6
- package/mustard.d.ts +23 -1
- package/package.json +34 -25
- package/Cargo.lock +0 -1579
- package/Cargo.toml +0 -40
- package/crates/mustard/Cargo.toml +0 -31
- package/crates/mustard/src/cancellation.rs +0 -28
- package/crates/mustard/src/diagnostic.rs +0 -145
- package/crates/mustard/src/ir.rs +0 -435
- package/crates/mustard/src/lib.rs +0 -21
- package/crates/mustard/src/limits.rs +0 -22
- package/crates/mustard/src/parser/expressions.rs +0 -723
- package/crates/mustard/src/parser/mod.rs +0 -115
- package/crates/mustard/src/parser/operators.rs +0 -105
- package/crates/mustard/src/parser/patterns.rs +0 -123
- package/crates/mustard/src/parser/scope.rs +0 -107
- package/crates/mustard/src/parser/statements.rs +0 -298
- package/crates/mustard/src/parser/tests/acceptance.rs +0 -339
- package/crates/mustard/src/parser/tests/mod.rs +0 -2
- package/crates/mustard/src/parser/tests/rejections.rs +0 -107
- package/crates/mustard/src/runtime/accounting.rs +0 -613
- package/crates/mustard/src/runtime/api.rs +0 -192
- package/crates/mustard/src/runtime/async_runtime/mod.rs +0 -5
- package/crates/mustard/src/runtime/async_runtime/promises.rs +0 -246
- package/crates/mustard/src/runtime/async_runtime/reactions.rs +0 -400
- package/crates/mustard/src/runtime/async_runtime/scheduler.rs +0 -224
- package/crates/mustard/src/runtime/builtins/arrays.rs +0 -1205
- package/crates/mustard/src/runtime/builtins/collections.rs +0 -573
- package/crates/mustard/src/runtime/builtins/install.rs +0 -501
- package/crates/mustard/src/runtime/builtins/intl.rs +0 -553
- package/crates/mustard/src/runtime/builtins/mod.rs +0 -25
- package/crates/mustard/src/runtime/builtins/objects.rs +0 -405
- package/crates/mustard/src/runtime/builtins/primitives.rs +0 -859
- package/crates/mustard/src/runtime/builtins/promises.rs +0 -335
- package/crates/mustard/src/runtime/builtins/regexp.rs +0 -356
- package/crates/mustard/src/runtime/builtins/strings.rs +0 -803
- package/crates/mustard/src/runtime/builtins/support.rs +0 -561
- package/crates/mustard/src/runtime/bytecode.rs +0 -123
- package/crates/mustard/src/runtime/compiler/assignments.rs +0 -690
- package/crates/mustard/src/runtime/compiler/bindings.rs +0 -92
- package/crates/mustard/src/runtime/compiler/context.rs +0 -46
- package/crates/mustard/src/runtime/compiler/control.rs +0 -342
- package/crates/mustard/src/runtime/compiler/expressions.rs +0 -372
- package/crates/mustard/src/runtime/compiler/mod.rs +0 -173
- package/crates/mustard/src/runtime/compiler/statements.rs +0 -459
- package/crates/mustard/src/runtime/conversions/boundary.rs +0 -293
- package/crates/mustard/src/runtime/conversions/coercions.rs +0 -217
- package/crates/mustard/src/runtime/conversions/errors.rs +0 -118
- package/crates/mustard/src/runtime/conversions/mod.rs +0 -14
- package/crates/mustard/src/runtime/conversions/operators.rs +0 -334
- package/crates/mustard/src/runtime/env.rs +0 -355
- package/crates/mustard/src/runtime/exceptions.rs +0 -377
- package/crates/mustard/src/runtime/gc.rs +0 -595
- package/crates/mustard/src/runtime/mod.rs +0 -318
- package/crates/mustard/src/runtime/properties.rs +0 -1762
- package/crates/mustard/src/runtime/serialization.rs +0 -127
- package/crates/mustard/src/runtime/shared.rs +0 -108
- package/crates/mustard/src/runtime/snapshot_validation_tests.rs +0 -93
- package/crates/mustard/src/runtime/state.rs +0 -652
- package/crates/mustard/src/runtime/tests/async_host.rs +0 -104
- package/crates/mustard/src/runtime/tests/collections.rs +0 -50
- package/crates/mustard/src/runtime/tests/diagnostics.rs +0 -36
- package/crates/mustard/src/runtime/tests/exceptions.rs +0 -122
- package/crates/mustard/src/runtime/tests/execution.rs +0 -553
- package/crates/mustard/src/runtime/tests/gc.rs +0 -533
- package/crates/mustard/src/runtime/tests/mod.rs +0 -56
- package/crates/mustard/src/runtime/tests/serialization.rs +0 -170
- package/crates/mustard/src/runtime/validation/bytecode.rs +0 -484
- package/crates/mustard/src/runtime/validation/mod.rs +0 -14
- package/crates/mustard/src/runtime/validation/policy.rs +0 -94
- package/crates/mustard/src/runtime/validation/snapshot.rs +0 -406
- package/crates/mustard/src/runtime/validation/walk.rs +0 -206
- package/crates/mustard/src/runtime/vm.rs +0 -1016
- package/crates/mustard/src/span.rs +0 -22
- package/crates/mustard/src/structured.rs +0 -107
- package/crates/mustard-bridge/Cargo.toml +0 -17
- package/crates/mustard-bridge/src/codec.rs +0 -46
- package/crates/mustard-bridge/src/dto.rs +0 -99
- package/crates/mustard-bridge/src/lib.rs +0 -12
- package/crates/mustard-bridge/src/operations.rs +0 -142
- package/crates/mustard-node/Cargo.toml +0 -24
- package/crates/mustard-node/build.rs +0 -3
- package/crates/mustard-node/src/lib.rs +0 -236
- package/crates/mustard-sidecar/Cargo.toml +0 -21
- package/crates/mustard-sidecar/src/lib.rs +0 -134
- package/crates/mustard-sidecar/src/main.rs +0 -36
- package/dist/install.js +0 -117
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
use super::*;
|
|
2
|
-
|
|
3
|
-
#[test]
|
|
4
|
-
fn round_trips_program_and_snapshot() {
|
|
5
|
-
let source = "const value = fetch_data(1); value + 2;";
|
|
6
|
-
let program = compile(source).expect("compile should succeed");
|
|
7
|
-
let bytecode = lower_to_bytecode(&program).expect("lowering should succeed");
|
|
8
|
-
let program_bytes = dump_program(&bytecode).expect("program dump should succeed");
|
|
9
|
-
let loaded_program = load_program(&program_bytes).expect("program load should succeed");
|
|
10
|
-
assert_eq!(loaded_program.root, bytecode.root);
|
|
11
|
-
assert_eq!(loaded_program.functions.len(), bytecode.functions.len());
|
|
12
|
-
|
|
13
|
-
let suspension = suspend(source, &["fetch_data"]);
|
|
14
|
-
let snapshot_bytes = dump_snapshot(&suspension.snapshot).expect("snapshot dump should succeed");
|
|
15
|
-
let loaded_snapshot = load_snapshot(&snapshot_bytes).expect("snapshot load should succeed");
|
|
16
|
-
let resumed = resume_with_options(
|
|
17
|
-
loaded_snapshot,
|
|
18
|
-
ResumePayload::Value(number(1.0)),
|
|
19
|
-
ResumeOptions {
|
|
20
|
-
cancellation_token: None,
|
|
21
|
-
snapshot_policy: Some(SnapshotPolicy {
|
|
22
|
-
capabilities: vec!["fetch_data".to_string()],
|
|
23
|
-
limits: RuntimeLimits::default(),
|
|
24
|
-
}),
|
|
25
|
-
},
|
|
26
|
-
)
|
|
27
|
-
.expect("resume should succeed");
|
|
28
|
-
match resumed {
|
|
29
|
-
ExecutionStep::Completed(value) => {
|
|
30
|
-
assert_eq!(value, number(3.0));
|
|
31
|
-
}
|
|
32
|
-
other => panic!("expected completion, got {other:?}"),
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
#[test]
|
|
37
|
-
fn rejects_invalid_jump_targets_before_execution() {
|
|
38
|
-
let program = invalid_program(vec![Instruction::Jump(99), Instruction::Return]);
|
|
39
|
-
let error = start_bytecode(&program, ExecutionOptions::default())
|
|
40
|
-
.expect_err("invalid jump target should fail validation");
|
|
41
|
-
assert!(error.to_string().contains("jumps to invalid target 99"));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
#[test]
|
|
45
|
-
fn rejects_inconsistent_stack_depth_in_serialized_programs() {
|
|
46
|
-
let program = invalid_program(vec![
|
|
47
|
-
Instruction::PushNumber(1.0),
|
|
48
|
-
Instruction::JumpIfTrue(3),
|
|
49
|
-
Instruction::Pop,
|
|
50
|
-
Instruction::Return,
|
|
51
|
-
]);
|
|
52
|
-
let bytes = dump_program(&program).expect("invalid program still serializes");
|
|
53
|
-
let error =
|
|
54
|
-
load_program(&bytes).expect_err("invalid serialized program should fail validation");
|
|
55
|
-
assert!(
|
|
56
|
-
error
|
|
57
|
-
.to_string()
|
|
58
|
-
.contains("has inconsistent validation state")
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
#[test]
|
|
63
|
-
fn rejects_cross_version_serialized_programs() {
|
|
64
|
-
let program = lower_to_bytecode(&compile("1;").expect("compile should succeed"))
|
|
65
|
-
.expect("lowering should succeed");
|
|
66
|
-
let mut bytes = dump_program(&program).expect("program should serialize");
|
|
67
|
-
bytes[0] = bytes[0].saturating_add(1);
|
|
68
|
-
let error = load_program(&bytes).expect_err("cross-version program should be rejected");
|
|
69
|
-
assert!(
|
|
70
|
-
error
|
|
71
|
-
.to_string()
|
|
72
|
-
.contains("serialized program version mismatch")
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
#[test]
|
|
77
|
-
fn rejects_invalid_snapshot_frame_state() {
|
|
78
|
-
let mut suspension = suspend("const value = fetch_data(1); value + 2;", &["fetch_data"]);
|
|
79
|
-
suspension.snapshot.runtime.frames[0].ip = 999;
|
|
80
|
-
let bytes = dump_snapshot(&suspension.snapshot).expect("snapshot should serialize");
|
|
81
|
-
let error = load_snapshot(&bytes).expect_err("invalid snapshot should fail validation");
|
|
82
|
-
assert!(
|
|
83
|
-
error
|
|
84
|
-
.to_string()
|
|
85
|
-
.contains("frame instruction pointer 999 is out of range")
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
#[test]
|
|
90
|
-
fn direct_execution_snapshot_deserialize_reruns_validation() {
|
|
91
|
-
let mut suspension = suspend("const value = fetch_data(1); value + 2;", &["fetch_data"]);
|
|
92
|
-
suspension.snapshot.runtime.frames[0].ip = 999;
|
|
93
|
-
let bytes =
|
|
94
|
-
bincode::serialize(&suspension.snapshot).expect("snapshot should serialize directly");
|
|
95
|
-
let error = bincode::deserialize::<ExecutionSnapshot>(&bytes)
|
|
96
|
-
.expect_err("invalid snapshots should fail validation during direct deserialize");
|
|
97
|
-
assert!(
|
|
98
|
-
error
|
|
99
|
-
.to_string()
|
|
100
|
-
.contains("frame instruction pointer 999 is out of range")
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
#[test]
|
|
105
|
-
fn rejects_cross_version_snapshots() {
|
|
106
|
-
let suspension = suspend("const value = fetch_data(1); value + 2;", &["fetch_data"]);
|
|
107
|
-
|
|
108
|
-
let mut bytes = dump_snapshot(&suspension.snapshot).expect("snapshot should serialize");
|
|
109
|
-
bytes[0] = bytes[0].saturating_add(1);
|
|
110
|
-
let error = load_snapshot(&bytes).expect_err("cross-version snapshot should be rejected");
|
|
111
|
-
assert!(
|
|
112
|
-
error
|
|
113
|
-
.to_string()
|
|
114
|
-
.contains("serialized snapshot version mismatch")
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
#[test]
|
|
119
|
-
fn rejects_out_of_range_promise_combinator_snapshot_state() {
|
|
120
|
-
let mut suspension = suspend(
|
|
121
|
-
r#"
|
|
122
|
-
async function main() {
|
|
123
|
-
return Promise.all([fetch_data(1), fetch_data(2)]);
|
|
124
|
-
}
|
|
125
|
-
main();
|
|
126
|
-
"#,
|
|
127
|
-
&["fetch_data"],
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
let target = suspension
|
|
131
|
-
.snapshot
|
|
132
|
-
.runtime
|
|
133
|
-
.promises
|
|
134
|
-
.iter()
|
|
135
|
-
.find_map(|(key, promise)| match promise.driver.as_ref() {
|
|
136
|
-
Some(PromiseDriver::All { .. }) => Some(key),
|
|
137
|
-
_ => None,
|
|
138
|
-
})
|
|
139
|
-
.expect("Promise.all target should exist");
|
|
140
|
-
|
|
141
|
-
let mutated = suspension
|
|
142
|
-
.snapshot
|
|
143
|
-
.runtime
|
|
144
|
-
.promises
|
|
145
|
-
.values_mut()
|
|
146
|
-
.find_map(|promise| {
|
|
147
|
-
promise.reactions.iter_mut().find_map(|reaction| match reaction {
|
|
148
|
-
PromiseReaction::Combinator {
|
|
149
|
-
target: reaction_target,
|
|
150
|
-
index,
|
|
151
|
-
..
|
|
152
|
-
} if *reaction_target == target => {
|
|
153
|
-
*index = 99;
|
|
154
|
-
Some(())
|
|
155
|
-
}
|
|
156
|
-
_ => None,
|
|
157
|
-
})
|
|
158
|
-
});
|
|
159
|
-
assert!(mutated.is_some(), "Promise.all combinator reaction should exist");
|
|
160
|
-
|
|
161
|
-
let bytes = dump_snapshot(&suspension.snapshot).expect("snapshot should serialize");
|
|
162
|
-
let error = load_snapshot(&bytes).expect_err("forged snapshot should fail validation");
|
|
163
|
-
assert!(
|
|
164
|
-
error
|
|
165
|
-
.to_string()
|
|
166
|
-
.contains("promise")
|
|
167
|
-
&& error.to_string().contains("combinator index"),
|
|
168
|
-
"unexpected error: {error}"
|
|
169
|
-
);
|
|
170
|
-
}
|
|
@@ -1,484 +0,0 @@
|
|
|
1
|
-
use super::*;
|
|
2
|
-
|
|
3
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
4
|
-
struct ValidationState {
|
|
5
|
-
stack_depth: usize,
|
|
6
|
-
scope_depth: usize,
|
|
7
|
-
handler_depth: usize,
|
|
8
|
-
pending_depth: usize,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
pub(in crate::runtime) fn validate_bytecode_program(
|
|
12
|
-
program: &BytecodeProgram,
|
|
13
|
-
) -> MustardResult<()> {
|
|
14
|
-
if program.functions.is_empty() {
|
|
15
|
-
return Err(MustardError::validation(
|
|
16
|
-
"bytecode validation failed: program defines no functions",
|
|
17
|
-
None,
|
|
18
|
-
));
|
|
19
|
-
}
|
|
20
|
-
if program.root >= program.functions.len() {
|
|
21
|
-
return Err(MustardError::validation(
|
|
22
|
-
format!(
|
|
23
|
-
"bytecode validation failed: root function {} is out of range for {} functions",
|
|
24
|
-
program.root,
|
|
25
|
-
program.functions.len()
|
|
26
|
-
),
|
|
27
|
-
None,
|
|
28
|
-
));
|
|
29
|
-
}
|
|
30
|
-
for (function_id, function) in program.functions.iter().enumerate() {
|
|
31
|
-
validate_function(program, function_id, function)?;
|
|
32
|
-
}
|
|
33
|
-
Ok(())
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
fn validate_function(
|
|
37
|
-
program: &BytecodeProgram,
|
|
38
|
-
function_id: usize,
|
|
39
|
-
function: &FunctionPrototype,
|
|
40
|
-
) -> MustardResult<()> {
|
|
41
|
-
if function.code.is_empty() {
|
|
42
|
-
return Err(MustardError::validation(
|
|
43
|
-
format!("bytecode validation failed: function {function_id} has no instructions"),
|
|
44
|
-
None,
|
|
45
|
-
));
|
|
46
|
-
}
|
|
47
|
-
if !matches!(function.code.last(), Some(Instruction::Return)) {
|
|
48
|
-
return Err(MustardError::validation(
|
|
49
|
-
format!("bytecode validation failed: function {function_id} does not end in Return"),
|
|
50
|
-
None,
|
|
51
|
-
));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let code_len = function.code.len();
|
|
55
|
-
for (ip, instruction) in function.code.iter().enumerate() {
|
|
56
|
-
match instruction {
|
|
57
|
-
Instruction::MakeClosure {
|
|
58
|
-
function_id: target,
|
|
59
|
-
} if *target >= program.functions.len() => {
|
|
60
|
-
return Err(MustardError::validation(
|
|
61
|
-
format!(
|
|
62
|
-
"bytecode validation failed: function {function_id} instruction {ip} references missing closure target {target}"
|
|
63
|
-
),
|
|
64
|
-
None,
|
|
65
|
-
));
|
|
66
|
-
}
|
|
67
|
-
Instruction::Jump(target)
|
|
68
|
-
| Instruction::JumpIfFalse(target)
|
|
69
|
-
| Instruction::JumpIfTrue(target)
|
|
70
|
-
| Instruction::JumpIfNullish(target)
|
|
71
|
-
| Instruction::EnterFinally { exit: target }
|
|
72
|
-
| Instruction::PushPendingJump { target, .. }
|
|
73
|
-
if *target >= code_len =>
|
|
74
|
-
{
|
|
75
|
-
return Err(MustardError::validation(
|
|
76
|
-
format!(
|
|
77
|
-
"bytecode validation failed: function {function_id} instruction {ip} jumps to invalid target {target}"
|
|
78
|
-
),
|
|
79
|
-
None,
|
|
80
|
-
));
|
|
81
|
-
}
|
|
82
|
-
Instruction::PushHandler { catch, finally }
|
|
83
|
-
if catch.is_some_and(|target| target >= code_len)
|
|
84
|
-
|| finally.is_some_and(|target| target >= code_len) =>
|
|
85
|
-
{
|
|
86
|
-
return Err(MustardError::validation(
|
|
87
|
-
format!(
|
|
88
|
-
"bytecode validation failed: function {function_id} instruction {ip} references an invalid exception target"
|
|
89
|
-
),
|
|
90
|
-
None,
|
|
91
|
-
));
|
|
92
|
-
}
|
|
93
|
-
_ => {}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
let mut states = vec![None; code_len];
|
|
98
|
-
let mut work = VecDeque::from([(
|
|
99
|
-
0usize,
|
|
100
|
-
ValidationState {
|
|
101
|
-
stack_depth: 0,
|
|
102
|
-
scope_depth: 0,
|
|
103
|
-
handler_depth: 0,
|
|
104
|
-
pending_depth: 0,
|
|
105
|
-
},
|
|
106
|
-
)]);
|
|
107
|
-
while let Some((ip, state)) = work.pop_front() {
|
|
108
|
-
if let Some(existing) = states[ip] {
|
|
109
|
-
if existing != state {
|
|
110
|
-
return Err(MustardError::validation(
|
|
111
|
-
format!(
|
|
112
|
-
"bytecode validation failed: function {function_id} instruction {ip} has inconsistent validation state: existing={existing:?}, new={state:?}"
|
|
113
|
-
),
|
|
114
|
-
None,
|
|
115
|
-
));
|
|
116
|
-
}
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
states[ip] = Some(state);
|
|
120
|
-
|
|
121
|
-
let instruction = &function.code[ip];
|
|
122
|
-
let next_state = apply_validation_effect(function_id, ip, instruction, state)?;
|
|
123
|
-
for successor in validation_successors(ip, instruction, code_len) {
|
|
124
|
-
work.push_back((successor, next_state));
|
|
125
|
-
}
|
|
126
|
-
match instruction {
|
|
127
|
-
Instruction::PushHandler { catch, finally } => {
|
|
128
|
-
if let Some(target) = catch {
|
|
129
|
-
work.push_back((
|
|
130
|
-
*target,
|
|
131
|
-
ValidationState {
|
|
132
|
-
handler_depth: state.handler_depth,
|
|
133
|
-
..state
|
|
134
|
-
},
|
|
135
|
-
));
|
|
136
|
-
} else if let Some(target) = finally {
|
|
137
|
-
work.push_back((
|
|
138
|
-
*target,
|
|
139
|
-
ValidationState {
|
|
140
|
-
handler_depth: state.handler_depth,
|
|
141
|
-
pending_depth: state.pending_depth + 1,
|
|
142
|
-
..state
|
|
143
|
-
},
|
|
144
|
-
));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
Instruction::PushPendingJump {
|
|
148
|
-
target,
|
|
149
|
-
target_handler_depth,
|
|
150
|
-
target_scope_depth,
|
|
151
|
-
} => {
|
|
152
|
-
work.push_back((
|
|
153
|
-
*target,
|
|
154
|
-
ValidationState {
|
|
155
|
-
scope_depth: *target_scope_depth,
|
|
156
|
-
handler_depth: *target_handler_depth,
|
|
157
|
-
..state
|
|
158
|
-
},
|
|
159
|
-
));
|
|
160
|
-
}
|
|
161
|
-
_ => {}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
Ok(())
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
fn apply_validation_effect(
|
|
169
|
-
function_id: usize,
|
|
170
|
-
ip: usize,
|
|
171
|
-
instruction: &Instruction,
|
|
172
|
-
state: ValidationState,
|
|
173
|
-
) -> MustardResult<ValidationState> {
|
|
174
|
-
let require_stack = |count: usize| -> MustardResult<()> {
|
|
175
|
-
if state.stack_depth < count {
|
|
176
|
-
return Err(MustardError::validation(
|
|
177
|
-
format!(
|
|
178
|
-
"bytecode validation failed: function {function_id} instruction {ip} requires stack depth {count}, found {}",
|
|
179
|
-
state.stack_depth
|
|
180
|
-
),
|
|
181
|
-
None,
|
|
182
|
-
));
|
|
183
|
-
}
|
|
184
|
-
Ok(())
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
let next = match instruction {
|
|
188
|
-
Instruction::PushUndefined
|
|
189
|
-
| Instruction::PushNull
|
|
190
|
-
| Instruction::PushBool(_)
|
|
191
|
-
| Instruction::PushNumber(_)
|
|
192
|
-
| Instruction::PushBigInt(_)
|
|
193
|
-
| Instruction::PushString(_)
|
|
194
|
-
| Instruction::PushRegExp { .. }
|
|
195
|
-
| Instruction::LoadName(_)
|
|
196
|
-
| Instruction::LoadGlobalObject
|
|
197
|
-
| Instruction::MakeClosure { .. }
|
|
198
|
-
| Instruction::BeginCatch => ValidationState {
|
|
199
|
-
stack_depth: state.stack_depth + 1,
|
|
200
|
-
..state
|
|
201
|
-
},
|
|
202
|
-
Instruction::StoreName(_) => {
|
|
203
|
-
require_stack(1)?;
|
|
204
|
-
state
|
|
205
|
-
}
|
|
206
|
-
Instruction::InitializePattern(_) | Instruction::Pop => {
|
|
207
|
-
require_stack(1)?;
|
|
208
|
-
ValidationState {
|
|
209
|
-
stack_depth: state.stack_depth - 1,
|
|
210
|
-
..state
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
Instruction::PushEnv => ValidationState {
|
|
214
|
-
scope_depth: state.scope_depth + 1,
|
|
215
|
-
..state
|
|
216
|
-
},
|
|
217
|
-
Instruction::PopEnv => {
|
|
218
|
-
if state.scope_depth == 0 {
|
|
219
|
-
return Err(MustardError::validation(
|
|
220
|
-
format!(
|
|
221
|
-
"bytecode validation failed: function {function_id} instruction {ip} pops an empty scope stack"
|
|
222
|
-
),
|
|
223
|
-
None,
|
|
224
|
-
));
|
|
225
|
-
}
|
|
226
|
-
ValidationState {
|
|
227
|
-
scope_depth: state.scope_depth - 1,
|
|
228
|
-
..state
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
Instruction::DeclareName { .. } => state,
|
|
232
|
-
Instruction::MakeArray { count } => {
|
|
233
|
-
require_stack(*count)?;
|
|
234
|
-
ValidationState {
|
|
235
|
-
stack_depth: state.stack_depth - count + 1,
|
|
236
|
-
..state
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
Instruction::ArrayPush => {
|
|
240
|
-
require_stack(2)?;
|
|
241
|
-
state
|
|
242
|
-
}
|
|
243
|
-
Instruction::ArrayPushHole => {
|
|
244
|
-
require_stack(1)?;
|
|
245
|
-
state
|
|
246
|
-
}
|
|
247
|
-
Instruction::ArrayExtend => {
|
|
248
|
-
require_stack(2)?;
|
|
249
|
-
ValidationState {
|
|
250
|
-
stack_depth: state.stack_depth - 1,
|
|
251
|
-
..state
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
Instruction::MakeObject { keys } => {
|
|
255
|
-
require_stack(keys.len())?;
|
|
256
|
-
ValidationState {
|
|
257
|
-
stack_depth: state.stack_depth - keys.len() + 1,
|
|
258
|
-
..state
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
Instruction::CopyDataProperties => {
|
|
262
|
-
require_stack(2)?;
|
|
263
|
-
ValidationState {
|
|
264
|
-
stack_depth: state.stack_depth - 1,
|
|
265
|
-
..state
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
Instruction::CreateIterator => {
|
|
269
|
-
require_stack(1)?;
|
|
270
|
-
state
|
|
271
|
-
}
|
|
272
|
-
Instruction::IteratorNext => {
|
|
273
|
-
require_stack(1)?;
|
|
274
|
-
ValidationState {
|
|
275
|
-
stack_depth: state.stack_depth + 1,
|
|
276
|
-
..state
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
Instruction::GetPropStatic { .. } => {
|
|
280
|
-
require_stack(1)?;
|
|
281
|
-
state
|
|
282
|
-
}
|
|
283
|
-
Instruction::GetPropComputed { .. } => {
|
|
284
|
-
require_stack(2)?;
|
|
285
|
-
ValidationState {
|
|
286
|
-
stack_depth: state.stack_depth - 1,
|
|
287
|
-
..state
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
Instruction::PatternArrayIndex(_)
|
|
291
|
-
| Instruction::PatternArrayRest(_)
|
|
292
|
-
| Instruction::PatternObjectRest(_)
|
|
293
|
-
| Instruction::Update(_) => {
|
|
294
|
-
require_stack(1)?;
|
|
295
|
-
state
|
|
296
|
-
}
|
|
297
|
-
Instruction::SetPropStatic { .. } => {
|
|
298
|
-
require_stack(2)?;
|
|
299
|
-
ValidationState {
|
|
300
|
-
stack_depth: state.stack_depth - 1,
|
|
301
|
-
..state
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
Instruction::SetPropComputed => {
|
|
305
|
-
require_stack(3)?;
|
|
306
|
-
ValidationState {
|
|
307
|
-
stack_depth: state.stack_depth - 2,
|
|
308
|
-
..state
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
Instruction::Unary(_) => {
|
|
312
|
-
require_stack(1)?;
|
|
313
|
-
state
|
|
314
|
-
}
|
|
315
|
-
Instruction::Binary(_) => {
|
|
316
|
-
require_stack(2)?;
|
|
317
|
-
ValidationState {
|
|
318
|
-
stack_depth: state.stack_depth - 1,
|
|
319
|
-
..state
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
Instruction::Dup => {
|
|
323
|
-
require_stack(1)?;
|
|
324
|
-
ValidationState {
|
|
325
|
-
stack_depth: state.stack_depth + 1,
|
|
326
|
-
..state
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
Instruction::Dup2 => {
|
|
330
|
-
require_stack(2)?;
|
|
331
|
-
ValidationState {
|
|
332
|
-
stack_depth: state.stack_depth + 2,
|
|
333
|
-
..state
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
Instruction::PushHandler { .. } => ValidationState {
|
|
337
|
-
handler_depth: state.handler_depth + 1,
|
|
338
|
-
..state
|
|
339
|
-
},
|
|
340
|
-
Instruction::PopHandler => {
|
|
341
|
-
if state.handler_depth == 0 {
|
|
342
|
-
return Err(MustardError::validation(
|
|
343
|
-
format!(
|
|
344
|
-
"bytecode validation failed: function {function_id} instruction {ip} pops an empty handler stack"
|
|
345
|
-
),
|
|
346
|
-
None,
|
|
347
|
-
));
|
|
348
|
-
}
|
|
349
|
-
ValidationState {
|
|
350
|
-
handler_depth: state.handler_depth - 1,
|
|
351
|
-
..state
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
Instruction::EnterFinally { .. } => state,
|
|
355
|
-
Instruction::Throw { .. } => {
|
|
356
|
-
require_stack(1)?;
|
|
357
|
-
state
|
|
358
|
-
}
|
|
359
|
-
Instruction::PushPendingJump {
|
|
360
|
-
target_handler_depth,
|
|
361
|
-
target_scope_depth,
|
|
362
|
-
..
|
|
363
|
-
} => {
|
|
364
|
-
if *target_handler_depth > state.handler_depth {
|
|
365
|
-
return Err(MustardError::validation(
|
|
366
|
-
format!(
|
|
367
|
-
"bytecode validation failed: function {function_id} instruction {ip} targets handler depth {target_handler_depth} from depth {}",
|
|
368
|
-
state.handler_depth
|
|
369
|
-
),
|
|
370
|
-
None,
|
|
371
|
-
));
|
|
372
|
-
}
|
|
373
|
-
if *target_scope_depth > state.scope_depth {
|
|
374
|
-
return Err(MustardError::validation(
|
|
375
|
-
format!(
|
|
376
|
-
"bytecode validation failed: function {function_id} instruction {ip} targets scope depth {target_scope_depth} from depth {}",
|
|
377
|
-
state.scope_depth
|
|
378
|
-
),
|
|
379
|
-
None,
|
|
380
|
-
));
|
|
381
|
-
}
|
|
382
|
-
ValidationState {
|
|
383
|
-
pending_depth: state.pending_depth + 1,
|
|
384
|
-
..state
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
Instruction::PushPendingReturn => {
|
|
388
|
-
require_stack(1)?;
|
|
389
|
-
ValidationState {
|
|
390
|
-
stack_depth: state.stack_depth - 1,
|
|
391
|
-
pending_depth: state.pending_depth + 1,
|
|
392
|
-
..state
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
Instruction::PushPendingThrow => {
|
|
396
|
-
require_stack(1)?;
|
|
397
|
-
ValidationState {
|
|
398
|
-
stack_depth: state.stack_depth - 1,
|
|
399
|
-
pending_depth: state.pending_depth + 1,
|
|
400
|
-
..state
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
Instruction::ContinuePending => {
|
|
404
|
-
if state.pending_depth == 0 {
|
|
405
|
-
return Err(MustardError::validation(
|
|
406
|
-
format!(
|
|
407
|
-
"bytecode validation failed: function {function_id} instruction {ip} resumes without a pending completion"
|
|
408
|
-
),
|
|
409
|
-
None,
|
|
410
|
-
));
|
|
411
|
-
}
|
|
412
|
-
ValidationState {
|
|
413
|
-
pending_depth: state.pending_depth - 1,
|
|
414
|
-
..state
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
Instruction::Jump(_) => state,
|
|
418
|
-
Instruction::JumpIfFalse(_)
|
|
419
|
-
| Instruction::JumpIfTrue(_)
|
|
420
|
-
| Instruction::JumpIfNullish(_) => {
|
|
421
|
-
require_stack(1)?;
|
|
422
|
-
state
|
|
423
|
-
}
|
|
424
|
-
Instruction::Call {
|
|
425
|
-
argc, with_this, ..
|
|
426
|
-
} => {
|
|
427
|
-
let required = argc + 1 + usize::from(*with_this);
|
|
428
|
-
require_stack(required)?;
|
|
429
|
-
ValidationState {
|
|
430
|
-
stack_depth: state.stack_depth - required + 1,
|
|
431
|
-
..state
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
Instruction::CallWithArray { with_this, .. } => {
|
|
435
|
-
let required = 2 + usize::from(*with_this);
|
|
436
|
-
require_stack(required)?;
|
|
437
|
-
ValidationState {
|
|
438
|
-
stack_depth: state.stack_depth - required + 1,
|
|
439
|
-
..state
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
Instruction::Await => {
|
|
443
|
-
require_stack(1)?;
|
|
444
|
-
state
|
|
445
|
-
}
|
|
446
|
-
Instruction::Construct { argc } => {
|
|
447
|
-
let required = argc + 1;
|
|
448
|
-
require_stack(required)?;
|
|
449
|
-
ValidationState {
|
|
450
|
-
stack_depth: state.stack_depth - required + 1,
|
|
451
|
-
..state
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
Instruction::ConstructWithArray => {
|
|
455
|
-
require_stack(2)?;
|
|
456
|
-
ValidationState {
|
|
457
|
-
stack_depth: state.stack_depth - 1,
|
|
458
|
-
..state
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
Instruction::Return => state,
|
|
462
|
-
};
|
|
463
|
-
Ok(next)
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
fn validation_successors(ip: usize, instruction: &Instruction, code_len: usize) -> Vec<usize> {
|
|
467
|
-
match instruction {
|
|
468
|
-
Instruction::Jump(target) => vec![*target],
|
|
469
|
-
Instruction::JumpIfFalse(target)
|
|
470
|
-
| Instruction::JumpIfTrue(target)
|
|
471
|
-
| Instruction::JumpIfNullish(target) => {
|
|
472
|
-
let mut successors = vec![*target];
|
|
473
|
-
if ip + 1 < code_len {
|
|
474
|
-
successors.push(ip + 1);
|
|
475
|
-
}
|
|
476
|
-
successors
|
|
477
|
-
}
|
|
478
|
-
Instruction::ContinuePending | Instruction::Throw { .. } | Instruction::Return => {
|
|
479
|
-
Vec::new()
|
|
480
|
-
}
|
|
481
|
-
_ if ip + 1 < code_len => vec![ip + 1],
|
|
482
|
-
_ => Vec::new(),
|
|
483
|
-
}
|
|
484
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
use std::collections::{HashSet, VecDeque};
|
|
2
|
-
|
|
3
|
-
use crate::diagnostic::{DiagnosticKind, MustardError, MustardResult};
|
|
4
|
-
|
|
5
|
-
use super::*;
|
|
6
|
-
|
|
7
|
-
mod bytecode;
|
|
8
|
-
mod policy;
|
|
9
|
-
mod snapshot;
|
|
10
|
-
mod walk;
|
|
11
|
-
|
|
12
|
-
pub(super) use bytecode::validate_bytecode_program;
|
|
13
|
-
pub(super) use policy::validate_snapshot_policy;
|
|
14
|
-
pub(super) use snapshot::validate_snapshot;
|