/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2013 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/cpu/function.h" #include "xenia/base/logging.h" #include "xenia/cpu/symbol.h" #include "xenia/cpu/thread_state.h" namespace xe { namespace cpu { using xe::debug::Breakpoint; Function::Function(Module* module, uint32_t address) : Symbol(Symbol::Type::kFunction, module, address) {} Function::~Function() = default; BuiltinFunction::BuiltinFunction(Module* module, uint32_t address) : Function(module, address) { behavior_ = Behavior::kBuiltin; } BuiltinFunction::~BuiltinFunction() = default; void BuiltinFunction::SetupBuiltin(Handler handler, void* arg0, void* arg1) { behavior_ = Behavior::kBuiltin; handler_ = handler; arg0_ = arg0; arg1_ = arg1; } bool BuiltinFunction::Call(ThreadState* thread_state, uint32_t return_address) { // SCOPE_profile_cpu_f("cpu"); ThreadState* original_thread_state = ThreadState::Get(); if (original_thread_state != thread_state) { ThreadState::Bind(thread_state); } assert_not_null(handler_); handler_(thread_state->context(), arg0_, arg1_); if (original_thread_state != thread_state) { ThreadState::Bind(original_thread_state); } return true; } GuestFunction::GuestFunction(Module* module, uint32_t address) : Function(module, address) { behavior_ = Behavior::kDefault; } GuestFunction::~GuestFunction() = default; void GuestFunction::SetupExtern(ExternHandler handler) { behavior_ = Behavior::kExtern; extern_handler_ = handler; } const SourceMapEntry* GuestFunction::LookupSourceOffset(uint32_t offset) const { // TODO(benvanik): binary search? We know the list is sorted by code order. for (size_t i = 0; i < source_map_.size(); ++i) { const auto& entry = source_map_[i]; if (entry.source_offset == offset) { return &entry; } } return nullptr; } const SourceMapEntry* GuestFunction::LookupHIROffset(uint32_t offset) const { // TODO(benvanik): binary search? We know the list is sorted by code order. for (size_t i = 0; i < source_map_.size(); ++i) { const auto& entry = source_map_[i]; if (entry.hir_offset >= offset) { return &entry; } } return nullptr; } const SourceMapEntry* GuestFunction::LookupCodeOffset(uint32_t offset) const { // TODO(benvanik): binary search? We know the list is sorted by code order. for (int64_t i = source_map_.size() - 1; i >= 0; --i) { const auto& entry = source_map_[i]; if (entry.code_offset <= offset) { return &entry; } } return source_map_.empty() ? nullptr : &source_map_[0]; } bool GuestFunction::Call(ThreadState* thread_state, uint32_t return_address) { // SCOPE_profile_cpu_f("cpu"); ThreadState* original_thread_state = ThreadState::Get(); if (original_thread_state != thread_state) { ThreadState::Bind(thread_state); } bool result = false; if (behavior_ == Behavior::kExtern) { // Special handling for extern functions to speed things up (we don't // trampoline into guest code only to trampoline back out). if (extern_handler_) { extern_handler_(thread_state->context(), thread_state->context()->kernel_state); } else { XELOGW("undefined extern call to %.8X %s", address(), name().c_str()); result = false; } } else { result = CallImpl(thread_state, return_address); } if (original_thread_state != thread_state) { ThreadState::Bind(original_thread_state); } return result; } } // namespace cpu } // namespace xe