class IntrinsicVisitor : public ValueObject { public: virtual ~IntrinsicVisitor() {}
// Dispatch logic.
void Dispatch(HInvoke* invoke) { switch (invoke->GetIntrinsic()) { case Intrinsics::kNone: return;
#define OPTIMIZING_INTRINSICS_WITH_SPECIALIZED_HIR(Name, ...) \ case Intrinsics::k ## Name:
ART_INTRINSICS_WITH_SPECIALIZED_HIR_LIST(OPTIMIZING_INTRINSICS_WITH_SPECIALIZED_HIR) #undef OPTIMIZING_INTRINSICS_WITH_SPECIALIZED_HIR // Note: clang++ can optimize this `switch` to a range check and a virtual dispatch // with indexed load from the vtable using an adjusted `invoke->GetIntrinsic()` // as the index. However, a non-empty `case` causes clang++ to produce much worse // code, so we want to limit this check to debug builds only.
DCHECK(false) << "Unexpected intrinsic with HIR: " << invoke->GetIntrinsic(); return;
// We're moving potentially two or more locations to locations that could overlap, so we need // a parallel move resolver.
HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
HInstruction* input = invoke->InputAt(i);
Location cc_loc = calling_convention_visitor->GetNextLocation(input->GetType());
Location actual_loc = locations->InAt(i);
// Temporary data structure for holding BoxedType.valueOf data for generating code. struct ValueOfInfo { static constexpr uint32_t kInvalidReference = static_cast<uint32_t>(-1);
ValueOfInfo();
// Offset of the value field of the boxed object for initializing a newly allocated instance.
uint32_t value_offset; // The low value in the cache.
int32_t low; // The length of the cache array.
uint32_t length;
// This union contains references to the boot image. For app AOT or JIT compilation, // these are the boot image offsets of the target. For boot image compilation, the // location shall be known only at link time, so we encode a symbolic reference using // IntrinsicObjects::EncodePatch(). union { // The target value for a constant input in the cache range. If the constant input // is out of range (use `low` and `length` to check), this value is bogus (set to // kInvalidReference) and the code must allocate a new Integer.
uint32_t value_boot_image_reference;
// The cache array data used for a non-constant input in the cache range. // If the input is out of range, the code must allocate a new Integer.
uint32_t array_data_boot_image_reference;
};
};
staticinlinebool IsValidIntrinsicAfterBuilder(Intrinsics intrinsic) { return !IsIntrinsicWithSpecializedHir(intrinsic) || // FIXME: The inliner can currently create graphs with any of the intrinsics with HIR. // However, we are able to compensate for `StringCharAt` and `StringLength` in the // `HInstructionSimplifier`, so we're allowing these two intrinsics for now, preserving // the old behavior. Besides fixing the bug, we should also clean up the simplifier // and remove `SimplifyStringCharAt` and `SimplifyStringLength`. Bug: 319045458
intrinsic == Intrinsics::kStringCharAt ||
intrinsic == Intrinsics::kStringLength;
}
class VarHandleOptimizations : public IntrinsicOptimizations { public: explicit VarHandleOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
INTRINSIC_OPTIMIZATION(DoNotIntrinsify, 0); // One of the checks is statically known to fail.
INTRINSIC_OPTIMIZATION(SkipObjectNullCheck, 1); // Not applicable for static fields.
// Use known `VarHandle` from the boot/app image. To apply this optimization, the following // `VarHandle` checks must pass based on static analysis: // - `VarHandle` type check (must match the coordinate count), // - access mode check, // - var type check (including assignability for reference types), // - object type check (except for static field VarHandles that do not take an object). // Note that the object null check is controlled by the above flag `SkipObjectNullCheck` // and arrays and byte array views (which always need a range check and sometimes also // array type check) are currently unsupported.
INTRINSIC_OPTIMIZATION(UseKnownImageVarHandle, 2);
};
#undef INTRISIC_OPTIMIZATION
// // Macros for use in the intrinsics code generators. //
// Defines an unimplemented intrinsic: that is, a method call that is recognized as an // intrinsic to exploit e.g. no side-effects or exceptions, but otherwise not handled // by this architecture-specific intrinsics code generator. Eventually it is implemented // as a true method call. #define UNIMPLEMENTED_INTRINSIC(Arch, Name) \ void IntrinsicLocationsBuilder##Arch::Visit##Name([[maybe_unused]] HInvoke* invoke) {} \ void IntrinsicCodeGenerator##Arch::Visit##Name([[maybe_unused]] HInvoke* invoke) {}
// Defines a list of unreached intrinsics: that is, method calls that are recognized as // an intrinsic, and then always converted into HIR instructions before they reach any // architecture-specific intrinsics code generator. This only applies to non-baseline // compilation. #define UNREACHABLE_INTRINSIC(Arch, Name) \ void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke) { \ if (Runtime::Current()->IsAotCompiler() && \
!codegen_->GetCompilerOptions().IsBaseline()) { \
LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic() \
<< " should have been converted to HIR"; \
} \
} \ void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke) { \
LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic() \
<< " should have been converted to HIR"; \
} #define UNREACHABLE_INTRINSICS(Arch) \
UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits) \
UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits)
template <typename IntrinsicLocationsBuilder, typename Codegenerator> bool IsIntrinsicCallFree(HInvoke* invoke, Codegenerator* codegen) {
DCHECK(invoke->IsIntrinsic()); // This invoke may have intrinsic code generation defined. However, we must // now also determine if this code generation is truly there and call-free // (not unimplemented, no bail on instruction features, or call on slow path). // This is done by actually calling the locations builder on the instruction // and clearing out the locations once result is known. We assume this // call only has creating locations as side effects! // TODO: Avoid wasting Arena memory.
IntrinsicLocationsBuilder builder(codegen); bool success = builder.TryDispatch(invoke) && !invoke->GetLocations()->CanCall();
invoke->SetLocations(nullptr); return success;
}
// Insert a `Float.floatToRawIntBits()` or `Double.doubleToRawLongBits()` intrinsic for a // given input. These fake calls are needed on arm and riscv64 to satisfy type consistency // checks while passing certain FP args in core registers for direct @CriticalNative calls. void InsertFpToIntegralIntrinsic(HInvokeStaticOrDirect* invoke, size_t input_index);
} // namespace art
#endif// ART_COMPILER_OPTIMIZING_INTRINSICS_H_
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.