sharkInliner.cpp revision 1879
/*
* Copyright 2009 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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/ciField.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciStreams.hpp"
#include "interpreter/bytecodes.hpp"
#include "memory/allocation.hpp"
#include "shark/sharkBlock.hpp"
#include "shark/sharkConstant.hpp"
#include "shark/sharkInliner.hpp"
#include "shark/sharkIntrinsics.hpp"
#include "shark/sharkState.hpp"
#include "shark/sharkValue.hpp"
#include "shark/shark_globals.hpp"
using namespace llvm;
class SharkInlineBlock : public SharkBlock {
public:
_entry_state(new SharkState(this)) {
}
}
private:
private:
SharkState* outer_state() {
return _outer_state;
}
SharkState* entry_state() {
return _entry_state;
}
public:
void emit_IR() {
}
private:
if (result->is_two_word())
}
}
};
class SharkInlinerHelper : public StackObj {
public:
private:
public:
ciBytecodeStream* iter() {
return &_iter;
}
SharkState* entry_state() const {
return _entry_state;
}
return _target;
}
public:
}
int max_locals() const {
return target()->max_locals();
}
int max_stack() const {
}
// Inlinability check
public:
bool is_inlinable();
private:
void initialize_for_check();
bool do_getstatic() {
return do_field_access(true, false);
}
bool do_getfield() {
return do_field_access(true, true);
}
bool do_putfield() {
return do_field_access(false, true);
}
// Local variables for inlinability check
private:
bool* _locals;
public:
bool* local_addr(int index) const {
}
return *local_addr(index);
}
}
// Expression stack for inlinability check
private:
bool* _stack;
bool* _sp;
public:
int stack_depth() const {
}
bool* stack_addr(int slot) const {
}
}
bool pop() {
return *(--_sp);
}
// Methods for two-word locals
public:
void push_pair_local(int index) {
}
void pop_pair_local(int index) {
}
// Code generation
public:
void do_inline() {
}
};
// Quick checks so we can bail out before doing too much
// We can't inline native methods
return false;
// Not much point inlining abstract ones, and in any
// case we'd need a stack frame to throw the exception
if (target->is_abstract())
return false;
// Don't inline anything huge
return false;
// Monitors aren't allowed without a frame to put them in
return false;
// We don't do control flow
return false;
// Don't try to inline constructors, as they must
// eventually call Object.<init> which we can't inline.
// Note that this catches <clinit> too, but why would
// we be compiling that?
if (target->is_initializer())
return false;
// Mustn't inline Object.<init>
// Should be caught by the above, but just in case...
return false;
return true;
}
// Full-on detailed check, for methods that pass the quick checks
// Inlined methods have no stack frame, so we can't do anything
// that would require one. This means no safepoints (and hence
// no loops) and no VM calls. No VM calls means, amongst other
// things, that no exceptions can be created, which means no null
// checks or divide-by-zero checks are allowed. The lack of null
// checks in particular would eliminate practically everything,
// but we can get around that restriction by relying on the zero-
// check eliminator to strip the checks. To do that, we need to
// walk through the method, tracking which values are and are not
// zero-checked.
bool SharkInlinerHelper::is_inlinable() {
bool a, b, c, d;
iter()->reset_to_bci(0);
switch (bc()) {
break;
case Bytecodes::_aconst_null:
push(false);
break;
push(false);
break;
case Bytecodes::_iconst_m1:
push(true);
break;
push(false);
push(false);
break;
push(true);
push(false);
break;
push(false);
break;
push(false);
push(false);
break;
break;
break;
return false;
if (sc->is_two_word())
push(false);
break;
break;
push_pair_local(0);
break;
break;
push_pair_local(1);
break;
break;
push_pair_local(2);
break;
break;
push_pair_local(3);
break;
break;
break;
break;
pop_pair_local(0);
break;
break;
pop_pair_local(1);
break;
break;
pop_pair_local(2);
break;
break;
pop_pair_local(3);
break;
break;
break;
pop();
break;
pop();
pop();
break;
a = pop();
b = pop();
push(a);
push(b);
break;
a = pop();
push(a);
push(a);
break;
a = pop();
b = pop();
push(a);
push(b);
push(a);
break;
a = pop();
b = pop();
c = pop();
push(a);
push(c);
push(b);
push(a);
break;
a = pop();
b = pop();
push(b);
push(a);
push(b);
push(a);
break;
a = pop();
b = pop();
c = pop();
push(b);
push(a);
push(c);
push(b);
push(a);
break;
a = pop();
b = pop();
c = pop();
d = pop();
push(b);
push(a);
push(d);
push(c);
push(b);
push(a);
break;
if (!do_getfield())
return false;
break;
case Bytecodes::_getstatic:
if (!do_getstatic())
return false;
break;
if (!do_putfield())
return false;
break;
pop();
pop();
push(false);
break;
a = pop();
b = pop();
push(a && b);
break;
if (!pop())
return false;
pop();
push(false);
break;
break;
pop();
pop();
pop();
pop();
push(false);
push(false);
break;
a = pop();
b = pop();
push(a && b);
break;
pop();
if (!pop())
return false;
pop();
pop();
push(false);
push(false);
break;
break;
pop();
pop();
pop();
push(false);
push(false);
break;
pop();
pop();
push(false);
break;
break;
pop();
pop();
pop();
pop();
push(false);
push(false);
break;
break;
break;
pop();
pop();
pop();
pop();
push(false);
break;
pop();
pop();
push(false);
break;
pop();
pop();
pop();
pop();
push(false);
break;
push(false);
break;
pop();
push(false);
break;
pop();
push(false);
push(false);
break;
pop();
pop();
push(false);
break;
pop();
pop();
push(false);
push(false);
break;
pop();
push(false);
break;
pop();
push(false);
push(false);
break;
pop();
pop();
push(false);
break;
pop();
pop();
push(false);
push(false);
break;
pop();
push(false);
break;
break;
default:
return false;
}
}
return true;
}
void SharkInlinerHelper::initialize_for_check() {
set_local(i, true);
}
}
// If the holder isn't linked then there isn't a lot we can do
return false;
// Get the field
bool will_link;
if (!will_link)
return false;
// If the field is mismatched then an exception needs throwing
return false;
// Pop the value off the stack if necessary
if (!is_get) {
pop();
pop();
}
// Pop and null-check the receiver if necessary
if (is_field) {
if (!pop())
return false;
}
// Push the result if necessary
if (is_get) {
bool result_pushed = false;
if (field->is_constant()) {
result_pushed = true;
}
}
if (!result_pushed)
push(false);
push(false);
}
return true;
}
return true;
}
if (may_be_inlinable(target)) {
if (inliner.is_inlinable()) {
return true;
}
}
return false;
}