Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  jni_macro_assembler_x86.cc

  Sprache: C
 

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "jni_macro_assembler_x86.h"

#include "base/casts.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "jni/indirect_reference_table.h"
#include "lock_word.h"
#include "thread.h"
#include "utils/assembler.h"

namespace art HIDDEN {
namespace x86 {

static Register GetScratchRegister() {
  // ECX is an argument register on entry and gets spilled in BuildFrame().
  // After that, we can use it as a scratch register.
  return ECX;
}

static dwarf::Reg DWARFReg(Register reg) {
  return dwarf::Reg::X86Core(static_cast<int>(reg));
}

constexpr size_t kFramePointerSize = 4;

static constexpr size_t kNativeStackAlignment = 16;
static_assert(kNativeStackAlignment == kStackAlignment);

#define __ asm_.

void X86JNIMacroAssembler::BuildFrame(size_t frame_size,
                                      ManagedRegister method_reg,
                                      ArrayRef<const ManagedRegister> spill_regs) {
  DCHECK_EQ(CodeSize(), 0U);  // Nothing emitted yet.
  cfi().SetCurrentCFAOffset(4);  // Return address on stack.
  if (frame_size == kFramePointerSize) {
    // For @CriticalNative tail call.
    CHECK(method_reg.IsNoRegister());
    CHECK(spill_regs.empty());
  } else if (method_reg.IsNoRegister()) {
    CHECK_ALIGNED(frame_size, kNativeStackAlignment);
  } else {
    CHECK_ALIGNED(frame_size, kStackAlignment);
  }
  int gpr_count = 0;
  for (int i = spill_regs.size() - 1; i >= 0; --i) {
    Register spill = spill_regs[i].AsX86().AsCpuRegister();
    __ pushl(spill);
    gpr_count++;
    cfi().AdjustCFAOffset(kFramePointerSize);
    cfi().RelOffset(DWARFReg(spill), 0);
  }

  // return address then method on stack.
  int32_t adjust = frame_size - gpr_count * kFramePointerSize -
      kFramePointerSize /*return address*/ -
      (method_reg.IsRegister() ? kFramePointerSize /*method*/ : 0u);
  if (adjust != 0) {
    __ addl(ESP, Immediate(-adjust));
    cfi().AdjustCFAOffset(adjust);
  }
  if (method_reg.IsRegister()) {
    __ pushl(method_reg.AsX86().AsCpuRegister());
    cfi().AdjustCFAOffset(kFramePointerSize);
  }
  DCHECK_EQ(static_cast<size_t>(cfi().GetCurrentCFAOffset()), frame_size);
}

void X86JNIMacroAssembler::RemoveFrame(size_t frame_size,
                                       ArrayRef<const ManagedRegister> spill_regs,
                                       [[maybe_unused]] bool may_suspend) {
  CHECK_ALIGNED(frame_size, kNativeStackAlignment);
  cfi().RememberState();
  // -kFramePointerSize for ArtMethod*.
  int adjust = frame_size - spill_regs.size() * kFramePointerSize - kFramePointerSize;
  if (adjust != 0) {
    __ addl(ESP, Immediate(adjust));
    cfi().AdjustCFAOffset(-adjust);
  }
  for (size_t i = 0; i < spill_regs.size(); ++i) {
    Register spill = spill_regs[i].AsX86().AsCpuRegister();
    __ popl(spill);
    cfi().AdjustCFAOffset(-static_cast<int>(kFramePointerSize));
    cfi().Restore(DWARFReg(spill));
  }
  __ ret();
  // The CFI should be restored for any code that follows the exit block.
  cfi().RestoreState();
  cfi().DefCFAOffset(frame_size);
}

void X86JNIMacroAssembler::IncreaseFrameSize(size_t adjust) {
  if (adjust != 0u) {
    CHECK_ALIGNED(adjust, kNativeStackAlignment);
    __ addl(ESP, Immediate(-adjust));
    cfi().AdjustCFAOffset(adjust);
  }
}

static void DecreaseFrameSizeImpl(X86Assembler* assembler, size_t adjust) {
  if (adjust != 0u) {
    CHECK_ALIGNED(adjust, kNativeStackAlignment);
    assembler->addl(ESP, Immediate(adjust));
    assembler->cfi().AdjustCFAOffset(-adjust);
  }
}

ManagedRegister X86JNIMacroAssembler::CoreRegisterWithSize(ManagedRegister src, size_t size) {
  DCHECK(src.AsX86().IsCpuRegister());
  DCHECK_EQ(size, 4u);
  return src;
}

void X86JNIMacroAssembler::DecreaseFrameSize(size_t adjust) {
  DecreaseFrameSizeImpl(&asm_, adjust);
}

void X86JNIMacroAssembler::Store(FrameOffset offs, ManagedRegister msrc, size_t size) {
  Store(X86ManagedRegister::FromCpuRegister(ESP), MemberOffset(offs.Int32Value()), msrc, size);
}

void X86JNIMacroAssembler::Store(ManagedRegister mbase,
                                 MemberOffset offs,
                                 ManagedRegister msrc,
                                 size_t size) {
  X86ManagedRegister base = mbase.AsX86();
  X86ManagedRegister src = msrc.AsX86();
  if (src.IsNoRegister()) {
    CHECK_EQ(0u, size);
  } else if (src.IsCpuRegister()) {
    CHECK_EQ(4u, size);
    __ movl(Address(base.AsCpuRegister(), offs), src.AsCpuRegister());
  } else if (src.IsRegisterPair()) {
    CHECK_EQ(8u, size);
    __ movl(Address(base.AsCpuRegister(), offs), src.AsRegisterPairLow());
    __ movl(Address(base.AsCpuRegister(), FrameOffset(offs.Int32Value()+4)),
            src.AsRegisterPairHigh());
  } else if (src.IsX87Register()) {
    if (size == 4) {
      __ fstps(Address(base.AsCpuRegister(), offs));
    } else {
      __ fstpl(Address(base.AsCpuRegister(), offs));
    }
  } else {
    CHECK(src.IsXmmRegister());
    if (size == 4) {
      __ movss(Address(base.AsCpuRegister(), offs), src.AsXmmRegister());
    } else {
      __ movsd(Address(base.AsCpuRegister(), offs), src.AsXmmRegister());
    }
  }
}

void X86JNIMacroAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
  X86ManagedRegister src = msrc.AsX86();
  CHECK(src.IsCpuRegister());
  __ movl(Address(ESP, dest), src.AsCpuRegister());
}

void X86JNIMacroAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs, bool tag_sp) {
  if (tag_sp) {
    // There is no free register, store contents onto stack and restore back later.
    Register scratch = ECX;
    __ movl(Address(ESP, -32), scratch);
    __ movl(scratch, ESP);
    __ orl(scratch, Immediate(0x2));
    __ fs()->movl(Address::Absolute(thr_offs), scratch);
    __ movl(scratch, Address(ESP, -32));
  } else {
    __ fs()->movl(Address::Absolute(thr_offs), ESP);
  }
}

