<commit_before>/*
 * Copyright (C) 2011 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 "object_utils.h"

namespace art {

#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
                                 (1 << kDebugDisplayMissingTargets))

const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0,
                            INVALID_REG, INVALID_REG, INVALID_SREG,
                            INVALID_SREG};

/* Mark register usage state and return long retloc */
RegLocation oatGetReturnWide(CompilationUnit* cUnit, bool isDouble)
{
  RegLocation gpr_res = LOC_C_RETURN_WIDE;
  RegLocation fpr_res = LOC_C_RETURN_WIDE_DOUBLE;
  RegLocation res = isDouble ? fpr_res : gpr_res;
  oatClobber(cUnit, res.lowReg);
  oatClobber(cUnit, res.highReg);
  oatLockTemp(cUnit, res.lowReg);
  oatLockTemp(cUnit, res.highReg);
  oatMarkPair(cUnit, res.lowReg, res.highReg);
  return res;
}

RegLocation oatGetReturn(CompilationUnit* cUnit, bool isFloat)
{
  RegLocation gpr_res = LOC_C_RETURN;
  RegLocation fpr_res = LOC_C_RETURN_FLOAT;
  RegLocation res = isFloat ? fpr_res : gpr_res;
  oatClobber(cUnit, res.lowReg);
  if (cUnit->instructionSet == kMips) {
    oatMarkInUse(cUnit, res.lowReg);
  } else {
    oatLockTemp(cUnit, res.lowReg);
  }
  return res;
}

void genInvoke(CompilationUnit* cUnit, CallInfo* info)
{
  if (genIntrinsic(cUnit, info)) {
    return;
  }
  InvokeType originalType = info->type;  // avoiding mutation by ComputeInvokeInfo
  int callState = 0;
  LIR* nullCk;
  LIR** pNullCk = NULL;
  NextCallInsn nextCallInsn;
  oatFlushAllRegs(cUnit);  /* Everything to home location */
  // Explicit register usage
  oatLockCallTemps(cUnit);

  OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
                           *cUnit->dex_file, *cUnit->dex_cache,
                           cUnit->code_item, cUnit->method_idx,
                           cUnit->access_flags);

  uint32_t dexMethodIdx = info->index;
  int vtableIdx;
  uintptr_t directCode;
  uintptr_t directMethod;
  bool skipThis;
  bool fastPath =
    cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, &mUnit, info->type,
                                       vtableIdx, directCode,
                                       directMethod)
    && !SLOW_INVOKE_PATH;
  if (info->type == kInterface) {
    nextCallInsn = fastPath ? nextInterfaceCallInsn
        : nextInterfaceCallInsnWithAccessCheck;
    skipThis = false;
  } else if (info->type == kDirect) {
    if (fastPath) {
      pNullCk = &nullCk;
    }
    nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
    skipThis = false;
  } else if (info->type == kStatic) {
    nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
    skipThis = false;
  } else if (info->type == kSuper) {
    DCHECK(!fastPath);  // Fast path is a direct call.
    nextCallInsn = nextSuperCallInsnSP;
    skipThis = false;
  } else {
    DCHECK_EQ(info->type, kVirtual);
    nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
    skipThis = fastPath;
  }
  if (!info->isRange) {
    callState = genDalvikArgsNoRange(cUnit, info, callState, pNullCk,
                                     nextCallInsn, dexMethodIdx,
                                     vtableIdx, directCode, directMethod,
                                     originalType, skipThis);
  } else {
    callState = genDalvikArgsRange(cUnit, info, callState, pNullCk,
                                   nextCallInsn, dexMethodIdx, vtableIdx,
                                   directCode, directMethod, originalType,
                                   skipThis);
  }
  // Finish up any of the call sequence not interleaved in arg loading
  while (callState >= 0) {
    callState = nextCallInsn(cUnit, info, callState, dexMethodIdx,
                             vtableIdx, directCode, directMethod,
                             originalType);
  }
  if (DISPLAY_MISSING_TARGETS) {
    genShowTarget(cUnit);
  }
#if !defined(TARGET_X86)
  opReg(cUnit, kOpBlx, rINVOKE_TGT);
#else
  if (fastPath && info->type != kInterface) {
    opMem(cUnit, kOpBlx, rARG0, Method::GetCodeOffset().Int32Value());
  } else {
    int trampoline = 0;
    switch (info->type) {
    case kInterface:
      trampoline = fastPath ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
          : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
      break;
    case kDirect:
      trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
      break;
    case kStatic:
      trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
      break;
    case kSuper:
      trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
      break;
    case kVirtual:
      trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
      break;
    default:
      LOG(FATAL) << "Unexpected invoke type";
    }
    opThreadMem(cUnit, kOpBlx, trampoline);
  }
