mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 13:36:13 +03:00
LibWasm: Refactor validator to use one stack for frame information
Previously, the validator had a lot of extraneous information related to frames. Now, there's just one stack with all the necessary information derived from it.
This commit is contained in:
parent
991759f453
commit
8217a77728
Notes:
sideshowbarker
2024-07-17 01:10:58 +09:00
Author: https://github.com/dzfrias Commit: https://github.com/LadybirdBrowser/ladybird/commit/8217a77728 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/147 Reviewed-by: https://github.com/alimpfard ✅
@ -289,8 +289,7 @@ ErrorOr<void, ValidationError> Validator::validate(CodeSection const& section)
|
||||
function_validator.m_context.locals.append(local.type());
|
||||
}
|
||||
|
||||
function_validator.m_context.labels = { ResultType { function_type.results() } };
|
||||
function_validator.m_context.return_ = ResultType { function_type.results() };
|
||||
function_validator.m_frames.empend(function_type, FrameKind::Function, (size_t)0);
|
||||
|
||||
TRY(function_validator.validate(function.body(), function_type.results()));
|
||||
}
|
||||
@ -1991,24 +1990,12 @@ VALIDATE_INSTRUCTION(unreachable)
|
||||
// Note: This is responsible for _all_ structured instructions, and is *not* from the spec.
|
||||
VALIDATE_INSTRUCTION(structured_end)
|
||||
{
|
||||
if (m_entered_scopes.is_empty())
|
||||
if (m_frames.is_empty())
|
||||
return Errors::invalid("usage of structured end"sv);
|
||||
|
||||
auto last_scope = m_entered_scopes.take_last();
|
||||
m_context = m_parent_contexts.take_last();
|
||||
auto last_block_type = m_entered_blocks.take_last();
|
||||
auto last_frame = m_frames.take_last();
|
||||
|
||||
switch (last_scope) {
|
||||
case ChildScopeKind::Block:
|
||||
case ChildScopeKind::IfWithoutElse:
|
||||
case ChildScopeKind::Else:
|
||||
m_block_details.take_last();
|
||||
break;
|
||||
case ChildScopeKind::IfWithElse:
|
||||
return Errors::invalid("usage of if without an else clause that appears to have one anyway"sv);
|
||||
}
|
||||
|
||||
auto& results = last_block_type.results();
|
||||
auto& results = last_frame.type.results();
|
||||
for (size_t i = 1; i <= results.size(); ++i)
|
||||
TRY(stack.take(results[results.size() - i]));
|
||||
|
||||
@ -2021,21 +2008,23 @@ VALIDATE_INSTRUCTION(structured_end)
|
||||
// Note: This is *not* from the spec.
|
||||
VALIDATE_INSTRUCTION(structured_else)
|
||||
{
|
||||
if (m_entered_scopes.is_empty())
|
||||
if (m_frames.is_empty())
|
||||
return Errors::invalid("usage of structured else"sv);
|
||||
|
||||
if (m_entered_scopes.last() != ChildScopeKind::IfWithElse)
|
||||
if (m_frames.last().kind != FrameKind::If)
|
||||
return Errors::invalid("usage of structured else"sv);
|
||||
|
||||
auto& block_type = m_entered_blocks.last();
|
||||
auto frame = m_frames.take_last();
|
||||
auto& block_type = frame.type;
|
||||
auto& results = block_type.results();
|
||||
|
||||
for (size_t i = 1; i <= results.size(); ++i)
|
||||
TRY(stack.take(results[results.size() - i]));
|
||||
|
||||
auto& details = m_block_details.last().details.get<BlockDetails::IfDetails>();
|
||||
m_entered_scopes.last() = ChildScopeKind::Else;
|
||||
stack = move(details.initial_stack);
|
||||
m_frames.empend(block_type, FrameKind::Else, stack.actual_size());
|
||||
for (auto& parameter : block_type.parameters())
|
||||
stack.append(parameter);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -2048,14 +2037,10 @@ VALIDATE_INSTRUCTION(block)
|
||||
for (size_t i = 1; i <= parameters.size(); ++i)
|
||||
TRY(stack.take(parameters[parameters.size() - i]));
|
||||
|
||||
m_frames.empend(block_type, FrameKind::Block, stack.actual_size());
|
||||
for (auto& parameter : parameters)
|
||||
stack.append(parameter);
|
||||
|
||||
m_entered_scopes.append(ChildScopeKind::Block);
|
||||
m_block_details.empend(stack.actual_size(), Empty {});
|
||||
m_parent_contexts.append(m_context);
|
||||
m_entered_blocks.append(block_type);
|
||||
m_context.labels.prepend(ResultType { block_type.results() });
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -2068,14 +2053,10 @@ VALIDATE_INSTRUCTION(loop)
|
||||
for (size_t i = 1; i <= parameters.size(); ++i)
|
||||
TRY(stack.take(parameters[parameters.size() - i]));
|
||||
|
||||
m_frames.empend(block_type, FrameKind::Loop, stack.actual_size());
|
||||
for (auto& parameter : parameters)
|
||||
stack.append(parameter);
|
||||
|
||||
m_entered_scopes.append(ChildScopeKind::Block);
|
||||
m_block_details.empend(stack.actual_size(), Empty {});
|
||||
m_parent_contexts.append(m_context);
|
||||
m_entered_blocks.append(block_type);
|
||||
m_context.labels.prepend(ResultType { block_type.parameters() });
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -2092,14 +2073,10 @@ VALIDATE_INSTRUCTION(if_)
|
||||
for (size_t i = 1; i <= parameters.size(); ++i)
|
||||
TRY(stack.take(parameters[parameters.size() - i]));
|
||||
|
||||
m_frames.empend(block_type, FrameKind::If, stack.actual_size());
|
||||
for (auto& parameter : parameters)
|
||||
stack.append(parameter);
|
||||
|
||||
m_entered_scopes.append(args.else_ip.has_value() ? ChildScopeKind::IfWithElse : ChildScopeKind::IfWithoutElse);
|
||||
m_block_details.empend(stack.actual_size(), BlockDetails::IfDetails { move(stack_snapshot) });
|
||||
m_parent_contexts.append(m_context);
|
||||
m_entered_blocks.append(block_type);
|
||||
m_context.labels.prepend(ResultType { block_type.results() });
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -2108,9 +2085,9 @@ VALIDATE_INSTRUCTION(br)
|
||||
auto label = instruction.arguments().get<LabelIndex>();
|
||||
TRY(validate(label));
|
||||
|
||||
auto& type = m_context.labels[label.value()];
|
||||
for (size_t i = 1; i <= type.types().size(); ++i)
|
||||
TRY(stack.take(type.types()[type.types().size() - i]));
|
||||
auto& type = m_frames[(m_frames.size() - 1) - label.value()].labels();
|
||||
for (size_t i = 1; i <= type.size(); ++i)
|
||||
TRY(stack.take(type[type.size() - i]));
|
||||
|
||||
stack.append(StackEntry());
|
||||
return {};
|
||||
@ -2123,13 +2100,13 @@ VALIDATE_INSTRUCTION(br_if)
|
||||
|
||||
TRY(stack.take<ValueType::I32>());
|
||||
|
||||
auto& type = m_context.labels[label.value()];
|
||||
auto& type = m_frames[(m_frames.size() - 1) - label.value()].labels();
|
||||
|
||||
Vector<StackEntry> entries;
|
||||
entries.ensure_capacity(type.types().size());
|
||||
entries.ensure_capacity(type.size());
|
||||
|
||||
for (size_t i = 0; i < type.types().size(); ++i) {
|
||||
auto& entry = type.types()[type.types().size() - i - 1];
|
||||
for (size_t i = 0; i < type.size(); ++i) {
|
||||
auto& entry = type[type.size() - i - 1];
|
||||
TRY(stack.take(entry));
|
||||
entries.append(entry);
|
||||
}
|
||||
@ -2150,13 +2127,13 @@ VALIDATE_INSTRUCTION(br_table)
|
||||
|
||||
TRY(stack.take<ValueType::I32>());
|
||||
|
||||
auto& default_types = m_context.labels[args.default_.value()].types();
|
||||
auto& default_types = m_frames[(m_frames.size() - 1) - args.default_.value()].labels();
|
||||
auto arity = default_types.size();
|
||||
|
||||
auto stack_snapshot = stack;
|
||||
auto stack_to_check = stack_snapshot;
|
||||
for (auto& label : args.labels) {
|
||||
auto& label_types = m_context.labels[label.value()].types();
|
||||
auto& label_types = m_frames[(m_frames.size() - 1) - label.value()].labels();
|
||||
if (label_types.size() != arity)
|
||||
return Errors::invalid("br_table label arity mismatch"sv);
|
||||
for (size_t i = 0; i < arity; ++i)
|
||||
@ -2176,10 +2153,7 @@ VALIDATE_INSTRUCTION(br_table)
|
||||
|
||||
VALIDATE_INSTRUCTION(return_)
|
||||
{
|
||||
if (!m_context.return_.has_value())
|
||||
return Errors::invalid("use of return outside function"sv);
|
||||
|
||||
auto& return_types = m_context.return_->types();
|
||||
auto& return_types = m_frames.first().type.results();
|
||||
for (size_t i = 0; i < return_types.size(); ++i)
|
||||
TRY((stack.take(return_types[return_types.size() - i - 1])));
|
||||
|
||||
|
@ -26,9 +26,7 @@ struct Context {
|
||||
COWVector<ValueType> elements;
|
||||
COWVector<bool> datas;
|
||||
COWVector<ValueType> locals;
|
||||
COWVector<ResultType> labels;
|
||||
Optional<u32> data_count;
|
||||
Optional<ResultType> return_;
|
||||
AK::HashTable<FunctionIndex> references;
|
||||
size_t imported_function_count { 0 };
|
||||
};
|
||||
@ -115,7 +113,7 @@ public:
|
||||
|
||||
ErrorOr<void, ValidationError> validate(LabelIndex index) const
|
||||
{
|
||||
if (index.value() < m_context.labels.size())
|
||||
if (index.value() < m_frames.size())
|
||||
return {};
|
||||
return Errors::invalid("LabelIndex"sv);
|
||||
}
|
||||
@ -328,13 +326,6 @@ private:
|
||||
static ByteString find_instruction_name(SourceLocation const&);
|
||||
};
|
||||
|
||||
enum class ChildScopeKind {
|
||||
Block,
|
||||
IfWithoutElse,
|
||||
IfWithElse,
|
||||
Else,
|
||||
};
|
||||
|
||||
struct BlockDetails {
|
||||
size_t initial_stack_size { 0 };
|
||||
struct IfDetails {
|
||||
@ -343,11 +334,28 @@ private:
|
||||
Variant<IfDetails, Empty> details;
|
||||
};
|
||||
|
||||
enum class FrameKind {
|
||||
Block,
|
||||
Loop,
|
||||
If,
|
||||
Else,
|
||||
Function,
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
FunctionType type;
|
||||
FrameKind kind;
|
||||
size_t init_size;
|
||||
bool unreachable { false };
|
||||
|
||||
Vector<ValueType> const& labels() const
|
||||
{
|
||||
return kind != FrameKind::Loop ? type.results() : type.parameters();
|
||||
}
|
||||
};
|
||||
|
||||
Context m_context;
|
||||
Vector<Context> m_parent_contexts;
|
||||
Vector<ChildScopeKind> m_entered_scopes;
|
||||
Vector<BlockDetails> m_block_details;
|
||||
Vector<FunctionType> m_entered_blocks;
|
||||
Vector<Frame> m_frames;
|
||||
COWVector<GlobalType> m_globals_without_internal_globals;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user