/* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #include "precompiled.hpp" #include "ci/ciMethod.hpp" #include "shark/llvmHeaders.hpp" #include "shark/sharkIntrinsics.hpp" #include "shark/sharkState.hpp" #include "shark/sharkValue.hpp" #include "shark/shark_globals.hpp" using namespace llvm; bool SharkIntrinsics::is_intrinsic(ciMethod *target) { switch (target->intrinsic_id()) { case vmIntrinsics::_none: return false; // java.lang.Math case vmIntrinsics::_min: case vmIntrinsics::_max: case vmIntrinsics::_dabs: case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: case vmIntrinsics::_datan2: case vmIntrinsics::_dsqrt: case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: case vmIntrinsics::_dpow: case vmIntrinsics::_dexp: return true; // java.lang.Object case vmIntrinsics::_getClass: return true; // java.lang.System case vmIntrinsics::_currentTimeMillis: return true; // java.lang.Thread case vmIntrinsics::_currentThread: return true; // sun.misc.Unsafe case vmIntrinsics::_compareAndSwapInt: return true; default: if (SharkPerformanceWarnings) { warning( "unhandled intrinsic vmIntrinsic::%s", vmIntrinsics::name_at(target->intrinsic_id())); } } return false; } void SharkIntrinsics::inline_intrinsic(ciMethod *target, SharkState *state) { SharkIntrinsics intrinsic(state, target); intrinsic.do_intrinsic(); } void SharkIntrinsics::do_intrinsic() { switch (target()->intrinsic_id()) { // java.lang.Math case vmIntrinsics::_min: do_Math_minmax(llvm::ICmpInst::ICMP_SLE); break; case vmIntrinsics::_max: do_Math_minmax(llvm::ICmpInst::ICMP_SGE); break; case vmIntrinsics::_dabs: do_Math_1to1(builder()->fabs()); break; case vmIntrinsics::_dsin: do_Math_1to1(builder()->sin()); break; case vmIntrinsics::_dcos: do_Math_1to1(builder()->cos()); break; case vmIntrinsics::_dtan: do_Math_1to1(builder()->tan()); break; case vmIntrinsics::_datan2: do_Math_2to1(builder()->atan2()); break; case vmIntrinsics::_dsqrt: do_Math_1to1(builder()->sqrt()); break; case vmIntrinsics::_dlog: do_Math_1to1(builder()->log()); break; case vmIntrinsics::_dlog10: do_Math_1to1(builder()->log10()); break; case vmIntrinsics::_dpow: do_Math_2to1(builder()->pow()); break; case vmIntrinsics::_dexp: do_Math_1to1(builder()->exp()); break; // java.lang.Object case vmIntrinsics::_getClass: do_Object_getClass(); break; // java.lang.System case vmIntrinsics::_currentTimeMillis: do_System_currentTimeMillis(); break; // java.lang.Thread case vmIntrinsics::_currentThread: do_Thread_currentThread(); break; // sun.misc.Unsafe case vmIntrinsics::_compareAndSwapInt: do_Unsafe_compareAndSwapInt(); break; default: ShouldNotReachHere(); } } void SharkIntrinsics::do_Math_minmax(ICmpInst::Predicate p) { // Pop the arguments SharkValue *sb = state()->pop(); SharkValue *sa = state()->pop(); Value *a = sa->jint_value(); Value *b = sb->jint_value(); // Perform the test BasicBlock *ip = builder()->GetBlockInsertionPoint(); BasicBlock *return_a = builder()->CreateBlock(ip, "return_a"); BasicBlock *return_b = builder()->CreateBlock(ip, "return_b"); BasicBlock *done = builder()->CreateBlock(ip, "done"); builder()->CreateCondBr(builder()->CreateICmp(p, a, b), return_a, return_b); builder()->SetInsertPoint(return_a); builder()->CreateBr(done); builder()->SetInsertPoint(return_b); builder()->CreateBr(done); builder()->SetInsertPoint(done); PHINode *phi = builder()->CreatePHI(a->getType(), "result"); phi->addIncoming(a, return_a); phi->addIncoming(b, return_b); // Push the result state()->push( SharkValue::create_jint( phi, sa->zero_checked() && sb->zero_checked())); } void SharkIntrinsics::do_Math_1to1(Value *function) { SharkValue *empty = state()->pop(); assert(empty == NULL, "should be"); state()->push( SharkValue::create_jdouble( builder()->CreateCall( function, state()->pop()->jdouble_value()))); state()->push(NULL); } void SharkIntrinsics::do_Math_2to1(Value *function) { SharkValue *empty = state()->pop(); assert(empty == NULL, "should be"); Value *y = state()->pop()->jdouble_value(); empty = state()->pop(); assert(empty == NULL, "should be"); Value *x = state()->pop()->jdouble_value(); state()->push( SharkValue::create_jdouble( builder()->CreateCall2(function, x, y))); state()->push(NULL); } void SharkIntrinsics::do_Object_getClass() { Value *klass = builder()->CreateValueOfStructEntry( state()->pop()->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), SharkType::oop_type(), "klass"); state()->push( SharkValue::create_jobject( builder()->CreateValueOfStructEntry( klass, in_ByteSize(Klass::java_mirror_offset_in_bytes()), SharkType::oop_type(), "java_mirror"), true)); } void SharkIntrinsics::do_System_currentTimeMillis() { state()->push( SharkValue::create_jlong( builder()->CreateCall(builder()->current_time_millis()), false)); state()->push(NULL); } void SharkIntrinsics::do_Thread_currentThread() { state()->push( SharkValue::create_jobject( builder()->CreateValueOfStructEntry( thread(), JavaThread::threadObj_offset(), SharkType::oop_type(), "threadObj"), true)); } void SharkIntrinsics::do_Unsafe_compareAndSwapInt() { // Pop the arguments Value *x = state()->pop()->jint_value(); Value *e = state()->pop()->jint_value(); SharkValue *empty = state()->pop(); assert(empty == NULL, "should be"); Value *offset = state()->pop()->jlong_value(); Value *object = state()->pop()->jobject_value(); Value *unsafe = state()->pop()->jobject_value(); // Convert the offset offset = builder()->CreateCall( builder()->unsafe_field_offset_to_byte_offset(), offset); // Locate the field Value *addr = builder()->CreateIntToPtr( builder()->CreateAdd( builder()->CreatePtrToInt(object, SharkType::intptr_type()), builder()->CreateIntCast(offset, SharkType::intptr_type(), true)), PointerType::getUnqual(SharkType::jint_type()), "addr"); // Perform the operation Value *result = builder()->CreateCmpxchgInt(x, addr, e); // Push the result state()->push( SharkValue::create_jint( builder()->CreateIntCast( builder()->CreateICmpEQ(result, e), SharkType::jint_type(), true), false)); }