blob: 98b336d8aa0813c39b0f80eff54e4c2ca029e7e1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* @author Yuri Kashnikov
*/
#include "PMFAction.h"
#include "Ia32Inst.h"
#include "Ia32IRManager.h"
#include "methodtable.h"
#define PRAGMA_UNINTERRUPTIBLE "org/vmmagic/pragma/Uninterruptible"
namespace Jitrino {
namespace Ia32{
class LightJNIAction: public Action {
public:
LightJNIAction():_myMM("LightJNIAction"){}
void init();
Method_Table* getOFTable() { return lightJNIMethodTable;}
protected:
MemoryManager _myMM;
Method_Table* lightJNIMethodTable;
};
class LightJNISession : public SessionAction {
protected:
void runImpl();
U_32 getSideEffects()const{ return 0; }
const char* getName() { return "light_jni"; }
bool isInOptimizationTable(Method_Table* table, MethodDesc* mmd);
void derefIfObject(CallInst* callInst, Opnd* origRetOpnd);
CompilationContext* cc;
IRManager* lirm;
ControlFlowGraph* fg;
};
ActionFactory<LightJNISession, LightJNIAction> light_jni("light_jni");
void LightJNIAction::init()
{
const char* lightJNIMethods = getStringArg("light_jni_methods", NULL);
lightJNIMethodTable = new (_myMM) Method_Table(_myMM, lightJNIMethods, "LIGHTJNI_METHODS", false);
Method_Table::Decision des = Method_Table::mt_accepted;
// java/lang/Math
lightJNIMethodTable->add_method_record("java/lang/Math","cos","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","asin","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","acos","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","atan","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","atan2","(DD)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","cbrt","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","ceil","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","cos","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","cosh","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","exp","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","expm1","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","floor","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","hypot","(DD)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","IEEEremainder","(DD)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","log","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","log10","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","log1p","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","pow","(DD)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","rint","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","sin","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","sinh","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","sqrt","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","tan","(D)D", des, false);
lightJNIMethodTable->add_method_record("java/lang/Math","tanh","(D)D", des, false);
}
bool LightJNISession::isInOptimizationTable(Method_Table* table, MethodDesc * mmd)
{
const char* className = mmd->getParentType()->getName();
const char* methodName = mmd->getName();
const char* sigName = mmd->getSignatureString();
bool optResult = table->accept_this_method(className,methodName, sigName);
return optResult;
}
void LightJNISession::derefIfObject(CallInst* callInst, Opnd* origRetOpnd)
{
Node* node = callInst->getNode();
Type* origRetType = origRetOpnd->getType();
Opnd* retOpnd = callInst->getOpnd(0);
if (callInst != node->getLastInst()) {
fg->splitNodeAtInstruction(callInst, true, true, NULL);
}
node = callInst->getNode();
Node* nextNode = node->getUnconditionalEdgeTarget();
assert(nextNode!=NULL);
fg->removeEdge(node->getUnconditionalEdge());
Node* zeroObject = fg->createBlockNode();
Node* nonZeroObject = fg->createBlockNode();
//TODO: EM64T!
Inst* cmpZeroInst = lirm->newInst(Mnemonic_CMP, retOpnd, lirm->newImmOpnd(retOpnd->getType(), 0));
Inst* jumpZeroInst = lirm->newBranchInst(Mnemonic_JE, zeroObject, nonZeroObject);
// cmp eax, 0 ; eax = retOpnd
// je @zeroObject
cmpZeroInst->insertAfter(callInst);
jumpZeroInst->insertAfter(cmpZeroInst);
// @zeroObject:
// mov eax,(NullObject)0 ; eax = retOpnd
Inst* movResZero = lirm->newInst(Mnemonic_MOV, origRetOpnd, lirm->newImmOpnd(lirm->getTypeManager().getNullObjectType(), 0));
zeroObject->appendInst(movResZero);
// @nonZeroObject:
// mov eax, [eax] ; eax = retOpnd
Inst* movResRes = lirm->newInst(Mnemonic_MOV, origRetOpnd, lirm->newMemOpndAutoKind(origRetType, retOpnd));
nonZeroObject->appendInst(movResRes);
// link nodes
fg->addEdge(node, nonZeroObject, 0.9);
fg->addEdge(node, zeroObject, 0.1);
fg->addEdge(zeroObject, nextNode);
fg->addEdge(nonZeroObject, nextNode);
}
void LightJNISession::runImpl() {
LightJNIAction* action = (LightJNIAction*)getAction();
Method_Table* tmpT = action->getOFTable();
cc = getCompilationContext();
MemoryManager tmpMM("tmp_lightjni_session");
lirm = cc->getLIRManager();
fg = lirm->getFlowGraph();
NamedType* uninterruptiblePragma = NULL;
TypeManager& tm = lirm->getTypeManager();
// @Uninterruptible pragma
uninterruptiblePragma = lirm->getCompilationInterface().findClassUsingBootstrapClassloader(PRAGMA_UNINTERRUPTIBLE);
StlVector<CallInst*> callsToOptimize(tmpMM);
const Nodes& nodes = fg->getNodesPostOrder();//process checking only reachable nodes.
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
if (node->isBlockNode()) {
for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) {
if (!inst->hasKind(Inst::Kind_CallInst) || !((CallInst*)inst)->isDirect()) {
continue;
}
CallInst* callInst = (CallInst*)inst;
Opnd * targetOpnd=callInst->getOpnd(callInst->getTargetOpndIndex());
assert(targetOpnd->isPlacedIn(OpndKind_Imm));
Opnd::RuntimeInfo * ri=targetOpnd->getRuntimeInfo();
if( !ri || ri->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) {
continue;
};
MethodDesc * md = (MethodDesc*)ri->getValue(0);
if (!md->isNative()) {
continue;
}
if (!isInOptimizationTable(tmpT, md)) {
if (uninterruptiblePragma==NULL || !md->hasAnnotation(uninterruptiblePragma)){
continue;
}
}
callsToOptimize.push_back(callInst);
}
}
}
for (StlVector<CallInst*>::const_iterator it = callsToOptimize.begin(), end = callsToOptimize.end(); it!=end; ++it) {
CallInst* callInst = *it;
Opnd * targetOpnd=callInst->getOpnd(callInst->getTargetOpndIndex());
assert(targetOpnd->isPlacedIn(OpndKind_Imm));
Opnd::RuntimeInfo * ri=targetOpnd->getRuntimeInfo();
assert( ri && ri->getKind() == Opnd::RuntimeInfo::Kind_MethodDirectAddr);
MethodDesc * md = (MethodDesc*)ri->getValue(0);
// printf("optimize %s::%s %s\n", md->getParentType()->getName(), md->getName(), md->getSignatureString());
void* tmpPoint = md->getNativeAddress();
Opnd* tmpZero = lirm->newImmOpnd(lirm->getTypeManager().getIntPtrType(), 0);
U_32 tmpNumArgs = callInst->getOpndCount();
CallInst* newCallInst = NULL;
Opnd* origRetOpnd = callInst->getOpnd(0);
//const char* mmthName = md->getName();
Opnd* newRetOpnd = origRetOpnd;
bool deref = origRetOpnd->getType()->isObject();
if (deref) {
newRetOpnd = lirm->newOpnd(tm.getUnmanagedPtrType(tm.getUInt8Type()));
}
if (md->isInstance()){
Opnd ** tmpOpnds = new (tmpMM) Opnd*[tmpNumArgs-1];
Opnd* newTargetOpnd = lirm->newImmOpnd(tm.getIntPtrType(), ((POINTER_SIZE_INT)tmpPoint));
tmpOpnds[0] = tmpZero;
for (U_32 i = 2; i<tmpNumArgs; i++) {
tmpOpnds[i-1] = callInst->getOpnd(i);
}
newCallInst = lirm->newCallInst(newTargetOpnd, &CallingConvention_STDCALL, tmpNumArgs - 1, tmpOpnds, newRetOpnd);
} else {
assert(md->isStatic());
Opnd ** tmpOpnds = new (tmpMM) Opnd*[tmpNumArgs];
Opnd* newTargetOpnd = lirm->newImmOpnd(tm.getIntPtrType(), ((POINTER_SIZE_INT)tmpPoint));
Opnd* tmpClassName = lirm->newImmOpnd(tm.getIntPtrType(), (POINTER_SIZE_INT)(md->getParentHandle()));
tmpOpnds[0] = tmpZero;
tmpOpnds[1] = tmpClassName;
for (U_32 i = 2; i<tmpNumArgs; i++){
tmpOpnds[i] = callInst->getOpnd(i);
}
newCallInst = lirm->newCallInst(newTargetOpnd, &CallingConvention_STDCALL, tmpNumArgs, tmpOpnds, newRetOpnd);
}
newCallInst->setBCOffset(callInst->getBCOffset());
newCallInst->insertBefore(callInst);
callInst->unlink();
if (deref) {
derefIfObject(newCallInst, origRetOpnd);
}
if (Log::isEnabled()) {
Log::out() << "changing for method" << md->getParentType()->getName() << "_" << md->getName() << "_" << md->getSignatureString() << std::endl;
}
}
}
}} //namespace