void X86JNIMacroAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
  Load(mdest, X86ManagedRegister::FromCpuRegister(ESP), MemberOffset(src.Int32Value()), size);
}

void X86JNIMacroAssembler::Load(ManagedRegister mdest,
                                ManagedRegister mbase,
                                MemberOffset offs,
                                size_t size) {
  X86ManagedRegister dest = mdest.AsX86();
  X86ManagedRegister base = mbase.AsX86();
  if (dest.IsNoRegister()) {
    CHECK_EQ(0u, size);
  } else if (dest.IsCpuRegister()) {
    CHECK_EQ(4u, size);
    __ movl(dest.AsCpuRegister(), Address(base.AsCpuRegister(), offs));
  } else if (dest.IsRegisterPair()) {
    CHECK_EQ(8u, size);
    __ movl(dest.AsRegisterPairLow(), Address(base.AsCpuRegister(), offs));
    __ movl(dest.AsRegisterPairHigh(),
            Address(base.AsCpuRegister(), FrameOffset(offs.Int32Value()+4)));
  } else if (dest.IsX87Register()) {
    if (size == 4) {
      __ flds(Address(base.AsCpuRegister(), offs));
    } else {
      __ fldl(Address(base.AsCpuRegister(), offs));
    }
  } else {
    CHECK(dest.IsXmmRegister());
    if (size == 4) {
      __ movss(dest.AsXmmRegister(), Address(base.AsCpuRegister(), offs));
    } else {
      __ movsd(dest.AsXmmRegister(), Address(base.AsCpuRegister(), offs));
    }
  }
}