#endif

  oatClobberCalleeSave(cUnit);
  if (info->result.location != kLocInvalid) {
    // We have a following MOVE_RESULT - do it now.
    if (info->result.wide) {
      RegLocation retLoc = oatGetReturnWide(cUnit, info->result.fp);
      storeValueWide(cUnit, info->result, retLoc);
    } else {
      RegLocation retLoc = oatGetReturn(cUnit, info->result.fp);
      storeValue(cUnit, info->result, retLoc);
    }
  }
}

/*
 * Build an array of location records for the incoming arguments.
 * Note: one location record per word of arguments, with dummy
 * high-word loc for wide arguments.  Also pull up any following
 * MOVE_RESULT and incorporate it into the invoke.
 */
CallInfo* newCallInfo(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
                      InvokeType type, bool isRange)
{
  CallInfo* info = (CallInfo*)oatNew(cUnit, sizeof(CallInfo), true,
                                         kAllocMisc);
#if defined(TARGET_X86)
  info->result.location = kLocInvalid;
#else
  MIR* moveResultMIR = oatFindMoveResult(cUnit, bb, mir);
  if (moveResultMIR == NULL) {
    info->result.location = kLocInvalid;
  } else {
    info->result = oatGetRawDest(cUnit, moveResultMIR);
    moveResultMIR->dalvikInsn.opcode = Instruction::NOP;
  }
#endif
  info->numArgWords = mir->ssaRep->numUses;
  info->args = (info->numArgWords == 0) ? NULL : (RegLocation*)
      oatNew(cUnit, sizeof(RegLocation) * info->numArgWords, false, kAllocMisc);
  for (int i = 0; i < info->numArgWords; i++) {
    info->args[i] = oatGetRawSrc(cUnit, mir, i);
  }
  info->optFlags = mir->optimizationFlags;<commit_msg>Disable move-result fusing<commit_after>/*
 * Copyright (C) 2011 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 "object_utils.h"

namespace art {

#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
                                 (1 << kDebugDisplayMissingTargets))

const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0,
                            INVALID_REG, INVALID_REG, INVALID_SREG,
                            INVALID_SREG};

/* Mark register usage state and return long retloc */
RegLocation oatGetReturnWide(CompilationUnit* cUnit, bool isDouble)
{
  RegLocation gpr_res = LOC_C_RETURN_WIDE;
  RegLocation fpr_res = LOC_C_RETURN_WIDE_DOUBLE;
  RegLocation res = isDouble ? fpr_res : gpr_res;
  oatClobber(cUnit, res.lowReg);
  oatClobber(cUnit, res.highReg);
  oatLockTemp(cUnit, res.lowReg);
  oatLockTemp(cUnit, res.highReg);
  oatMarkPair(cUnit, res.lowReg, res.highReg);
  return res;
}

RegLocation oatGetReturn(CompilationUnit* cUnit, bool isFloat)
{
  RegLocation gpr_res = LOC_C_RETURN;
  RegLocation fpr_res = LOC_C_RETURN_FLOAT;
  RegLocation res = isFloat ? fpr_res : gpr_res;
  oatClobber(cUnit, res.lowReg);
  if (cUnit->instructionSet == kMips) {
    oatMarkInUse(cUnit, res.lowReg);
  } else {
    oatLockTemp(cUnit, res.lowReg);
  }
  return res;
}

void genInvoke(CompilationUnit* cUnit, CallInfo* info)
{
  if (genIntrinsic(cUnit, info)) {
    return;
  }
  InvokeType originalType = info->type;  // avoiding mutation by ComputeInvokeInfo
  int callState = 0;
  LIR* nullCk;
  LIR** pNullCk = NULL;
  NextCallInsn nextCallInsn;
  oatFlushAllRegs(cUnit);  /* Everything to home location */
  // Explicit register usage
  oatLockCallTemps(cUnit);

  OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
                           *cUnit->dex_file, *cUnit->dex_cache,
                           cUnit->code_item, cUnit->method_idx,
                           cUnit->access_flags);

  uint32_t dexMethodIdx = info->index;
  int vtableIdx;
  uintptr_t directCode;
  uintptr_t directMethod;
  bool skipThis;
  bool fastPath =
    cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, &mUnit, info->type,
                                       vtableIdx, directCode,
                                       directMethod)
    && !SLOW_INVOKE_PATH;
  if (info->type == kInterface) {
    nextCallInsn = fastPath ? nextInterfaceCallInsn
        : nextInterfaceCallInsnWithAccessCheck;
    skipThis = false;
  } else if (info->type == kDirect) {
    if (fastPath) {
      pNullCk = &nullCk;
    }
    nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
    skipThis = false;
  } else if (info->type == kStatic) {
    nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
    skipThis = false;
  } else if (info->type == kSuper) {
    DCHECK(!fastPath);  // Fast path is a direct call.
    nextCallInsn = nextSuperCallInsnSP;
    skipThis = false;
  } else {
    DCHECK_EQ(info->type, kVirtual);
    nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
    skipThis = fastPath;
  }
  if (!info->isRange) {
    callState = genDalvikArgsNoRange(cUnit, info, callState, pNullCk,
                                     nextCallInsn, dexMethodIdx,
                                     vtableIdx, directCode, directMethod,
                                     originalType, skipThis);
  } else {
    callState = genDalvikArgsRange(cUnit, info, callState, pNullCk,
                                   nextCallInsn, dexMethodIdx, vtableIdx,
                                   directCode, directMethod, originalType,
                                   skipThis);
  }
  // Finish up any of the call sequence not interleaved in arg loading
  while (callState >= 0) {
    callState = nextCallInsn(cUnit, info, callState, dexMethodIdx,
                             vtableIdx, directCode, directMethod,
                             originalType);
  }
  if (DISPLAY_MISSING_TARGETS) {
    genShowTarget(cUnit);
  }
