summaryrefslogtreecommitdiff
path: root/compiler/optimizing/code_generator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/code_generator.cc')
-rw-r--r--compiler/optimizing/code_generator.cc119
1 files changed, 97 insertions, 22 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index cfd9ea6333..886cabbe0a 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -32,11 +32,13 @@
#include "code_generator_x86_64.h"
#endif
+#include "art_method-inl.h"
#include "base/bit_utils.h"
#include "base/bit_utils_iterator.h"
#include "base/casts.h"
#include "base/leb128.h"
#include "class_linker.h"
+#include "class_root-inl.h"
#include "compiled_method.h"
#include "dex/bytecode_utils.h"
#include "dex/code_item_accessors-inl.h"
@@ -433,7 +435,7 @@ void CodeGenerator::Compile(CodeAllocator* allocator) {
// Finalize instructions in assember;
Finalize(allocator);
- GetStackMapStream()->EndMethod();
+ GetStackMapStream()->EndMethod(GetAssembler()->CodeSize());
}
void CodeGenerator::Finalize(CodeAllocator* allocator) {
@@ -503,26 +505,77 @@ void CodeGenerator::CreateCommonInvokeLocationSummary(
if (invoke->IsInvokeStaticOrDirect()) {
HInvokeStaticOrDirect* call = invoke->AsInvokeStaticOrDirect();
- switch (call->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
- locations->SetInAt(call->GetSpecialInputIndex(), visitor->GetMethodLocation());
- break;
- case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall:
- locations->AddTemp(visitor->GetMethodLocation());
- locations->SetInAt(call->GetSpecialInputIndex(), Location::RequiresRegister());
- break;
- default:
- locations->AddTemp(visitor->GetMethodLocation());
- break;
+ MethodLoadKind method_load_kind = call->GetMethodLoadKind();
+ CodePtrLocation code_ptr_location = call->GetCodePtrLocation();
+ if (code_ptr_location == CodePtrLocation::kCallCriticalNative) {
+ locations->AddTemp(Location::RequiresRegister()); // For target method.
+ }
+ if (code_ptr_location == CodePtrLocation::kCallCriticalNative ||
+ method_load_kind == MethodLoadKind::kRecursive) {
+ // For `kCallCriticalNative` we need the current method as the hidden argument
+ // if we reach the dlsym lookup stub for @CriticalNative.
+ locations->SetInAt(call->GetCurrentMethodIndex(), visitor->GetMethodLocation());
+ } else {
+ locations->AddTemp(visitor->GetMethodLocation());
+ if (method_load_kind == MethodLoadKind::kRuntimeCall) {
+ locations->SetInAt(call->GetCurrentMethodIndex(), Location::RequiresRegister());
+ }
}
} else if (!invoke->IsInvokePolymorphic()) {
locations->AddTemp(visitor->GetMethodLocation());
}
}
+void CodeGenerator::PrepareCriticalNativeArgumentMoves(
+ HInvokeStaticOrDirect* invoke,
+ /*inout*/InvokeDexCallingConventionVisitor* visitor,
+ /*out*/HParallelMove* parallel_move) {
+ LocationSummary* locations = invoke->GetLocations();
+ for (size_t i = 0, num = invoke->GetNumberOfArguments(); i != num; ++i) {
+ Location in_location = locations->InAt(i);
+ DataType::Type type = invoke->InputAt(i)->GetType();
+ DCHECK_NE(type, DataType::Type::kReference);
+ Location out_location = visitor->GetNextLocation(type);
+ if (out_location.IsStackSlot() || out_location.IsDoubleStackSlot()) {
+ // Stack arguments will need to be moved after adjusting the SP.
+ parallel_move->AddMove(in_location, out_location, type, /*instruction=*/ nullptr);
+ } else {
+ // Register arguments should have been assigned their final locations for register allocation.
+ DCHECK(out_location.Equals(in_location)) << in_location << " -> " << out_location;
+ }
+ }
+}
+
+void CodeGenerator::FinishCriticalNativeFrameSetup(size_t out_frame_size,
+ /*inout*/HParallelMove* parallel_move) {
+ DCHECK_NE(out_frame_size, 0u);
+ IncreaseFrame(out_frame_size);
+ // Adjust the source stack offsets by `out_frame_size`, i.e. the additional
+ // frame size needed for outgoing stack arguments.
+ for (size_t i = 0, num = parallel_move->NumMoves(); i != num; ++i) {
+ MoveOperands* operands = parallel_move->MoveOperandsAt(i);
+ Location source = operands->GetSource();
+ if (operands->GetSource().IsStackSlot()) {
+ operands->SetSource(Location::StackSlot(source.GetStackIndex() + out_frame_size));
+ } else if (operands->GetSource().IsDoubleStackSlot()) {
+ operands->SetSource(Location::DoubleStackSlot(source.GetStackIndex() + out_frame_size));
+ }
+ }
+ // Emit the moves.
+ GetMoveResolver()->EmitNativeCode(parallel_move);
+}
+
+const char* CodeGenerator::GetCriticalNativeShorty(HInvokeStaticOrDirect* invoke,
+ uint32_t* shorty_len) {
+ ScopedObjectAccess soa(Thread::Current());
+ DCHECK(invoke->GetResolvedMethod()->IsCriticalNative());
+ return invoke->GetResolvedMethod()->GetShorty(shorty_len);
+}
+
void CodeGenerator::GenerateInvokeStaticOrDirectRuntimeCall(
HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
- MoveConstant(temp, invoke->GetDexMethodIndex());
+ MethodReference method_reference(invoke->GetMethodReference());
+ MoveConstant(temp, method_reference.index);
// The access check is unnecessary but we do not want to introduce
// extra entrypoints for the codegens that do not support some
@@ -551,7 +604,8 @@ void CodeGenerator::GenerateInvokeStaticOrDirectRuntimeCall(
InvokeRuntime(entrypoint, invoke, invoke->GetDexPc(), slow_path);
}
void CodeGenerator::GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invoke) {
- MoveConstant(invoke->GetLocations()->GetTemp(0), invoke->GetDexMethodIndex());
+ MethodReference method_reference(invoke->GetMethodReference());
+ MoveConstant(invoke->GetLocations()->GetTemp(0), method_reference.index);
// Initialize to anything to silent compiler warnings.
QuickEntrypointEnum entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck;
@@ -579,12 +633,13 @@ void CodeGenerator::GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invok
InvokeRuntime(entrypoint, invoke, invoke->GetDexPc(), nullptr);
}
-void CodeGenerator::GenerateInvokePolymorphicCall(HInvokePolymorphic* invoke) {
+void CodeGenerator::GenerateInvokePolymorphicCall(HInvokePolymorphic* invoke,
+ SlowPathCode* slow_path) {
// invoke-polymorphic does not use a temporary to convey any additional information (e.g. a
// method index) since it requires multiple info from the instruction (registers A, B, H). Not
// using the reservation has no effect on the registers used in the runtime call.
QuickEntrypointEnum entrypoint = kQuickInvokePolymorphic;
- InvokeRuntime(entrypoint, invoke, invoke->GetDexPc(), nullptr);
+ InvokeRuntime(entrypoint, invoke, invoke->GetDexPc(), slow_path);
}
void CodeGenerator::GenerateInvokeCustomCall(HInvokeCustom* invoke) {
@@ -837,7 +892,6 @@ void CodeGenerator::GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_ty
static uint32_t GetBootImageOffsetImpl(const void* object, ImageHeader::ImageSections section) {
Runtime* runtime = Runtime::Current();
- DCHECK(runtime->IsAotCompiler());
const std::vector<gc::space::ImageSpace*>& boot_image_spaces =
runtime->GetHeap()->GetBootImageSpaces();
// Check that the `object` is in the expected section of one of the boot image files.
@@ -853,6 +907,10 @@ static uint32_t GetBootImageOffsetImpl(const void* object, ImageHeader::ImageSec
return dchecked_integral_cast<uint32_t>(offset);
}
+uint32_t CodeGenerator::GetBootImageOffset(ObjPtr<mirror::Object> object) {
+ return GetBootImageOffsetImpl(object.Ptr(), ImageHeader::kSectionObjects);
+}
+
// NO_THREAD_SAFETY_ANALYSIS: Avoid taking the mutator lock, boot image classes are non-moveable.
uint32_t CodeGenerator::GetBootImageOffset(HLoadClass* load_class) NO_THREAD_SAFETY_ANALYSIS {
DCHECK_EQ(load_class->GetLoadKind(), HLoadClass::LoadKind::kBootImageRelRo);
@@ -869,13 +927,28 @@ uint32_t CodeGenerator::GetBootImageOffset(HLoadString* load_string) NO_THREAD_S
return GetBootImageOffsetImpl(string.Ptr(), ImageHeader::kSectionObjects);
}
-uint32_t CodeGenerator::GetBootImageOffset(HInvokeStaticOrDirect* invoke) {
- DCHECK_EQ(invoke->GetMethodLoadKind(), HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo);
+uint32_t CodeGenerator::GetBootImageOffset(HInvoke* invoke) {
ArtMethod* method = invoke->GetResolvedMethod();
DCHECK(method != nullptr);
return GetBootImageOffsetImpl(method, ImageHeader::kSectionArtMethods);
}
+// NO_THREAD_SAFETY_ANALYSIS: Avoid taking the mutator lock, boot image objects are non-moveable.
+uint32_t CodeGenerator::GetBootImageOffset(ClassRoot class_root) NO_THREAD_SAFETY_ANALYSIS {
+ ObjPtr<mirror::Class> klass = GetClassRoot<kWithoutReadBarrier>(class_root);
+ return GetBootImageOffsetImpl(klass.Ptr(), ImageHeader::kSectionObjects);
+}
+
+// NO_THREAD_SAFETY_ANALYSIS: Avoid taking the mutator lock, boot image classes are non-moveable.
+uint32_t CodeGenerator::GetBootImageOffsetOfIntrinsicDeclaringClass(HInvoke* invoke)
+ NO_THREAD_SAFETY_ANALYSIS {
+ DCHECK_NE(invoke->GetIntrinsic(), Intrinsics::kNone);
+ ArtMethod* method = invoke->GetResolvedMethod();
+ DCHECK(method != nullptr);
+ ObjPtr<mirror::Class> declaring_class = method->GetDeclaringClass<kWithoutReadBarrier>();
+ return GetBootImageOffsetImpl(declaring_class.Ptr(), ImageHeader::kSectionObjects);
+}
+
void CodeGenerator::BlockIfInRegister(Location location, bool is_out) const {
// The DCHECKS below check that a register is not specified twice in
// the summary. The out location can overlap with an input, so we need
@@ -1594,6 +1667,7 @@ void CodeGenerator::ValidateInvokeRuntime(QuickEntrypointEnum entrypoint,
(kEmitCompilerReadBarrier &&
!kUseBakerReadBarrier &&
(instruction->IsInstanceFieldGet() ||
+ instruction->IsPredicatedInstanceFieldGet() ||
instruction->IsStaticFieldGet() ||
instruction->IsArrayGet() ||
instruction->IsLoadClass() ||
@@ -1604,7 +1678,8 @@ void CodeGenerator::ValidateInvokeRuntime(QuickEntrypointEnum entrypoint,
<< "instruction->DebugName()=" << instruction->DebugName()
<< " instruction->GetSideEffects().ToString()="
<< instruction->GetSideEffects().ToString()
- << " slow_path->GetDescription()=" << slow_path->GetDescription();
+ << " slow_path->GetDescription()=" << slow_path->GetDescription() << std::endl
+ << "Instruction and args: " << instruction->DumpWithArgs();
}
} else {
// The GC side effect is not required for the instruction. But the instruction might still have
@@ -1629,6 +1704,7 @@ void CodeGenerator::ValidateInvokeRuntimeWithoutRecordingPcInfo(HInstruction* in
// PC-related information.
DCHECK(kUseBakerReadBarrier);
DCHECK(instruction->IsInstanceFieldGet() ||
+ instruction->IsPredicatedInstanceFieldGet() ||
instruction->IsStaticFieldGet() ||
instruction->IsArrayGet() ||
instruction->IsArraySet() ||
@@ -1636,8 +1712,7 @@ void CodeGenerator::ValidateInvokeRuntimeWithoutRecordingPcInfo(HInstruction* in
instruction->IsLoadString() ||
instruction->IsInstanceOf() ||
instruction->IsCheckCast() ||
- (instruction->IsInvokeVirtual() && instruction->GetLocations()->Intrinsified()) ||
- (instruction->IsInvokeStaticOrDirect() && instruction->GetLocations()->Intrinsified()))
+ (instruction->IsInvoke() && instruction->GetLocations()->Intrinsified()))
<< "instruction->DebugName()=" << instruction->DebugName()
<< " slow_path->GetDescription()=" << slow_path->GetDescription();
}