void X86JNIMacroAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) {
  X86ManagedRegister dest = mdest.AsX86();
  CHECK(dest.IsCpuRegister());
  __ fs()->movl(dest.AsCpuRegister(), Address::Absolute(offs));
}

void X86JNIMacroAssembler::SignExtend(ManagedRegister mreg, size_t size) {
  X86ManagedRegister reg = mreg.AsX86();
  CHECK(size == 1 || size == 2) << size;
  CHECK(reg.IsCpuRegister()) << reg;
  if (size == 1) {
    __ movsxb(reg.AsCpuRegister(), reg.AsByteRegister());
  } else {
    __ movsxw(reg.AsCpuRegister(), reg.AsCpuRegister());
  }
}

void X86JNIMacroAssembler::ZeroExtend(ManagedRegister mreg, size_t size) {
  X86ManagedRegister reg = mreg.AsX86();
  CHECK(size == 1 || size == 2) << size;
  CHECK(reg.IsCpuRegister()) << reg;
  if (size == 1) {
    __ movzxb(reg.AsCpuRegister(), reg.AsByteRegister());
  } else {
    __ movzxw(reg.AsCpuRegister(), reg.AsCpuRegister());
  }
}

void X86JNIMacroAssembler::MoveArguments(ArrayRef<ArgumentLocation> dests,
                                         ArrayRef<ArgumentLocation> srcs,
                                         ArrayRef<FrameOffset> refs) {
  size_t arg_count = dests.size();
  DCHECK_EQ(arg_count, srcs.size());
  DCHECK_EQ(arg_count, refs.size());

  // Store register args to stack slots. Convert processed references to `jobject`.
  bool found_hidden_arg = false;
  for (size_t i = 0; i != arg_count; ++i) {
    const ArgumentLocation& src = srcs[i];
    const ArgumentLocation& dest = dests[i];
    const FrameOffset ref = refs[i];
    DCHECK_EQ(src.GetSize(), dest.GetSize());  // Even for references.
    if (src.IsRegister()) {
      if (UNLIKELY(dest.IsRegister())) {
        if (dest.GetRegister().Equals(src.GetRegister())) {
          // JNI compiler sometimes adds a no-op move.
          continue;
        }
        // Native ABI has only stack arguments but we may pass one "hidden arg" in register.
        CHECK(!found_hidden_arg);
        found_hidden_arg = true;
        DCHECK_EQ(ref, kInvalidReferenceOffset);
        DCHECK(
            !dest.GetRegister().Equals(X86ManagedRegister::FromCpuRegister(GetScratchRegister())));
        Move(dest.GetRegister(), src.GetRegister(), dest.GetSize());
      } else {
        if (ref != kInvalidReferenceOffset) {
          // Note: We can clobber `src` here as the register cannot hold more than one argument.
          //       This overload of `CreateJObject()` currently does not use the scratch
          //       register ECX, so this shall not clobber another argument.
          CreateJObject(src.GetRegister(), ref, src.GetRegister(), /*null_allowed=*/ i != 0u);
        }
        Store(dest.GetFrameOffset(), src.GetRegister(), dest.GetSize());
      }
    } else {
      // Delay copying until we have spilled all registers, including the scratch register ECX.
    }
  }

  // Copy incoming stack args. Convert processed references to `jobject`.
  for (size_t i = 0; i != arg_count; ++i) {
    const ArgumentLocation& src = srcs[i];
    const ArgumentLocation& dest = dests[i];
    const FrameOffset ref = refs[i];
    DCHECK_EQ(src.GetSize(), dest.GetSize());  // Even for references.
    if (!src.IsRegister()) {
      DCHECK(!dest.IsRegister());
      if (ref != kInvalidReferenceOffset) {
        DCHECK_EQ(srcs[i].GetFrameOffset(), refs[i]);
        CreateJObject(dest.GetFrameOffset(), ref, /*null_allowed=*/ i != 0u);
      } else {
        Copy(dest.GetFrameOffset(), src.GetFrameOffset(), dest.GetSize());
      }
    }
  }
}