#if !defined(TARGET_X86)
  opReg(cUnit, kOpBlx, rINVOKE_TGT);
#else
  if (fastPath && info->type != kInterface) {
    opMem(cUnit, kOpBlx, rARG0, Method::GetCodeOffset().Int32Value());
  } else {
    int trampoline = 0;
    switch (info->type) {
    case kInterface:
      trampoline = fastPath ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
          : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
      break;
    case kDirect:
      trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
      break;
    case kStatic:
      trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
      break;
    case kSuper:
      trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
      break;
    case kVirtual:
      trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
      break;
    default:
      LOG(FATAL) << "Unexpected invoke type";
    }
    opThreadMem(cUnit, kOpBlx, trampoline);
  }
#endif

  oatClobberCalleeSave(cUnit);
  if (info->result.location != kLocInvalid) {
    // We have a following MOVE_RESULT - do it now.
    if (info->result.wide) {
      RegLocation retLoc = oatGetReturnWide(cUnit, info->result.fp);
      storeValueWide(cUnit, info->result, retLoc);
    } else {
      RegLocation retLoc = oatGetReturn(cUnit, info->result.fp);
      storeValue(cUnit, info->result, retLoc);
    }
  }
}

/*
 * Build an array of location records for the incoming arguments.
 * Note: one location record per word of arguments, with dummy
 * high-word loc for wide arguments.  Also pull up any following
 * MOVE_RESULT and incorporate it into the invoke.
 */
CallInfo* newCallInfo(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
                      InvokeType type, bool isRange)
{
  CallInfo* info = (CallInfo*)oatNew(cUnit, sizeof(CallInfo), true,
                                         kAllocMisc);
//FIXME: Disable all fusing as temporary workaround
#if 1
  info->result.location = kLocInvalid;
#else
  MIR* moveResultMIR = oatFindMoveResult(cUnit, bb, mir);
  if (moveResultMIR == NULL) {
    info->result.location = kLocInvalid;
  } else {
    info->result = oatGetRawDest(cUnit, moveResultMIR);
    moveResultMIR->dalvikInsn.opcode = Instruction::NOP;
  }
#endif
  info->numArgWords = mir->ssaRep->numUses;
  info->args = (info->numArgWords == 0) ? NULL : (RegLocation*)
      oatNew(cUnit, sizeof(RegLocation) * info->numArgWords, false, kAllocMisc);
  for (int i = 0; i < info->numArgWords; i++) {
    info->args[i] = oatGetRawSrc(cUnit, mir, i);
  }
  info->optFlags = mir->optimizationFlags;
{'fraction_non_alphanumeric': 0.09748892171344166, 'fraction_numerical': 0.004290637968629106, 'mean_word_length': 2.852072609049038, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4032059', 'n_tokens_mistral': 4628, 'n_tokens_neox': 4461, 'n_words': 1082}