Files
sdk/runtime/vm/compiler/compiler_state.cc
Tess Strickland 7d8b5becb4 [vm,dyn_modules] Remove CompilerState use from CallMarshaller.
The CallMarshaller is used not only from the compiler, but also
from the FfiCall runtime entry used by the interpreter. Since it
only has one use of the thread's CompilerState, looking up the
TypedData class, move the storage of that class from the compiler
state to the object store and remove this dependency.

TEST=ffi/address_of_array_generated_test
     ffi/address_of_cast_test
     fii/address_of_struct_generated_test
     ffi/address_of_typeddata_generated_test

Fixes: https://github.com/dart-lang/sdk/issues/61913
Cq-Include-Trybots: luci.dart.try:vm-dyn-linux-debug-x64-try
Change-Id: Ia4fc5d9ecef370aa9476b998e37cc4ae94ee447f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/498563
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2026-06-09 07:54:09 -07:00

218 lines
8.9 KiB
C++

// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/compiler/compiler_state.h"
#include <functional>
#include "vm/compiler/aot/precompiler.h"
#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/compiler/backend/il_printer.h"
#include "vm/compiler/backend/slot.h"
#include "vm/growable_array.h"
#include "vm/object_store.h"
#include "vm/scopes.h"
namespace dart {
template <typename T>
T* PutIfAbsent(Thread* thread,
ZoneGrowableArray<T*>** array_slot,
intptr_t index,
std::function<T*()> create) {
auto array = *array_slot;
if (array == nullptr) {
Zone* const Z = thread->zone();
*array_slot = array = new (Z) ZoneGrowableArray<T*>(Z, index + 1);
}
while (array->length() <= index) {
array->Add(nullptr);
}
if (array->At(index) == nullptr) {
(*array)[index] = create();
}
return array->At(index);
}
CompilerTracing CompilerState::ShouldTrace(const Function& func) {
return FlowGraphPrinter::ShouldPrint(func) ? CompilerTracing::kOn
: CompilerTracing::kOff;
}
const Class& CompilerState::ComparableClass() {
if (comparable_class_ == nullptr) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
// When obfuscation is enabled we need to obfuscate the name of the
// class before looking it up.
String& name = String::Handle(zone, Symbols::New(thread, "Comparable"));
if (thread->isolate_group()->obfuscate()) {
Obfuscator obfuscator(thread, Object::null_string());
name = obfuscator.Rename(name);
}
const Library& lib = Library::Handle(zone, Library::CoreLibrary());
const Class& cls = Class::ZoneHandle(zone, lib.LookupClass(name));
ASSERT(!cls.IsNull());
comparable_class_ = &cls;
}
return *comparable_class_;
}
const Function& CompilerState::StringBaseInterpolateSingle() {
if (interpolate_single_ == nullptr) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Class& cls =
Class::Handle(Library::LookupCoreClass(Symbols::StringBase()));
ASSERT(!cls.IsNull());
interpolate_single_ = &Function::ZoneHandle(
zone, cls.LookupFunctionAllowPrivate(Symbols::InterpolateSingle()));
ASSERT(!interpolate_single_->IsNull());
}
return *interpolate_single_;
}
const Function& CompilerState::StringBaseInterpolate() {
if (interpolate_ == nullptr) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Class& cls =
Class::Handle(Library::LookupCoreClass(Symbols::StringBase()));
ASSERT(!cls.IsNull());
interpolate_ = &Function::ZoneHandle(
zone, cls.LookupFunctionAllowPrivate(Symbols::Interpolate()));
ASSERT(!interpolate_->IsNull());
}
return *interpolate_;
}
#define DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Upper, Lower) \
const Function& CompilerState::TypedListGet##Upper() { \
if (typed_list_get_##Lower##_ == nullptr) { \
Thread* thread = Thread::Current(); \
Zone* zone = thread->zone(); \
const auto& cls = CompilerState::TypedListClass(); \
typed_list_get_##Lower##_ = &Function::ZoneHandle( \
zone, cls.LookupFunctionAllowPrivate(Symbols::_nativeGet##Upper())); \
ASSERT(!typed_list_get_##Lower##_->IsNull()); \
} \
return *typed_list_get_##Lower##_; \
} \
const Function& CompilerState::TypedListSet##Upper() { \
if (typed_list_set_##Lower##_ == nullptr) { \
Thread* thread = Thread::Current(); \
Zone* zone = thread->zone(); \
const auto& cls = CompilerState::TypedListClass(); \
typed_list_set_##Lower##_ = &Function::ZoneHandle( \
zone, cls.LookupFunctionAllowPrivate(Symbols::_nativeSet##Upper())); \
ASSERT(!typed_list_set_##Lower##_->IsNull()); \
} \
return *typed_list_set_##Lower##_; \
}
DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Float32, float32)
DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Float64, float64)
DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Float32x4, float32x4)
DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Int32x4, int32x4)
DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Float64x2, float64x2)
#undef DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER
#define DEFINE_CLASS_GETTER(Lib, Upper, Lower, Symbol) \
const Class& CompilerState::Upper##Class() { \
if (Lower##_class_ == nullptr) { \
Thread* thread = Thread::Current(); \
Zone* zone = thread->zone(); \
const auto& lib = Library::Handle(zone, Library::Lib##Library()); \
const auto& cls = \
Class::Handle(zone, lib.LookupClassAllowPrivate(Symbols::Symbol())); \
ASSERT(!cls.IsNull()); \
const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread)); \
ASSERT(error.IsNull()); \
Lower##_class_ = &cls; \
} \
return *Lower##_class_; \
}
DEFINE_CLASS_GETTER(TypedData, TypedList, typed_list, _TypedList)
#undef DEFINE_CLASS_GETTER
const Field& CompilerState::ErrorStackTraceField() {
if (error_stack_trace_field_ == nullptr) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const auto& error_class = Class::Handle(
zone, thread->isolate_group()->object_store()->error_class());
const auto& field = Field::ZoneHandle(
zone,
error_class.LookupInstanceFieldAllowPrivate(Symbols::_stackTrace()));
ASSERT(!field.IsNull());
error_stack_trace_field_ = &field;
}
return *error_stack_trace_field_;
}
static bool IsMarkedWithNoBoundsChecks(const Function& function) {
Object& options = Object::Handle();
return Library::FindPragma(dart::Thread::Current(),
/*only_core=*/false, function,
Symbols::vm_unsafe_no_bounds_checks(),
/*multiple=*/false, &options);
}
FunctionPragmas::FunctionPragmas(const Function& function)
: function(function),
unsafe_no_bounds_checks(IsMarkedWithNoBoundsChecks(function)) {}
const FunctionPragmas& CompilerState::PragmasOf(const Function& function) {
if (cached_pragmas_ == nullptr) {
Zone* zone = thread()->zone();
cached_pragmas_ = new (zone) CachedPragmasMap(zone);
}
auto result = cached_pragmas_->LookupValue(&function);
if (result == nullptr) {
Zone* zone = thread()->zone();
result = new (zone) FunctionPragmas(Function::Handle(zone, function.ptr()));
cached_pragmas_->Insert(result);
}
return *result;
}
void CompilerState::ReportCrash() {
OS::PrintErr("=== Crash occurred when compiling %s in %s mode in %s pass\n",
function() != nullptr ? function()->ToFullyQualifiedCString()
: "unknown function",
is_aot() ? "AOT"
: is_optimizing() ? "optimizing JIT"
: "unoptimized JIT",
pass() != nullptr ? pass()->name() : "unknown");
if (pass_state() != nullptr && pass()->id() == CompilerPass::kGenerateCode) {
if (pass_state()->graph_compiler->current_block() != nullptr) {
OS::PrintErr("=== When compiling block %s\n",
pass_state()->graph_compiler->current_block()->ToCString());
}
if (pass_state()->graph_compiler->current_instruction() != nullptr) {
OS::PrintErr(
"=== When compiling instruction %s\n",
pass_state()->graph_compiler->current_instruction()->ToCString());
}
}
if (pass_state() != nullptr && pass_state()->flow_graph() != nullptr) {
pass_state()->flow_graph()->Print(pass()->name());
} else {
OS::PrintErr("=== Flow Graph not available\n");
}
}
} // namespace dart