From 544c8dbc13b0196442c4bb8199bd7f950323cc12 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 3 Jul 2025 00:46:42 +0300 Subject: [PATCH] Kernel: Optimize AML interpreter stack usage There is a very hacky no-inline hack that I am not proud of but it drops the stack usage of few functions A LOT. Previously Virtual Box could not boot with our 8 page stack, but these changes allow it to boot on 5! --- kernel/kernel/ACPI/AML/Node.cpp | 292 ++++++++++++++++---------------- 1 file changed, 145 insertions(+), 147 deletions(-) diff --git a/kernel/kernel/ACPI/AML/Node.cpp b/kernel/kernel/ACPI/AML/Node.cpp index 29b878be..cfdfc155 100644 --- a/kernel/kernel/ACPI/AML/Node.cpp +++ b/kernel/kernel/ACPI/AML/Node.cpp @@ -1,3 +1,10 @@ +// FIXME: Rewrite aml interpreter to not be recursive. +// Not inlining TRYs drops our stack usage a ton... +#pragma GCC push_options +#pragma GCC optimize "no-inline" +#include +#pragma GCC pop_options + #include #include @@ -382,9 +389,6 @@ namespace Kernel::ACPI::AML return result; } -// FIXME: WHY TF IS THIS USING OVER 1 KiB of stack -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" static BAN::ErrorOr parse_logical_op(ParseContext& context) { dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_logical_op"); @@ -475,7 +479,6 @@ namespace Kernel::ACPI::AML return result; } -#pragma GCC diagnostic pop static BAN::ErrorOr parse_index_op(ParseContext& context); @@ -751,8 +754,6 @@ namespace Kernel::ACPI::AML return {}; } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" static BAN::ErrorOr perform_store(const Node& source, Reference* target, TargetType target_type) { dprintln_if(AML_DUMP_FUNCTION_CALLS, "perform_store"); @@ -833,7 +834,6 @@ namespace Kernel::ACPI::AML return {}; } -#pragma GCC diagnostic pop static BAN::ErrorOr store_into_target(ParseContext& context, const Node& node) { @@ -1240,7 +1240,7 @@ namespace Kernel::ACPI::AML } ASSERT(object); - return TRY(sizeof_impl(object->node)); + return sizeof_impl(object->node); } static BAN::ErrorOr derefof_impl(const Node& source) @@ -1248,7 +1248,7 @@ namespace Kernel::ACPI::AML switch (source.type) { case Node::Type::Reference: - return TRY(source.as.reference->node.copy()); + return source.as.reference->node.copy(); case Node::Type::Index: { switch (source.as.index.type) @@ -1267,7 +1267,7 @@ namespace Kernel::ACPI::AML { ASSERT(source.as.index.index < source.as.index.as.package->num_elements); TRY(resolve_package_element(source.as.index.as.package->elements[source.as.index.index], true)); - return TRY(source.as.index.as.package->elements[source.as.index.index].value.node->copy()); + return source.as.index.as.package->elements[source.as.index.index].value.node->copy(); } default: ASSERT_NOT_REACHED(); } @@ -1549,9 +1549,6 @@ namespace Kernel::ACPI::AML return result; } -// FIXME: WHY TF IS THIS USING OVER 1 KiB of stack -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" static BAN::ErrorOr parse_explicit_conversion(ParseContext& context) { dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_explicit_conversion"); @@ -1704,7 +1701,6 @@ namespace Kernel::ACPI::AML return result; } -#pragma GCC diagnostic pop static BAN::ErrorOr parse_to_string_op(ParseContext& context) { @@ -2006,7 +2002,6 @@ namespace Kernel::ACPI::AML return {}; } - static BAN::ErrorOr parse_wait_op(ParseContext& context) { dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_wait_op"); @@ -2622,7 +2617,7 @@ namespace Kernel::ACPI::AML case Node::Type::Buffer: case Node::Type::Index: case Node::Type::Reference: - return TRY(node.copy()); + return node.copy(); case Node::Type::BufferField: dwarnln("TODO: evaluate BufferField"); return BAN::Error::from_errno(ENOTSUP); @@ -2631,7 +2626,7 @@ namespace Kernel::ACPI::AML case Node::Type::Method: if (node.as.method.arg_count != 0) return BAN::Error::from_errno(EFAULT); - return TRY(method_call(node_path, node, BAN::Array{})); + return method_call(node_path, node, BAN::Array{}); } dwarnln("evaluate {}", node); @@ -2766,9 +2761,6 @@ namespace Kernel::ACPI::AML return method_call(scope, method, BAN::move(args)); } -// FIXME: WHY TF IS THIS USING OVER 2 KiB of stack -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" BAN::ErrorOr parse_node(ParseContext& context, bool return_ref) { if (context.aml_data.empty()) @@ -2783,15 +2775,15 @@ namespace Kernel::ACPI::AML switch (static_cast(opcode)) { case AML::ExtOp::CondRefOfOp: - return TRY(parse_condrefof_op(context)); + return parse_condrefof_op(context); case AML::ExtOp::AcquireOp: - return TRY(parse_acquire_op(context)); + return parse_acquire_op(context); case AML::ExtOp::LoadOp: - return TRY(parse_load_op(context)); + return parse_load_op(context); case AML::ExtOp::TimerOp: - return TRY(parse_timer_op(context)); + return parse_timer_op(context); case AML::ExtOp::WaitOp: - return TRY(parse_wait_op(context)); + return parse_wait_op(context); case AML::ExtOp::DebugOp: { context.aml_data = context.aml_data.slice(2); @@ -2817,46 +2809,46 @@ namespace Kernel::ACPI::AML case AML::Byte::WordPrefix: case AML::Byte::DWordPrefix: case AML::Byte::QWordPrefix: - return TRY(parse_integer(context.aml_data)); + return parse_integer(context.aml_data); case AML::Byte::StringPrefix: - return TRY(parse_string(context.aml_data)); + return parse_string(context.aml_data); case AML::Byte::BufferOp: - return TRY(parse_buffer_op(context)); + return parse_buffer_op(context); case AML::Byte::PackageOp: case AML::Byte::VarPackageOp: - return TRY(parse_package_op(context)); + return parse_package_op(context); case AML::Byte::SizeOfOp: - return TRY(parse_sizeof_op(context)); + return parse_sizeof_op(context); case AML::Byte::RefOfOp: - return TRY(parse_refof_op(context)); + return parse_refof_op(context); case AML::Byte::DerefOfOp: - return TRY(parse_derefof_op(context)); + return parse_derefof_op(context); case AML::Byte::StoreOp: - return TRY(parse_store_op(context)); + return parse_store_op(context); case AML::Byte::CopyObjectOp: - return TRY(parse_copy_object_op(context)); + return parse_copy_object_op(context); case AML::Byte::ConcatOp: - return TRY(parse_concat_op(context)); + return parse_concat_op(context); case AML::Byte::MidOp: - return TRY(parse_mid_op(context)); + return parse_mid_op(context); case AML::Byte::IndexOp: - return TRY(parse_index_op(context)); + return parse_index_op(context); case AML::Byte::ObjectTypeOp: - return TRY(parse_object_type_op(context)); + return parse_object_type_op(context); case AML::Byte::MatchOp: - return TRY(parse_match_op(context)); + return parse_match_op(context); case AML::Byte::ToBufferOp: case AML::Byte::ToDecimalStringOp: case AML::Byte::ToHexStringOp: case AML::Byte::ToIntegerOp: - return TRY(parse_explicit_conversion(context)); + return parse_explicit_conversion(context); case AML::Byte::ToStringOp: - return TRY(parse_to_string_op(context)); + return parse_to_string_op(context); case AML::Byte::IncrementOp: case AML::Byte::DecrementOp: - return TRY(parse_inc_dec_op(context)); + return parse_inc_dec_op(context); case AML::Byte::NotOp: - return TRY(parse_unary_integer_op(context)); + return parse_unary_integer_op(context); case AML::Byte::AddOp: case AML::Byte::SubtractOp: case AML::Byte::MultiplyOp: @@ -2869,17 +2861,17 @@ namespace Kernel::ACPI::AML case AML::Byte::NorOp: case AML::Byte::XorOp: case AML::Byte::ModOp: - return TRY(parse_binary_integer_op(context)); + return parse_binary_integer_op(context); case AML::Byte::LAndOp: case AML::Byte::LEqualOp: case AML::Byte::LGreaterOp: case AML::Byte::LLessOp: case AML::Byte::LNotOp: case AML::Byte::LOrOp: - return TRY(parse_logical_op(context)); + return parse_logical_op(context); case AML::Byte::FindSetLeftBitOp: case AML::Byte::FindSetRightBitOp: - return TRY(parse_find_set_bit_op(context)); + return parse_find_set_bit_op(context); case AML::Byte::Local0: case AML::Byte::Local1: case AML::Byte::Local2: @@ -2897,7 +2889,7 @@ namespace Kernel::ACPI::AML return BAN::Error::from_errno(EINVAL); } if (!return_ref) - return TRY(context.locals[local_index]->node.copy()); + return context.locals[local_index]->node.copy(); Node reference; reference.type = Node::Type::Reference; reference.as.reference = context.locals[local_index]; @@ -2920,7 +2912,7 @@ namespace Kernel::ACPI::AML return BAN::Error::from_errno(EINVAL); } if (!return_ref) - return TRY(context.args[arg_index]->node.copy()); + return context.args[arg_index]->node.copy(); Node reference; reference.type = Node::Type::Reference; reference.as.reference = context.args[arg_index]; @@ -2967,11 +2959,11 @@ namespace Kernel::ACPI::AML } } - return TRY(method_call(BAN::move(object_scope), named_object->node, BAN::move(args), context.call_depth)); + return method_call(BAN::move(object_scope), named_object->node, BAN::move(args), context.call_depth); } if (!return_ref) - return TRY(named_object->node.copy()); + return named_object->node.copy(); Node reference; reference.type = Node::Type::Reference; @@ -2979,20 +2971,13 @@ namespace Kernel::ACPI::AML reference.as.reference->ref_count++; return reference; } -#pragma GCC diagnostic pop -// FIXME: WHY TF IS THIS USING ALMOST 2 KiB of stack -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" BAN::ErrorOr parse_node_or_execution_flow(ParseContext& context) { if (context.aml_data.empty()) return BAN::Error::from_errno(ENODATA); - auto dummy_return = ExecutionFlowResult { - .elem1 = ExecutionFlow::Normal, - .elem2 = BAN::Optional(), - }; + BAN::ErrorOr (*function)(ParseContext&) = nullptr; if (context.aml_data[0] == static_cast(AML::Byte::ExtOpPrefix)) { @@ -3001,116 +2986,130 @@ namespace Kernel::ACPI::AML switch (static_cast(context.aml_data[1])) { case AML::ExtOp::MutexOp: - TRY(parse_mutex_op(context)); - return dummy_return; + function = parse_mutex_op; + break; case AML::ExtOp::FatalOp: - TRY(parse_fatal_op(context)); - return dummy_return; + function = parse_fatal_op; + break; case AML::ExtOp::EventOp: - TRY(parse_event_op(context)); - return dummy_return; + function = parse_event_op; + break; case AML::ExtOp::ResetOp: case AML::ExtOp::SignalOp: - TRY(parse_reset_signal_op(context)); - return dummy_return; + function = parse_reset_signal_op; + break; case AML::ExtOp::CreateFieldOp: - TRY(parse_createfield_op(context)); - return dummy_return; + function = parse_createfield_op; + break; case AML::ExtOp::SleepOp: - TRY(parse_sleep_op(context)); - return dummy_return; + function = parse_sleep_op; + break; case AML::ExtOp::StallOp: - TRY(parse_stall_op(context)); - return dummy_return; + function = parse_stall_op; + break; case AML::ExtOp::ReleaseOp: - TRY(parse_release_op(context)); - return dummy_return; + function = parse_release_op; + break; case AML::ExtOp::OpRegionOp: - TRY(parse_opregion_op(context)); - return dummy_return; + function = parse_opregion_op; + break; case AML::ExtOp::FieldOp: - TRY(parse_field_op(context)); - return dummy_return; + function = parse_field_op; + break; case AML::ExtOp::IndexFieldOp: - TRY(parse_index_field_op(context)); - return dummy_return; + function = parse_index_field_op; + break; case AML::ExtOp::BankFieldOp: - TRY(parse_bank_field_op(context)); - return dummy_return; + function = parse_bank_field_op; + break; case AML::ExtOp::DeviceOp: - TRY(parse_device_op(context)); - return dummy_return; + function = parse_device_op; + break; case AML::ExtOp::ProcessorOp: - TRY(parse_processor_op(context)); - return dummy_return; + function = parse_processor_op; + break; case AML::ExtOp::PowerResOp: - TRY(parse_power_resource_op(context)); - return dummy_return; + function = parse_power_resource_op; + break; case AML::ExtOp::ThermalZoneOp: - TRY(parse_thermal_zone_op(context)); - return dummy_return; + function = parse_thermal_zone_op; + break; + default: + break; + } + } + else + { + switch (static_cast(context.aml_data[0])) + { + case AML::Byte::AliasOp: + function = parse_alias_op; + break; + case AML::Byte::NameOp: + function = parse_name_op; + break; + case AML::Byte::MethodOp: + function = parse_method_op; + break; + case AML::Byte::ScopeOp: + function = parse_scope_op; + break; + case AML::Byte::NotifyOp: + function = parse_notify_op; + break; + case AML::Byte::CreateBitFieldOp: + case AML::Byte::CreateByteFieldOp: + case AML::Byte::CreateWordFieldOp: + case AML::Byte::CreateDWordFieldOp: + case AML::Byte::CreateQWordFieldOp: + function = parse_createfield_op; + break; + case AML::Byte::IfOp: + return parse_if_op(context); + case AML::Byte::WhileOp: + return parse_while_op(context); + case AML::Byte::NoopOp: + case AML::Byte::BreakPointOp: + context.aml_data = context.aml_data.slice(1); + return ExecutionFlowResult { + .elem1 = ExecutionFlow::Normal, + .elem2 = BAN::Optional(), + };; + case AML::Byte::BreakOp: + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_break_op"); + context.aml_data = context.aml_data.slice(1); + return ExecutionFlowResult { + .elem1 = ExecutionFlow::Break, + .elem2 = BAN::Optional(), + }; + case AML::Byte::ContinueOp: + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_continue_op"); + context.aml_data = context.aml_data.slice(1); + return ExecutionFlowResult { + .elem1 = ExecutionFlow::Continue, + .elem2 = BAN::Optional(), + }; + case AML::Byte::ReturnOp: + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_return_op"); + context.aml_data = context.aml_data.slice(1); + return ExecutionFlowResult { + .elem1 = ExecutionFlow::Return, + .elem2 = TRY(parse_node(context)), + }; + } default: break; } } - switch (static_cast(context.aml_data[0])) + if (function) { - case AML::Byte::AliasOp: - TRY(parse_alias_op(context)); - return dummy_return; - case AML::Byte::NameOp: - TRY(parse_name_op(context)); - return dummy_return; - case AML::Byte::MethodOp: - TRY(parse_method_op(context)); - return dummy_return; - case AML::Byte::NoopOp: - case AML::Byte::BreakPointOp: - context.aml_data = context.aml_data.slice(1); - return dummy_return; - case AML::Byte::ScopeOp: - TRY(parse_scope_op(context)); - return dummy_return; - case AML::Byte::NotifyOp: - TRY(parse_notify_op(context)); - return dummy_return; - case AML::Byte::CreateBitFieldOp: - case AML::Byte::CreateByteFieldOp: - case AML::Byte::CreateWordFieldOp: - case AML::Byte::CreateDWordFieldOp: - case AML::Byte::CreateQWordFieldOp: - TRY(parse_createfield_op(context)); - return dummy_return; - case AML::Byte::IfOp: - return parse_if_op(context); - case AML::Byte::WhileOp: - return parse_while_op(context); - case AML::Byte::BreakOp: - dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_break_op"); - context.aml_data = context.aml_data.slice(1); - return ExecutionFlowResult { - .elem1 = ExecutionFlow::Break, - .elem2 = BAN::Optional(), - }; - case AML::Byte::ContinueOp: - dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_continue_op"); - context.aml_data = context.aml_data.slice(1); - return ExecutionFlowResult { - .elem1 = ExecutionFlow::Continue, - .elem2 = BAN::Optional(), - }; - case AML::Byte::ReturnOp: - { - dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_return_op"); - context.aml_data = context.aml_data.slice(1); - return ExecutionFlowResult { - .elem1 = ExecutionFlow::Return, - .elem2 = TRY(parse_node(context)), - }; - } - default: - break; + TRY(function(context)); + return ExecutionFlowResult { + .elem1 = ExecutionFlow::Normal, + .elem2 = BAN::Optional(), + };; } auto node = TRY(parse_node(context)); @@ -3119,7 +3118,6 @@ namespace Kernel::ACPI::AML .elem2 = BAN::move(node) }; } -#pragma GCC diagnostic pop BAN::ErrorOr NameString::from_string(BAN::StringView name) {