void X86JNIMacroAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
  DCHECK(!mdest.Equals(X86ManagedRegister::FromCpuRegister(GetScratchRegister())));
  X86ManagedRegister dest = mdest.AsX86();
  X86ManagedRegister src = msrc.AsX86();
  if (!dest.Equals(src)) {
    if (dest.IsCpuRegister() && src.IsCpuRegister()) {
      __ movl(dest.AsCpuRegister(), src.AsCpuRegister());
    } else if (src.IsX87Register() && dest.IsXmmRegister()) {
      // Pass via stack and pop X87 register
      IncreaseFrameSize(16);
      if (size == 4) {
        CHECK_EQ(src.AsX87Register(), ST0);
        __ fstps(Address(ESP, 0));
        __ movss(dest.AsXmmRegister(), Address(ESP, 0));
      } else {
        CHECK_EQ(src.AsX87Register(), ST0);
        __ fstpl(Address(ESP, 0));
        __ movsd(dest.AsXmmRegister(), Address(ESP, 0));
      }
      DecreaseFrameSize(16);
    } else {
      // TODO: x87, SSE
      UNIMPLEMENTED(FATAL) << ": Move " << dest << ", " << src;
    }
  }
}

void X86JNIMacroAssembler::Move(ManagedRegister mdest, size_t value) {
  X86ManagedRegister dest = mdest.AsX86();
  __ movl(dest.AsCpuRegister(), Immediate(value));
}

void X86JNIMacroAssembler::Copy(FrameOffset dest, FrameOffset src, size_t size) {
  DCHECK(size == 4 || size == 8) << size;
  Register scratch = GetScratchRegister();
  __ movl(scratch, Address(ESP, src));
  __ movl(Address(ESP, dest), scratch);
  if (size == 8) {
    __ movl(scratch, Address(ESP, FrameOffset(src.Int32Value() + 4)));
    __ movl(Address(ESP, FrameOffset(dest.Int32Value() + 4)), scratch);
  }
}

void X86JNIMacroAssembler::CreateJObject(ManagedRegister mout_reg,
                                         FrameOffset spilled_reference_offset,
                                         ManagedRegister min_reg,
                                         bool null_allowed) {
  X86ManagedRegister out_reg = mout_reg.AsX86();
  X86ManagedRegister in_reg = min_reg.AsX86();
  CHECK(in_reg.IsCpuRegister());
  CHECK(out_reg.IsCpuRegister());
  VerifyObject(in_reg, null_allowed);
  if (null_allowed) {
    Label null_arg;
    if (!out_reg.Equals(in_reg)) {
      __ xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister());
    }
    __ testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister());
    __ j(kZero, &null_arg);
    __ leal(out_reg.AsCpuRegister(), Address(ESP, spilled_reference_offset));
    __ Bind(&null_arg);
  } else {
    __ leal(out_reg.AsCpuRegister(), Address(ESP, spilled_reference_offset));
  }
}

