/* * Copyright (C) 2012 RoboVM AB * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. */ package org.robovm.compiler; import static org.robovm.compiler.Bro.*; import static org.robovm.compiler.Types.*; import static org.robovm.compiler.llvm.Type.*; import org.robovm.compiler.Bro.MarshalerFlags; import org.robovm.compiler.clazz.Clazz; import org.robovm.compiler.config.Config; import org.robovm.compiler.llvm.Bitcast; import org.robovm.compiler.llvm.Function; import org.robovm.compiler.llvm.Getelementptr; import org.robovm.compiler.llvm.Inttoptr; import org.robovm.compiler.llvm.Load; import org.robovm.compiler.llvm.PointerType; import org.robovm.compiler.llvm.Ret; import org.robovm.compiler.llvm.StructureType; import org.robovm.compiler.llvm.Type; import org.robovm.compiler.llvm.Value; import org.robovm.compiler.llvm.Variable; import org.robovm.compiler.llvm.VariableRef; import soot.SootMethod; import soot.VoidType; /** * @author niklas * */ public class StructMemberMethodCompiler extends BroMethodCompiler { private StructureType structType; public StructMemberMethodCompiler(Config config) { super(config); } @Override public void reset(Clazz clazz) { super.reset(clazz); structType = null; if (isStruct(sootClass)) { structType = getStructType(sootClass); } } @Override protected Function doCompile(ModuleBuilder moduleBuilder, SootMethod method) { if ("_sizeOf".equals(method.getName()) || "sizeOf".equals(method.getName())) { return structSizeOf(moduleBuilder, method); } else { return structMember(moduleBuilder, method); } } private Function structSizeOf(ModuleBuilder moduleBuilder, SootMethod method) { Function fn = createMethodFunction(method); moduleBuilder.addFunction(fn); fn.add(new Ret(sizeof(structType))); return fn; } private Function structMember(ModuleBuilder moduleBuilder, SootMethod method) { Function function = createMethodFunction(method); moduleBuilder.addFunction(function); // Get the value of the handle field in the Struct base class and cast it to a <structType>* Variable handleI64 = function.newVariable(I64); function.add(new Load(handleI64, getFieldPtr(function, function.getParameterRef(1), offsetof(new StructureType(DATA_OBJECT, new StructureType(I64)), 1, 0), I64))); Variable handlePtr = function.newVariable(new PointerType(structType)); function.add(new Inttoptr(handlePtr, handleI64.ref(), handlePtr.getType())); int offset = getStructMemberOffset(method) + 1; // Add 1 since the first type in structType is the superclass type or {}. Type memberType = getStructMemberType(method); Variable memberPtr = function.newVariable(new PointerType(memberType)); if (memberType != structType.getTypeAt(offset)) { // Several @StructMembers of different types have this offset (union) Variable tmp = function.newVariable(new PointerType(structType.getTypeAt(offset))); function.add(new Getelementptr(tmp, handlePtr.ref(), 0, offset)); function.add(new Bitcast(memberPtr, tmp.ref(), memberPtr.getType())); } else { function.add(new Getelementptr(memberPtr, handlePtr.ref(), 0, offset)); } VariableRef env = function.getParameterRef(0); if (method.getParameterCount() == 0) { // Getter Value result = loadValueForGetter(method, function, memberType, memberPtr.ref(), function.getParameterRef(0), true, MarshalerFlags.CALL_TYPE_STRUCT_MEMBER); function.add(new Ret(result)); } else { // Setter Value value = function.getParameterRef(2); // 'env' is parameter 0, 'this' is at 1, the value we're interested in is at index 2 storeValueForSetter(method, function, memberType, memberPtr.ref(), env, value, MarshalerFlags.CALL_TYPE_STRUCT_MEMBER); if (method.getReturnType().equals(VoidType.v())) { function.add(new Ret()); } else { function.add(new Ret(function.getParameterRef(1))); } } return function; } }