/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* 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.
*/
package com.sun.max.vm.actor.holder;
import static com.sun.max.vm.MaxineVM.*;
import com.sun.max.annotate.*;
import com.sun.max.collect.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.code.*;
import com.sun.max.vm.compiler.deps.*;
import com.sun.max.vm.compiler.target.*;
import com.sun.max.vm.heap.*;
import com.sun.max.vm.layout.*;
import com.sun.max.vm.reference.*;
import com.sun.max.vm.runtime.*;
/**
*/
public final class DynamicHub extends Hub {
DynamicHub(Size tupleSize,
SpecificLayout specificLayout,
ClassActor classActor,
int[] superClassActorIds,
Iterable<InterfaceActor> allInterfaceActors,
int vTableLength,
TupleReferenceMap referenceMap) {
super(tupleSize,
specificLayout,
classActor,
superClassActorIds,
allInterfaceActors,
vTableLength,
referenceMap);
}
/**
* First valid interface index for an interface method actor.
* Interface index always starts from 1 (index 0 is reserved).
* The interface index is used to index the {@link ClassActor#iToV()} table.
* @return the first valid interface index
*/
@FOLD
public static int firstValidInterfaceIndex() {
return 1;
}
private void initializeMTable(int[] superClassActorIds, Iterable<InterfaceActor> allInterfaceActors, Mapping<MethodActor, VirtualMethodActor> methodLookup, int[] iToV) {
// The first word of the iTable is where all unused mTable entries point:
int iTableIndex = iTableStartIndex;
// We set it to zero so it does not match any class actor's serial (they start at 1):
setWord(iTableIndex, Address.zero());
// Initialize all mTable entries by making them point to the first iTable slot:
for (int mTableIndex = mTableStartIndex; mTableIndex < mTableStartIndex + mTableLength; mTableIndex++) {
setInt(mTableIndex, iTableIndex);
}
iTableIndex++;
// Reserve iTable space for interface method entries:
for (InterfaceActor interfaceActor : allInterfaceActors) {
final int mTableIndex = getMTableIndex(interfaceActor.id);
setInt(mTableIndex, iTableIndex);
assert getWord(iTableIndex).isZero();
setWord(iTableIndex, Address.fromInt(interfaceActor.id));
iTableIndex++;
if (classActor.isReferenceClassActor()) {
for (InterfaceMethodActor interfaceMethodActor : interfaceActor.localInterfaceMethodActors()) {
final VirtualMethodActor virtualMethodActor = methodLookup.get(interfaceMethodActor);
iToV[iTableIndex - iTableStartIndex] = virtualMethodActor.vTableIndex();
iTableIndex++;
}
}
}
for (int id : superClassActorIds) {
if (id >= 0) {
final int mTableIndex = getMTableIndex(id);
setInt(mTableIndex, iTableIndex);
assert getWord(iTableIndex).isZero();
setWord(iTableIndex, Address.fromInt(id));
iTableIndex++;
} else {
// ignore interface ids
}
}
}
DynamicHub expand(int[] superClassActorIds, Iterable<InterfaceActor> allInterfaceActors, Mapping<MethodActor, VirtualMethodActor> methodLookup, int[] iToV, TupleReferenceMap referenceMap) {
final DynamicHub hub = (DynamicHub) expand();
assert hub.mTableLength > 0;
referenceMap.copyIntoHub(hub);
hub.initializeMTable(superClassActorIds, allInterfaceActors, methodLookup, iToV);
return hub;
}
void initializeITable(Iterable<InterfaceActor> allInterfaceActors, Mapping<MethodActor, VirtualMethodActor> methodLookup) {
if (classActor.isReferenceClassActor()) {
for (InterfaceActor interfaceActor : allInterfaceActors) {
final int interfaceIndex = getITableIndex(interfaceActor.id);
for (InterfaceMethodActor interfaceMethodActor : interfaceActor.localInterfaceMethodActors()) {
final VirtualMethodActor virtualMethodActor = methodLookup.get(interfaceMethodActor);
final int iTableIndex = interfaceIndex + interfaceMethodActor.iIndexInInterface();
final int iIndex = iTableIndex - iTableStartIndex;
assert getWord(iTableIndex).isZero();
Address iTableEntry;
if (MaxineVM.isHosted()) {
iTableEntry = checkCompiled(virtualMethodActor);
if (iTableEntry.isZero()) {
iTableEntry = vm().stubs.interfaceTrampoline(iIndex).toAddress();
}
} else {
// IMPORTANT: Don't fill with compiled method entry points.
// See Hub.initializeVTable for a detailed explanation.
iTableEntry = vm().stubs.interfaceTrampoline(iIndex).toAddress();
}
setWord(iTableIndex, iTableEntry);
}
}
}
}
private void checkITableEntry(int iTableIndex) {
final Address vTableEntry = getWord(iTableIndex).asAddress();
TargetMethod tm = Code.codePointerToTargetMethod(vTableEntry.asPointer());
if (tm == null || Stubs.isJumpToStaticTrampoline(tm)) {
Log.println(classActor.toString() + "(hub = " + Reference.fromJava(this).toOrigin().to0xHexString() +
") has interface table entry #" + (iTableIndex - iTableStartIndex) + "(" + iTableIndex + ") points to method patched with static trampoline");
FatalError.unexpected("corrupted itable");
}
}
/**
* Make a given itable entry point to the trampoline again.
* @param index a word index relative to the hub's origin into the itable
*/
public void resetITableEntry(int index) {
setWord(index, vm().stubs.interfaceTrampoline(index - iTableStartIndex).toAddress());
}
/**
* Replace itable trampolines with compiled method entry points for compiled methods.
* This is done once, upon adding the class actor to the class hierarchy.
* @see DependenciesManager
*/
public void refreshITable() {
final int lastITableIndex = iTableStartIndex + iTableLength;
final int [] iToV = classActor.iToV();
for (int iTableIndex = iTableStartIndex; iTableIndex < lastITableIndex; iTableIndex++) {
final int iIndex = iTableIndex - iTableStartIndex;
final int vTableIndex = iToV[iIndex];
if (vTableIndex >= vTableStartIndex()) {
final VirtualMethodActor virtualMethodActor = classActor.getVirtualMethodActorByVTableIndex(vTableIndex);
final Address vTableEntry = checkCompiled(virtualMethodActor);
if (vTableEntry.isNotZero()) {
setWord(iTableIndex, vTableEntry);
}
if (MaxineVM.isDebug()) {
checkITableEntry(iTableIndex);
}
}
}
}
@Override
public FieldActor findFieldActor(int offset) {
return classActor.findInstanceFieldActor(offset);
}
}