diff options
| author | 2016-11-10 18:05:50 +0000 | |
|---|---|---|
| committer | 2016-11-10 18:05:50 +0000 | |
| commit | 977919fbcbfbf0c1c3fa97e51490bc678da646d2 (patch) | |
| tree | 3e462b1ea5887345ed025b030b0c0a4b71003524 /compiler/optimizing | |
| parent | ee59d46595bb860fea26122f47f8797d2d0fe5f4 (diff) | |
| parent | aa474eb597056d21c0b21d353b9b6aa460351d0f (diff) | |
Merge "Avoid read barriers for inlined check cast"
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 69 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.h | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 69 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.h | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 53 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.h | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 116 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 3 |
8 files changed, 196 insertions, 123 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 25d3855e39..8ca8b8a57b 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -6036,7 +6036,7 @@ static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) { return 0; } -// InteraceCheck has 3 temps, one for holding the number of interfaces, one for the current +// Interface case has 3 temps, one for holding the number of interfaces, one for the current // interface pointer, one for loading the current interface. // The other checks have one temp for loading the object's class. static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) { @@ -6126,7 +6126,11 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { Label loop; __ Bind(&loop); // /* HeapReference<Class> */ out = out->super_class_ - GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + super_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); // If `out` is null, we use it for the result, and jump to `done`. __ CompareAndBranchIfZero(out, &done); __ cmp(out, ShifterOperand(cls)); @@ -6145,7 +6149,11 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { __ cmp(out, ShifterOperand(cls)); __ b(&success, EQ); // /* HeapReference<Class> */ out = out->super_class_ - GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + super_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); __ CompareAndBranchIfNonZero(out, &loop); // If `out` is null, we use it for the result, and jump to `done`. __ b(&done); @@ -6164,7 +6172,11 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { __ b(&exact_check, EQ); // Otherwise, we need to check that the object's class is a non-primitive array. // /* HeapReference<Class> */ out = out->component_type_ - GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + component_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); // If `out` is null, we use it for the result, and jump to `done`. __ CompareAndBranchIfZero(out, &done); __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset); @@ -6284,12 +6296,15 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { const uint32_t object_array_data_offset = mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value(); - bool is_type_check_slow_path_fatal = - (type_check_kind == TypeCheckKind::kExactCheck || - type_check_kind == TypeCheckKind::kAbstractClassCheck || - type_check_kind == TypeCheckKind::kClassHierarchyCheck || - type_check_kind == TypeCheckKind::kArrayObjectCheck) && - !instruction->CanThrowIntoCatchBlock(); + bool is_type_check_slow_path_fatal = false; + if (!kEmitCompilerReadBarrier) { + is_type_check_slow_path_fatal = + (type_check_kind == TypeCheckKind::kExactCheck || + type_check_kind == TypeCheckKind::kAbstractClassCheck || + type_check_kind == TypeCheckKind::kClassHierarchyCheck || + type_check_kind == TypeCheckKind::kArrayObjectCheck) && + !instruction->CanThrowIntoCatchBlock(); + } SlowPathCodeARM* type_check_slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction, is_type_check_slow_path_fatal); @@ -6310,7 +6325,7 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { obj_loc, class_offset, maybe_temp2_loc, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); __ cmp(temp, ShifterOperand(cls)); // Jump to slow path for throwing the exception or doing a @@ -6326,14 +6341,18 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { obj_loc, class_offset, maybe_temp2_loc, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // If the class is abstract, we eagerly fetch the super class of the // object to avoid doing a comparison we know will fail. Label loop; __ Bind(&loop); // /* HeapReference<Class> */ temp = temp->super_class_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + super_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the class reference currently in `temp` is null, jump to the slow path to throw the // exception. @@ -6352,7 +6371,7 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { obj_loc, class_offset, maybe_temp2_loc, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // Walk over the class hierarchy to find a match. Label loop; @@ -6361,7 +6380,11 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { __ b(&done, EQ); // /* HeapReference<Class> */ temp = temp->super_class_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + super_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the class reference currently in `temp` is null, jump to the slow path to throw the // exception. @@ -6378,7 +6401,7 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { obj_loc, class_offset, maybe_temp2_loc, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // Do an exact check. __ cmp(temp, ShifterOperand(cls)); @@ -6386,7 +6409,11 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { // Otherwise, we need to check that the object's class is a non-primitive array. // /* HeapReference<Class> */ temp = temp->component_type_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + component_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the component type is null, jump to the slow path to throw the exception. __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel()); // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type` @@ -6730,9 +6757,11 @@ void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instr void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction, Location out, uint32_t offset, - Location maybe_temp) { + Location maybe_temp, + bool emit_read_barrier) { Register out_reg = out.AsRegister<Register>(); - if (kEmitCompilerReadBarrier) { + if (emit_read_barrier) { + CHECK(kEmitCompilerReadBarrier); DCHECK(maybe_temp.IsRegister()) << maybe_temp; if (kUseBakerReadBarrier) { // Load with fast path based Baker's read barrier. @@ -6766,7 +6795,7 @@ void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction Register out_reg = out.AsRegister<Register>(); Register obj_reg = obj.AsRegister<Register>(); if (emit_read_barrier) { - DCHECK(kEmitCompilerReadBarrier); + CHECK(kEmitCompilerReadBarrier); if (kUseBakerReadBarrier) { DCHECK(maybe_temp.IsRegister()) << maybe_temp; // Load with fast path based Baker's read barrier. diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 6561984fe4..e953df893d 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -263,7 +263,8 @@ class InstructionCodeGeneratorARM : public InstructionCodeGenerator { void GenerateReferenceLoadOneRegister(HInstruction* instruction, Location out, uint32_t offset, - Location maybe_temp); + Location maybe_temp, + bool emit_read_barrier); // Generate a heap reference load using two different registers // `out` and `obj`: // diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index c54e8e1130..6f55b422fa 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -3344,7 +3344,7 @@ static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) { return 0; } -// InteraceCheck has 3 temps, one for holding the number of interfaces, one for the current +// Interface case has 3 temps, one for holding the number of interfaces, one for the current // interface pointer, one for loading the current interface. // The other checks have one temp for loading the object's class. static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) { @@ -3436,7 +3436,11 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { vixl::aarch64::Label loop, success; __ Bind(&loop); // /* HeapReference<Class> */ out = out->super_class_ - GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + super_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); // If `out` is null, we use it for the result, and jump to `done`. __ Cbz(out, &done); __ Cmp(out, cls); @@ -3455,7 +3459,11 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { __ Cmp(out, cls); __ B(eq, &success); // /* HeapReference<Class> */ out = out->super_class_ - GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + super_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); __ Cbnz(out, &loop); // If `out` is null, we use it for the result, and jump to `done`. __ B(&done); @@ -3474,7 +3482,11 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { __ B(eq, &exact_check); // Otherwise, we need to check that the object's class is a non-primitive array. // /* HeapReference<Class> */ out = out->component_type_ - GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + component_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); // If `out` is null, we use it for the result, and jump to `done`. __ Cbz(out, &done); __ Ldrh(out, HeapOperand(out, primitive_offset)); @@ -3596,12 +3608,15 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { const uint32_t object_array_data_offset = mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value(); - bool is_type_check_slow_path_fatal = - (type_check_kind == TypeCheckKind::kExactCheck || - type_check_kind == TypeCheckKind::kAbstractClassCheck || - type_check_kind == TypeCheckKind::kClassHierarchyCheck || - type_check_kind == TypeCheckKind::kArrayObjectCheck) && - !instruction->CanThrowIntoCatchBlock(); + bool is_type_check_slow_path_fatal = false; + if (!kEmitCompilerReadBarrier) { + is_type_check_slow_path_fatal = + (type_check_kind == TypeCheckKind::kExactCheck || + type_check_kind == TypeCheckKind::kAbstractClassCheck || + type_check_kind == TypeCheckKind::kClassHierarchyCheck || + type_check_kind == TypeCheckKind::kArrayObjectCheck) && + !instruction->CanThrowIntoCatchBlock(); + } SlowPathCodeARM64* type_check_slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(instruction, is_type_check_slow_path_fatal); @@ -3622,7 +3637,7 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { obj_loc, class_offset, maybe_temp2_loc, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); __ Cmp(temp, cls); // Jump to slow path for throwing the exception or doing a @@ -3638,14 +3653,18 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { obj_loc, class_offset, maybe_temp2_loc, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // If the class is abstract, we eagerly fetch the super class of the // object to avoid doing a comparison we know will fail. vixl::aarch64::Label loop; __ Bind(&loop); // /* HeapReference<Class> */ temp = temp->super_class_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + super_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the class reference currently in `temp` is null, jump to the slow path to throw the // exception. @@ -3663,7 +3682,7 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { obj_loc, class_offset, maybe_temp2_loc, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // Walk over the class hierarchy to find a match. vixl::aarch64::Label loop; @@ -3672,7 +3691,11 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { __ B(eq, &done); // /* HeapReference<Class> */ temp = temp->super_class_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + super_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the class reference currently in `temp` is not null, jump // back at the beginning of the loop. @@ -3689,7 +3712,7 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { obj_loc, class_offset, maybe_temp2_loc, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // Do an exact check. __ Cmp(temp, cls); @@ -3697,7 +3720,11 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { // Otherwise, we need to check that the object's class is a non-primitive array. // /* HeapReference<Class> */ temp = temp->component_type_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + component_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the component type is null, jump to the slow path to throw the exception. __ Cbz(temp, type_check_slow_path->GetEntryLabel()); @@ -5258,10 +5285,12 @@ void InstructionCodeGeneratorARM64::VisitPackedSwitch(HPackedSwitch* switch_inst void InstructionCodeGeneratorARM64::GenerateReferenceLoadOneRegister(HInstruction* instruction, Location out, uint32_t offset, - Location maybe_temp) { + Location maybe_temp, + bool emit_read_barrier) { Primitive::Type type = Primitive::kPrimNot; Register out_reg = RegisterFrom(out, type); - if (kEmitCompilerReadBarrier) { + if (emit_read_barrier) { + CHECK(kEmitCompilerReadBarrier); Register temp_reg = RegisterFrom(maybe_temp, type); if (kUseBakerReadBarrier) { // Load with fast path based Baker's read barrier. @@ -5301,7 +5330,7 @@ void InstructionCodeGeneratorARM64::GenerateReferenceLoadTwoRegisters(HInstructi Register out_reg = RegisterFrom(out, type); Register obj_reg = RegisterFrom(obj, type); if (emit_read_barrier) { - DCHECK(kEmitCompilerReadBarrier); + CHECK(kEmitCompilerReadBarrier); if (kUseBakerReadBarrier) { // Load with fast path based Baker's read barrier. Register temp_reg = RegisterFrom(maybe_temp, type); diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index e8518f661b..e9a47b600f 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -269,7 +269,8 @@ class InstructionCodeGeneratorARM64 : public InstructionCodeGenerator { void GenerateReferenceLoadOneRegister(HInstruction* instruction, Location out, uint32_t offset, - Location maybe_temp); + Location maybe_temp, + bool emit_read_barrier); // Generate a heap reference load using two different registers // `out` and `obj`: // diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 8c6580690b..20bb36dc10 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -6353,7 +6353,7 @@ static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) { return 0; } -// InteraceCheck has 3 temps, one for holding the number of interfaces, one for the current +// Interface case has 3 temps, one for holding the number of interfaces, one for the current // interface pointer, one for loading the current interface. // The other checks have one temp for loading the object's class. static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) { @@ -6449,7 +6449,11 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { NearLabel loop; __ Bind(&loop); // /* HeapReference<Class> */ out = out->super_class_ - GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + super_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); __ testl(out, out); // If `out` is null, we use it for the result, and jump to `done`. __ j(kEqual, &done); @@ -6479,7 +6483,11 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { } __ j(kEqual, &success); // /* HeapReference<Class> */ out = out->super_class_ - GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + super_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); __ testl(out, out); __ j(kNotEqual, &loop); // If `out` is null, we use it for the result, and jump to `done`. @@ -6504,7 +6512,11 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { __ j(kEqual, &exact_check); // Otherwise, we need to check that the object's class is a non-primitive array. // /* HeapReference<Class> */ out = out->component_type_ - GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + component_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); __ testl(out, out); // If `out` is null, we use it for the result, and jump to `done`. __ j(kEqual, &done); @@ -6664,7 +6676,7 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { temp_loc, obj_loc, class_offset, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); if (cls.IsRegister()) { __ cmpl(temp, cls.AsRegister<Register>()); @@ -6684,14 +6696,18 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { temp_loc, obj_loc, class_offset, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // If the class is abstract, we eagerly fetch the super class of the // object to avoid doing a comparison we know will fail. NearLabel loop; __ Bind(&loop); // /* HeapReference<Class> */ temp = temp->super_class_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + super_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the class reference currently in `temp` is null, jump to the slow path to throw the // exception. @@ -6715,7 +6731,7 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { temp_loc, obj_loc, class_offset, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // Walk over the class hierarchy to find a match. NearLabel loop; @@ -6729,7 +6745,11 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { __ j(kEqual, &done); // /* HeapReference<Class> */ temp = temp->super_class_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + super_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the class reference currently in `temp` is not null, jump // back at the beginning of the loop. @@ -6746,7 +6766,7 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { temp_loc, obj_loc, class_offset, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // Do an exact check. if (cls.IsRegister()) { @@ -6759,7 +6779,11 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { // Otherwise, we need to check that the object's class is a non-primitive array. // /* HeapReference<Class> */ temp = temp->component_type_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + component_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the component type is null (i.e. the object not an array), jump to the slow path to // throw the exception. Otherwise proceed with the check. @@ -6787,7 +6811,7 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { // Fast path for the interface check. Since we compare with a memory location in the inner // loop we would need to have cls poisoned. However unpoisoning cls would reset the // conditional flags and cause the conditional jump to be incorrect. Therefore we just jump - // to the slow path if we are running under poisoning + // to the slow path if we are running under poisoning. if (!kPoisonHeapReferences) { // /* HeapReference<Class> */ temp = obj->klass_ GenerateReferenceLoadTwoRegisters(instruction, @@ -6994,9 +7018,10 @@ void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instr void InstructionCodeGeneratorX86::GenerateReferenceLoadOneRegister(HInstruction* instruction, Location out, uint32_t offset, - Location maybe_temp) { + Location maybe_temp, + bool emit_read_barrier) { Register out_reg = out.AsRegister<Register>(); - if (kEmitCompilerReadBarrier) { + if (emit_read_barrier) { if (kUseBakerReadBarrier) { // Load with fast path based Baker's read barrier. // /* HeapReference<Object> */ out = *(out + offset) diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index d2249023e1..87295a4f22 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -240,7 +240,8 @@ class InstructionCodeGeneratorX86 : public InstructionCodeGenerator { void GenerateReferenceLoadOneRegister(HInstruction* instruction, Location out, uint32_t offset, - Location maybe_temp); + Location maybe_temp, + bool emit_read_barrier); // Generate a heap reference load using two different registers // `out` and `obj`: // diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 524cd5b21d..a6dd0c1668 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -5858,7 +5858,11 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { NearLabel loop, success; __ Bind(&loop); // /* HeapReference<Class> */ out = out->super_class_ - GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + super_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); __ testl(out, out); // If `out` is null, we use it for the result, and jump to `done`. __ j(kEqual, &done); @@ -5888,7 +5892,11 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { } __ j(kEqual, &success); // /* HeapReference<Class> */ out = out->super_class_ - GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + super_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); __ testl(out, out); __ j(kNotEqual, &loop); // If `out` is null, we use it for the result, and jump to `done`. @@ -5913,7 +5921,11 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { __ j(kEqual, &exact_check); // Otherwise, we need to check that the object's class is a non-primitive array. // /* HeapReference<Class> */ out = out->component_type_ - GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc); + GenerateReferenceLoadOneRegister(instruction, + out_loc, + component_offset, + maybe_temp_loc, + kEmitCompilerReadBarrier); __ testl(out, out); // If `out` is null, we use it for the result, and jump to `done`. __ j(kEqual, &done); @@ -6060,22 +6072,23 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { is_type_check_slow_path_fatal); codegen_->AddSlowPath(type_check_slow_path); + + NearLabel done; + // Avoid null check if we know obj is not null. + if (instruction->MustDoNullCheck()) { + __ testl(obj, obj); + __ j(kEqual, &done); + } + switch (type_check_kind) { case TypeCheckKind::kExactCheck: case TypeCheckKind::kArrayCheck: { - NearLabel done; - // Avoid null check if we know obj is not null. - if (instruction->MustDoNullCheck()) { - __ testl(obj, obj); - __ j(kEqual, &done); - } - // /* HeapReference<Class> */ temp = obj->klass_ GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); if (cls.IsRegister()) { __ cmpl(temp, cls.AsRegister<CpuRegister>()); } else { @@ -6085,30 +6098,26 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { // Jump to slow path for throwing the exception or doing a // more involved array check. __ j(kNotEqual, type_check_slow_path->GetEntryLabel()); - __ Bind(&done); break; } case TypeCheckKind::kAbstractClassCheck: { - NearLabel done; - // Avoid null check if we know obj is not null. - if (instruction->MustDoNullCheck()) { - __ testl(obj, obj); - __ j(kEqual, &done); - } - // /* HeapReference<Class> */ temp = obj->klass_ GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // If the class is abstract, we eagerly fetch the super class of the // object to avoid doing a comparison we know will fail. NearLabel loop; __ Bind(&loop); // /* HeapReference<Class> */ temp = temp->super_class_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + super_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the class reference currently in `temp` is null, jump to the slow path to throw the // exception. @@ -6122,24 +6131,16 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex())); } __ j(kNotEqual, &loop); - __ Bind(&done); break; } case TypeCheckKind::kClassHierarchyCheck: { - NearLabel done; - // Avoid null check if we know obj is not null. - if (instruction->MustDoNullCheck()) { - __ testl(obj, obj); - __ j(kEqual, &done); - } - // /* HeapReference<Class> */ temp = obj->klass_ GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // Walk over the class hierarchy to find a match. NearLabel loop; __ Bind(&loop); @@ -6152,7 +6153,11 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { __ j(kEqual, &done); // /* HeapReference<Class> */ temp = temp->super_class_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + super_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the class reference currently in `temp` is not null, jump // back at the beginning of the loop. @@ -6160,28 +6165,16 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { __ j(kNotZero, &loop); // Otherwise, jump to the slow path to throw the exception. __ jmp(type_check_slow_path->GetEntryLabel()); - __ Bind(&done); break; } case TypeCheckKind::kArrayObjectCheck: { - // We cannot use a NearLabel here, as its range might be too - // short in some cases when read barriers are enabled. This has - // been observed for instance when the code emitted for this - // case uses high x86-64 registers (R8-R15). - Label done; - // Avoid null check if we know obj is not null. - if (instruction->MustDoNullCheck()) { - __ testl(obj, obj); - __ j(kEqual, &done); - } - // /* HeapReference<Class> */ temp = obj->klass_ GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, - kEmitCompilerReadBarrier); + /*emit_read_barrier*/ false); // Do an exact check. NearLabel check_non_primitive_component_type; if (cls.IsRegister()) { @@ -6194,7 +6187,11 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { // Otherwise, we need to check that the object's class is a non-primitive array. // /* HeapReference<Class> */ temp = temp->component_type_ - GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc); + GenerateReferenceLoadOneRegister(instruction, + temp_loc, + component_offset, + maybe_temp2_loc, + /*emit_read_barrier*/ false); // If the component type is not null (i.e. the object is indeed // an array), jump to label `check_non_primitive_component_type` @@ -6205,7 +6202,6 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { __ j(kZero, type_check_slow_path->GetEntryLabel()); __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot)); __ j(kNotEqual, type_check_slow_path->GetEntryLabel()); - __ Bind(&done); break; } @@ -6219,27 +6215,11 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { // instruction (following the runtime calling convention), which // might be cluttered by the potential first read barrier // emission at the beginning of this method. - - NearLabel done; - // Avoid null check if we know obj is not null. - if (instruction->MustDoNullCheck()) { - __ testl(obj, obj); - __ j(kEqual, &done); - } __ jmp(type_check_slow_path->GetEntryLabel()); - __ Bind(&done); break; } case TypeCheckKind::kInterfaceCheck: - NearLabel done; - - // Avoid null check if we know obj is not null. - if (instruction->MustDoNullCheck()) { - __ testl(obj, obj); - __ j(kEqual, &done); - } - // Fast path for the interface check. We always go slow path for heap poisoning since // unpoisoning cls would require an extra temp. if (!kPoisonHeapReferences) { @@ -6277,10 +6257,13 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { __ Bind(&is_null); } __ jmp(type_check_slow_path->GetEntryLabel()); - __ Bind(&done); break; } + if (done.IsLinked()) { + __ Bind(&done); + } + __ Bind(type_check_slow_path->GetExitLabel()); } @@ -6420,9 +6403,11 @@ void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* in void InstructionCodeGeneratorX86_64::GenerateReferenceLoadOneRegister(HInstruction* instruction, Location out, uint32_t offset, - Location maybe_temp) { + Location maybe_temp, + bool emit_read_barrier) { CpuRegister out_reg = out.AsRegister<CpuRegister>(); - if (kEmitCompilerReadBarrier) { + if (emit_read_barrier) { + CHECK(kEmitCompilerReadBarrier); if (kUseBakerReadBarrier) { // Load with fast path based Baker's read barrier. // /* HeapReference<Object> */ out = *(out + offset) @@ -6455,6 +6440,7 @@ void InstructionCodeGeneratorX86_64::GenerateReferenceLoadTwoRegisters(HInstruct CpuRegister out_reg = out.AsRegister<CpuRegister>(); CpuRegister obj_reg = obj.AsRegister<CpuRegister>(); if (emit_read_barrier) { + CHECK(kEmitCompilerReadBarrier); if (kUseBakerReadBarrier) { // Load with fast path based Baker's read barrier. // /* HeapReference<Object> */ out = *(obj + offset) diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 5a6dc54e7a..807a9f1d80 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -234,7 +234,8 @@ class InstructionCodeGeneratorX86_64 : public InstructionCodeGenerator { void GenerateReferenceLoadOneRegister(HInstruction* instruction, Location out, uint32_t offset, - Location maybe_temp); + Location maybe_temp, + bool emit_read_barrier); // Generate a heap reference load using two different registers // `out` and `obj`: // |