void X86JNIMacroAssembler::CreateJObject(FrameOffset out_off,
                                         FrameOffset spilled_reference_offset,
                                         bool null_allowed) {
  Register scratch = GetScratchRegister();
  if (null_allowed) {
    Label null_arg;
    __ movl(scratch, Address(ESP, spilled_reference_offset));
    __ testl(scratch, scratch);
    __ j(kZero, &null_arg);
    __ leal(scratch, Address(ESP, spilled_reference_offset));
    __ Bind(&null_arg);
  } else {
    __ leal(scratch, Address(ESP, spilled_reference_offset));
  }
  __ movl(Address(ESP, out_off), scratch);
}

void X86JNIMacroAssembler::DecodeJNITransitionOrLocalJObject(ManagedRegister reg,
                                                             JNIMacroLabel* slow_path,
                                                             JNIMacroLabel* resume) {
  constexpr uint32_t kGlobalOrWeakGlobalMask =
      dchecked_integral_cast<uint32_t>(IndirectReferenceTable::GetGlobalOrWeakGlobalMask());
  constexpr uint32_t kIndirectRefKindMask =
      dchecked_integral_cast<uint32_t>(IndirectReferenceTable::GetIndirectRefKindMask());
  __ testl(reg.AsX86().AsCpuRegister(), Immediate(kGlobalOrWeakGlobalMask));
  __ j(kNotZero, X86JNIMacroLabel::Cast(slow_path)->AsX86());
  __ andl(reg.AsX86().AsCpuRegister(), Immediate(~kIndirectRefKindMask));
  __ j(kZero, X86JNIMacroLabel::Cast(resume)->AsX86());  // Skip load for null.
  __ movl(reg.AsX86().AsCpuRegister(), Address(reg.AsX86().AsCpuRegister(), /*disp=*/ 0));
}

void X86JNIMacroAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {
  // TODO: not validating references
}

void X86JNIMacroAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) {
  // TODO: not validating references
}

void X86JNIMacroAssembler::Jump(ManagedRegister mbase, Offset offset) {
  X86ManagedRegister base = mbase.AsX86();
  CHECK(base.IsCpuRegister());
  __ jmp(Address(base.AsCpuRegister(), offset.Int32Value()));
}

void X86JNIMacroAssembler::Call(ManagedRegister mbase, Offset offset) {
  X86ManagedRegister base = mbase.AsX86();
  CHECK(base.IsCpuRegister());
  __ call(Address(base.AsCpuRegister(), offset.Int32Value()));
  // TODO: place reference map on call
}

void X86JNIMacroAssembler::CallFromThread(ThreadOffset32 offset) {
  __ fs()->call(Address::Absolute(offset));
}

void X86JNIMacroAssembler::GetCurrentThread(ManagedRegister dest) {
  __ fs()->movl(dest.AsX86().AsCpuRegister(),
                Address::Absolute(Thread::SelfOffset<kX86PointerSize>()));
}

void X86JNIMacroAssembler::GetCurrentThread(FrameOffset offset) {
  Register scratch = GetScratchRegister();
  __ fs()->movl(scratch, Address::Absolute(Thread::SelfOffset<kX86PointerSize>()));
  __ movl(Address(ESP, offset), scratch);
}

