/*******************************************************************************
* Copyright 2014,
* Luis Pina <luis@luispina.me>,
* Michael Hicks <mwh@cs.umd.edu>
*
* This file is part of Rubah.
*
* Rubah is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rubah 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with Rubah. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package rubah.runtime.state.migrator;
import java.lang.reflect.Array;
import java.util.Set;
import rubah.Rubah;
import rubah.runtime.Version;
import rubah.runtime.state.strategy.MigrationStrategy;
public class ArrayMigratorFactory extends MigratorSubFactory {
private Version v1;
protected Set<String> transformedClasses, outdatedClasses;
private ArrayMigrator theMigrator = new ArrayMigrator();
public ArrayMigratorFactory(
Set<String> transformedClasses,
Set<String> outdatedClasses,
Version v1,
MigrationStrategy strategy) {
super(strategy);
this.transformedClasses = transformedClasses;
this.outdatedClasses = outdatedClasses;
this.v1 = v1;
}
@Override
public boolean canMigrate(Class<?> c) {
return c.isArray();
}
@Override
public Migrator buildMigrator() {
return this.theMigrator;
}
protected class ArrayMigrator extends Migrator {
private Object migrateArray(Object pre, Object post) {
if (pre.getClass().getComponentType().isPrimitive()) {
return post;
}
Object[] newArray = (Object[]) post;
Object[] array = (Object[]) pre;
// Unsafe unsafe = Rubah.getUnsafe();
// long base = unsafe.arrayBaseOffset(post.getClass());
// long scale = unsafe.arrayIndexScale(post.getClass());
for (int i = 0; i < newArray.length; i++)
newArray[i] = strategy.migrate(array[i]);
// for (int i = 0; i < newArray.length; i++) {
// long index = base + (i * scale);
// strategy.migrate(array, index, newArray, index);
// }
// long index = base;
// for (int i = 0; i < newArray.length; i++, index += scale) {
// Object obj = unsafe.getObject(array, index);
// Object migrated = strategy.migrate(obj);
// if (pre == post)
// unsafe.compareAndSwapObject(newArray, index, obj, migrated);
// else
// unsafe.putObject(newArray, index, migrated);
// }
return post;
}
@Override
protected Object doMigrate(Object obj) {
Class<?> objClass = obj.getClass();
Class<?> arrayType = objClass.getComponentType();
if (!transformedClasses.contains(arrayType.getName()) && !outdatedClasses.contains(arrayType.getName())) {
return this.migrateArray(obj, obj);
}
String originalName = v1.getOriginalName(arrayType.getName());
if (originalName == null) {
return this.migrateArray(obj, obj);
}
String newUpdatableName = v1.getUpdatableName(originalName);
if (newUpdatableName.equals(arrayType.getName())) {
return this.migrateArray(obj, obj);
}
Object[] array = (Object[]) obj;
Object[] newArray;
try {
Class<?> newClass = Class.forName(newUpdatableName, true, Rubah.getLoader());
// if (outdatedClasses.contains(arrayType.getName())) {
// UnsafeUtils.getInstance().changeClass(obj, Array.newInstance(objClass, 0), Array.newInstance(newClass, 0));
// newArray = array;
// } else {
newArray = (Object[]) Array.newInstance(newClass, Array.getLength(obj));
// }
return this.migrateArray(array, newArray);
} catch (NegativeArraySizeException e) {
throw new Error(e);
} catch (IllegalArgumentException e) {
throw new Error(e);
} catch (ClassNotFoundException e) {
throw new Error(e);
}
}
@Override
public void followReferences(Object post) {
// if (pre.getClass().getComponentType().isPrimitive()) {
// return;
// }
//
// Object[] newArray = (Object[]) post;
// Object[] array = (Object[]) pre;
// for (int i = 0; i < newArray.length; i++) {
// newArray[i] = this.strategy.migrate(array[i]);
// }
}
}
}