void X86JNIMacroAssembler::TryToTransitionFromRunnableToNative(
    JNIMacroLabel* label, ArrayRef<const ManagedRegister> scratch_regs) {
  constexpr uint32_t kNativeStateValue = Thread::StoredThreadStateValue(ThreadState::kNative);
  constexpr uint32_t kRunnableStateValue = Thread::StoredThreadStateValue(ThreadState::kRunnable);
  constexpr ThreadOffset32 thread_flags_offset = Thread::ThreadFlagsOffset<kX86PointerSize>();
  constexpr ThreadOffset32 thread_held_mutex_mutator_lock_offset =
      Thread::HeldMutexOffset<kX86PointerSize>(kMutatorLock);

  // We need to preserve managed argument EAX.
  DCHECK_GE(scratch_regs.size(), 2u);
  Register saved_eax = scratch_regs[0].AsX86().AsCpuRegister();
  Register scratch = scratch_regs[1].AsX86().AsCpuRegister();

  // CAS release, old_value = kRunnableStateValue, new_value = kNativeStateValue, no flags.
  __ movl(saved_eax, EAX);  // Save EAX.
  static_assert(kRunnableStateValue == 0u);
  __ xorl(EAX, EAX);
  __ movl(scratch, Immediate(kNativeStateValue));
  __ fs()->LockCmpxchgl(Address::Absolute(thread_flags_offset.Uint32Value()), scratch);
  // LOCK CMPXCHG has full barrier semantics, so we don't need barriers here.
  __ movl(EAX, saved_eax);  // Restore EAX; MOV does not change flags.
  // If any flags are set, go to the slow path.
  __ j(kNotZero, X86JNIMacroLabel::Cast(label)->AsX86());

  // Clear `self->tlsPtr_.held_mutexes[kMutatorLock]`.
  __ fs()->movl(Address::Absolute(thread_held_mutex_mutator_lock_offset.Uint32Value()),
                Immediate(0));
}

void X86JNIMacroAssembler::TryToTransitionFromNativeToRunnable(
    JNIMacroLabel* label,
    ArrayRef<const ManagedRegister> scratch_regs,
    ManagedRegister return_reg) {
  constexpr uint32_t kNativeStateValue = Thread::StoredThreadStateValue(ThreadState::kNative);
  constexpr uint32_t kRunnableStateValue = Thread::StoredThreadStateValue(ThreadState::kRunnable);
  constexpr ThreadOffset32 thread_flags_offset = Thread::ThreadFlagsOffset<kX86PointerSize>();
  constexpr ThreadOffset32 thread_held_mutex_mutator_lock_offset =
      Thread::HeldMutexOffset<kX86PointerSize>(kMutatorLock);
  constexpr ThreadOffset32 thread_mutator_lock_offset =
      Thread::MutatorLockOffset<kX86PointerSize>();

  size_t scratch_index = 0u;
  auto get_scratch_reg = [&]() {
    while (true) {
      DCHECK_LT(scratch_index, scratch_regs.size());
      X86ManagedRegister scratch_reg = scratch_regs[scratch_index].AsX86();
      ++scratch_index;
      DCHECK(!scratch_reg.Overlaps(return_reg.AsX86()));
      if (scratch_reg.AsCpuRegister() != EAX) {
        return scratch_reg.AsCpuRegister();
      }
    }
  };
  Register scratch = get_scratch_reg();
  bool preserve_eax = return_reg.AsX86().Overlaps(X86ManagedRegister::FromCpuRegister(EAX));
  Register saved_eax = preserve_eax ? get_scratch_reg() : kNoRegister;

  // CAS acquire, old_value = kNativeStateValue, new_value = kRunnableStateValue, no flags.
  if (preserve_eax) {
    __ movl(saved_eax, EAX);  // Save EAX.
  }
  __ movl(EAX, Immediate(kNativeStateValue));
  static_assert(kRunnableStateValue == 0u);
  __ xorl(scratch, scratch);
  __ fs()->LockCmpxchgl(Address::Absolute(thread_flags_offset.Uint32Value()), scratch);
  // LOCK CMPXCHG has full barrier semantics, so we don't need barriers here.
  if (preserve_eax) {
    __ movl(EAX, saved_eax);  // Restore EAX; MOV does not change flags.
  }
  // If any flags are set, or the state is not Native, go to the slow path.
  // (While the thread can theoretically transition between different Suspended states,
  // it would be very unexpected to see a state other than Native at this point.)
  __ j(kNotZero, X86JNIMacroLabel::Cast(label)->AsX86());

  // Set `self->tlsPtr_.held_mutexes[kMutatorLock]` to the mutator lock.
  __ fs()->movl(scratch, Address::Absolute(thread_mutator_lock_offset.Uint32Value()));
  __ fs()->movl(Address::Absolute(thread_held_mutex_mutator_lock_offset.Uint32Value()),
                scratch);
}

void X86JNIMacroAssembler::SuspendCheck(JNIMacroLabel* label) {
  __ fs()->testl(Address::Absolute(Thread::ThreadFlagsOffset<kX86PointerSize>()),
                 Immediate(Thread::SuspendOrCheckpointRequestFlags()));
  __ j(kNotZero, X86JNIMacroLabel::Cast(label)->AsX86());
}

void X86JNIMacroAssembler::ExceptionPoll(JNIMacroLabel* label) {
  __ fs()->cmpl(Address::Absolute(Thread::ExceptionOffset<kX86PointerSize>()), Immediate(0));
  __ j(kNotEqual, X86JNIMacroLabel::Cast(label)->AsX86());
}

void X86JNIMacroAssembler::DeliverPendingException() {
  // Pass exception as argument in EAX
  __ fs()->movl(EAX, Address::Absolute(Thread::ExceptionOffset<kX86PointerSize>()));
  __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86PointerSize, pDeliverException)));
  // this call should never return
  __ int3();
}

std::unique_ptr<JNIMacroLabel> X86JNIMacroAssembler::CreateLabel() {
  return std::unique_ptr<JNIMacroLabel>(new (asm_.GetAllocator()) X86JNIMacroLabel());
}

void X86JNIMacroAssembler::Jump(JNIMacroLabel* label) {
  CHECK(label != nullptr);
  __ jmp(X86JNIMacroLabel::Cast(label)->AsX86());
}

static Condition UnaryConditionToX86Condition(JNIMacroUnaryCondition cond) {
  switch (cond) {
    case JNIMacroUnaryCondition::kZero:
      return kZero;
    case JNIMacroUnaryCondition::kNotZero:
      return kNotZero;
  }
}

void X86JNIMacroAssembler::TestGcMarking(JNIMacroLabel* label, JNIMacroUnaryCondition cond) {
  CHECK(label != nullptr);

  // CMP self->tls32_.is_gc_marking, 0
  // Jcc <Offset>
  DCHECK_EQ(Thread::IsGcMarkingSize(), 4u);
  __ fs()->cmpl(Address::Absolute(Thread::IsGcMarkingOffset<kX86PointerSize>()), Immediate(0));
  __ j(UnaryConditionToX86Condition(cond), X86JNIMacroLabel::Cast(label)->AsX86());
}

void X86JNIMacroAssembler::TestMarkBit(ManagedRegister mref,
                                       JNIMacroLabel* label,
                                       JNIMacroUnaryCondition cond) {
  DCHECK(kUseBakerReadBarrier);
  Register ref = mref.AsX86().AsCpuRegister();
  static_assert(LockWord::kMarkBitStateSize == 1u);
  __ testl(Address(ref, mirror::Object::MonitorOffset().SizeValue()),
           Immediate(LockWord::kMarkBitStateMaskShifted));
  __ j(UnaryConditionToX86Condition(cond), X86JNIMacroLabel::Cast(label)->AsX86());
}


void X86JNIMacroAssembler::TestByteAndJumpIfNotZero(uintptr_t address, JNIMacroLabel* label) {
  __ cmpb(Address::Absolute(address), Immediate(0));
  __ j(kNotZero, X86JNIMacroLabel::Cast(label)->AsX86());
}

void X86JNIMacroAssembler::Bind(JNIMacroLabel* label) {
  CHECK(label != nullptr);
  __ Bind(X86JNIMacroLabel::Cast(label)->AsX86());
}

#undef __

}  // namespace x86
}  // namespace art

Messung V0.5 in Prozent
C=81 H=93 G=86

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik