| /******************************************************************************* |
| * Copyright (c) 2019 Sebastian Zarnekow and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Sebastian Zarnekow - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.tests.builder; |
| |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.tests.util.Util; |
| |
| import junit.framework.Test; |
| |
| public class Bug544921Test extends BuilderTests { |
| public Bug544921Test(String name) { |
| super(name); |
| } |
| |
| public static Test suite() { |
| return buildTestSuite(Bug544921Test.class); |
| } |
| |
| public void testCompilerRegression() throws JavaModelException, Exception { |
| IPath projectPath = env.addProject("Bug544921Test", "1.8"); //$NON-NLS-1$ |
| |
| env.addExternalJars(projectPath, Util.getJavaClassLibs()); |
| env.addClass(projectPath, "a", "Test", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package a;\n" + |
| "import java.util.EnumMap;\n" + |
| "enum E {}\n" + |
| "public class Test {\n" + |
| " Object x = new EnumMap<E, String>(E.class) {\n" + |
| " static final long serialVersionUID = 1;\n" + |
| " {\n" + |
| " E.values();\n" + |
| " }\n" + |
| " };\n" + |
| "}" //$NON-NLS-1$ |
| ); |
| fullBuild(); |
| expectingNoProblems(); |
| } |
| |
| public void testBuildLargeFile_01() throws JavaModelException, Exception { |
| IPath projectPath = env.addProject("Bug544921Test", "1.8"); //$NON-NLS-1$ |
| scaffoldProject(projectPath, 1, 10, 64); |
| fullBuild(); |
| expectingNoProblems(); |
| } |
| |
| public void testBuildLargeFile_02() throws JavaModelException, Exception { |
| IPath projectPath = env.addProject("Bug544921Test", "1.8"); //$NON-NLS-1$ |
| scaffoldProject(projectPath, 2, 500, 64); |
| fullBuild(); |
| expectingNoProblems(); |
| } |
| |
| public void testBuildLargeFile_03() throws JavaModelException, Exception { |
| IPath projectPath = env.addProject("Bug544921Test", "1.8"); //$NON-NLS-1$ |
| scaffoldProject(projectPath, 3, 500, 64); |
| fullBuild(); |
| expectingNoProblems(); |
| } |
| |
| private boolean hasEnoughMemory(long required) { |
| long bytes = Runtime.getRuntime().maxMemory(); |
| long megabytes = bytes / 1024 / 1024; |
| return megabytes > required; |
| } |
| |
| public void testBuildLargeFile_04() throws JavaModelException, Exception { |
| if (hasEnoughMemory(2048)) { |
| IPath projectPath = env.addProject("Bug544921Test", "1.8"); //$NON-NLS-1$ |
| scaffoldProject(projectPath, 4, 500, 64); |
| fullBuild(); |
| expectingNoProblems(); |
| } |
| } |
| |
| public void testBuildLargeFile_05() throws JavaModelException, Exception { |
| if (hasEnoughMemory(2048)) { |
| IPath projectPath = env.addProject("Bug544921Test", "1.8"); //$NON-NLS-1$ |
| scaffoldProject(projectPath, 5, 500, 64); |
| fullBuild(); |
| expectingNoProblems(); |
| } |
| } |
| |
| public void testBuildLargeFile_08() throws JavaModelException, Exception { |
| if (hasEnoughMemory(2048)) { |
| IPath projectPath = env.addProject("Bug544921Test", "1.8"); //$NON-NLS-1$ |
| scaffoldProject(projectPath, 8, 500, 64); |
| fullBuild(); |
| expectingNoProblems(); |
| } |
| } |
| |
| public void testBuildLargeFile_10() throws JavaModelException, Exception { |
| if (hasEnoughMemory(2048)) { |
| IPath projectPath = env.addProject("Bug544921Test", "1.8"); //$NON-NLS-1$ |
| scaffoldProject(projectPath, 10, 500, 64); |
| fullBuild(); |
| expectingNoProblems(); |
| } |
| } |
| |
| private void scaffoldProject(IPath projectPath, int maxPeripheral, int maxRegister, int maxFields) throws JavaModelException { |
| env.addExternalJars(projectPath, Util.getJavaClassLibs()); |
| |
| env.addClass(projectPath, "reg", "Field", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package reg;\n" + |
| "\n" + |
| "import reg.Register.AccessType;\n" + |
| "\n" + |
| "public class Field {\n" + |
| " String name;\n" + |
| " String description;\n" + |
| " long bitRange;\n" + |
| " AccessType accessType;\n" + |
| "\n" + |
| " public Field(String name, String description, long bitRange, AccessType accessType) {\n" + |
| " super();\n" + |
| " this.name = name;\n" + |
| " this.description = description;\n" + |
| " this.bitRange = bitRange;\n" + |
| " this.accessType = accessType;\n" + |
| " }\n" + |
| "\n" + |
| " @Override\n" + |
| " public String toString() {\n" + |
| " return \"Field [name=\" + name + \", description=\" + description + \", bitRange=\" + bitRange + \", accessType=\"\n" + |
| " + accessType + \"]\";\n" + |
| " }\n" + |
| " \n" + |
| "}" //$NON-NLS-1$ |
| ); |
| |
| env.addClass(projectPath, "reg", "Peripheral", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package reg;\n" + |
| "\n" + |
| "import java.util.Collection;\n" + |
| "import java.util.Map;\n" + |
| "import java.util.TreeMap;\n" + |
| "\n" + |
| "public class Peripheral {\n" + |
| "\n" + |
| " String name;\n" + |
| " String version;\n" + |
| " String description;\n" + |
| " String groupName;\n" + |
| " long baseAddress;\n" + |
| " long size;\n" + |
| "\n" + |
| " Map<String, Register> registersMap;\n" + |
| "\n" + |
| " public Peripheral(String name, String version, String description, String groupName,\n" + |
| " long baseAddress, long size) {\n" + |
| " super();\n" + |
| " this.name = name;\n" + |
| " this.version = version;\n" + |
| " this.description = description;\n" + |
| " this.groupName = groupName;\n" + |
| " this.baseAddress = baseAddress;\n" + |
| " this.size = size;\n" + |
| " }\n" + |
| "\n" + |
| " private void initRegistersMap(){\n" + |
| " if (registersMap != null) {\n" + |
| " return;\n" + |
| " }\n" + |
| " registersMap = new TreeMap<>();\n" + |
| " for (java.lang.reflect.Field field : this.getClass().getDeclaredFields()) {\n" + |
| " if (!Register.class.isAssignableFrom(field.getType())){\n" + |
| " continue;\n" + |
| " }\n" + |
| " try {\n" + |
| " registersMap.put(field.getName(), (Register) field.get(this));\n" + |
| " } catch (Exception e) {\n" + |
| " e.printStackTrace();\n" + |
| " }\n" + |
| " }\n" + |
| " }\n" + |
| "\n" + |
| " public Register getRegister(String name) {\n" + |
| " return registersMap.get(name);\n" + |
| " }\n" + |
| " public Collection<Register> getRegisters(){\n" + |
| " initRegistersMap();\n" + |
| " return registersMap.values();\n" + |
| " }\n" + |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| env.addClass(projectPath, "reg", "Reg", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package reg;\n" + |
| "\n" + |
| "public final class Reg {\n" + |
| "\n" + |
| " Peripheral_TIMER0 peripheral_Timer0 = new Peripheral_TIMER0();\n" + |
| "\n" + |
| " public static final class Peripheral_TIMER0 extends Peripheral {\n" + |
| "\n" + |
| " public Peripheral_TIMER0() {\n" + |
| " super(\"TIMER0\", \"1.0\", \"desc\", \"groupName\", 0, 32);\n" + |
| " }\n" + |
| "\n" + |
| " public Reg_CR regCR = new Reg_CR();\n" + |
| "\n" + |
| " public static final class Reg_CR extends Register {\n" + |
| " public Reg_CR() {\n" + |
| " super(\"CR\", \"\", 0, 32, AccessType.readWrite, 0xf, 0x0);\n" + |
| " }\n" + |
| "\n" + |
| " // fields of CR\n" + |
| " public Field_EN fieldEn = new Field_EN();\n" + |
| "\n" + |
| " public static final class Field_EN extends Field {\n" + |
| " public Field_EN() {\n" + |
| " super(\"EN\", \"description\", 0, AccessType.readWrite);\n" + |
| " }\n" + |
| " }\n" + |
| "\n" + |
| " public Field_RST fieldRST = new Field_RST();\n" + |
| "\n" + |
| " public static final class Field_RST extends Field {\n" + |
| " public Field_RST() {\n" + |
| " super(\"RST\", \"description\", 1, AccessType.readWrite);\n" + |
| " }\n" + |
| " }\n" + |
| " }\n" + |
| " }\n" + |
| "\n" + |
| " public static void main(String[] args) {\n" + |
| " Reg reg = new Reg();\n" + |
| "\n" + |
| " System.out.println(reg.peripheral_Timer0.regCR.name + \": \" + reg.peripheral_Timer0.regCR.resetValue);\n" + |
| " System.out.println(reg.peripheral_Timer0.regCR.fieldEn.name + \": \" + reg.peripheral_Timer0.regCR.fieldEn.bitRange);\n" + |
| " }\n" + |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| env.addClass(projectPath, "reg", "Register", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package reg;\n" + |
| "\n" + |
| "import java.util.Collection;\n" + |
| "import java.util.Map;\n" + |
| "import java.util.TreeMap;\n" + |
| "\n" + |
| "public class Register {\n" + |
| "\n" + |
| " public enum AccessType {\n" + |
| " readOnly, readWrite;\n" + |
| " }\n" + |
| "\n" + |
| " String name;\n" + |
| " String description;\n" + |
| " long addressOffset;\n" + |
| " long size;\n" + |
| " AccessType accessType;\n" + |
| " long resetValue;\n" + |
| " long resetMask;\n" + |
| " long value;\n" + |
| "\n" + |
| " Map<String, Field> fieldsMap;\n" + |
| "\n" + |
| " public Register(String name, String description, long addressOffset, long size,\n" + |
| " AccessType accessType, long resetValue, long resetMask) {\n" + |
| " this.name = name;\n" + |
| " this.description = description;\n" + |
| " this.addressOffset = addressOffset;\n" + |
| " this.size = size;\n" + |
| " this.accessType = accessType;\n" + |
| " this.resetValue = resetValue;\n" + |
| " this.resetMask = resetMask;\n" + |
| "\n" + |
| " }\n" + |
| "\n" + |
| " private void initFieldsMap(){\n" + |
| " if (fieldsMap != null) {\n" + |
| " return;\n" + |
| " }\n" + |
| " fieldsMap = new TreeMap<>();\n" + |
| " for (java.lang.reflect.Field field : this.getClass().getDeclaredFields()) {\n" + |
| " if (!Field.class.isAssignableFrom(field.getType())){\n" + |
| " continue;\n" + |
| " }\n" + |
| " try {\n" + |
| " fieldsMap.put(field.getName(), (Field) field.get(this));\n" + |
| " } catch (Exception e) {\n" + |
| " e.printStackTrace();\n" + |
| " }\n" + |
| " }\n" + |
| " }\n" + |
| "\n" + |
| " public void setValue(long value){\n" + |
| " this.value = value;\n" + |
| " }\n" + |
| "\n" + |
| " public long getValue(){\n" + |
| " return this.value;\n" + |
| " }\n" + |
| "\n" + |
| " public Collection<Field> getFields(){\n" + |
| " initFieldsMap();\n" + |
| " return fieldsMap.values();\n" + |
| " }\n" + |
| "\n" + |
| " @Override\n" + |
| " public String toString() {\n" + |
| " return \"Register [name=\" + name + \", description=\" + description + \", addressOffset=\" + addressOffset\n" + |
| " + \", size=\" + size + \", accessType=\" + accessType + \", resetValue=\" + resetValue + \", resetMask=\"\n" + |
| " + resetMask + \"]\";\n" + |
| " }\n" + |
| "\n" + |
| "\n" + |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| env.addClass(projectPath, "reg.generate", "DeviceXY", genSource(maxPeripheral, maxRegister, maxFields)); |
| } |
| |
| public static String genSource(int maxPeripheral, int maxRegister, int maxFields) { |
| /* |
| * |
| * The example that took 25 minutes was generated with: int maxPeripheral = 10; |
| * int maxRegister = 500; int maxFields = 64; |
| * |
| * Still performs ok (less than a minute): int maxPeripheral = 2; int |
| * maxRegister = 500; int maxFields = 64; |
| * |
| * With this (8 MB) it gets already slow (few minutes): int maxPeripheral = 3; |
| * int maxRegister = 500; int maxFields = 64; |
| * |
| * This takes 5 minutes (14MB file-size): int maxPeripheral = 5; int maxRegister |
| * = 500; int maxFields = 64; |
| */ |
| |
| StringBuilder source = new StringBuilder(); |
| |
| source.append("package reg.generate;").append(System.lineSeparator()); |
| source.append("public class DeviceXY {").append(System.lineSeparator()); |
| source.append("private static DeviceXY instance;").append(System.lineSeparator()); |
| source.append("private DeviceXY() {}").append(System.lineSeparator()); |
| source.append("public static DeviceXY getInstance() {").append(System.lineSeparator()); |
| source.append(" if (instance == null) { instance = new DeviceXY(); }").append(System.lineSeparator()); |
| source.append(" return instance;").append(System.lineSeparator()); |
| source.append("}").append(System.lineSeparator()); |
| |
| for (int peripheral = 0; peripheral < maxPeripheral; peripheral++) { |
| String peripheralName = "peri_" + peripheral; |
| String peripheralClassName = String.valueOf(Character.toUpperCase(peripheralName.charAt(0))) |
| + peripheralName.substring(1); |
| |
| source.append("public ").append(peripheralClassName).append(" ").append(peripheralName) |
| .append(" = new ").append(peripheralClassName).append("();").append(System.lineSeparator()); |
| source.append("public static final class ").append(peripheralClassName) |
| .append(" extends reg.Peripheral {").append(System.lineSeparator()); |
| // constructor start |
| source.append("public ").append(peripheralClassName).append("() {").append(System.lineSeparator()); |
| source.append(" super(\"").append(peripheralName).append("\",") |
| .append("\"1.0\",\"desc\", \"groupName\", 0, 32);").append(System.lineSeparator()); |
| source.append("}").append(System.lineSeparator()); |
| // constructor end |
| |
| for (int register = 0; register < maxRegister; register++) { |
| String registerName = "reg_" + register; |
| String registerClassName = String.valueOf(Character.toUpperCase(registerName.charAt(0))) |
| + registerName.substring(1); |
| |
| source.append("public ").append(registerClassName).append(" ").append(registerName) |
| .append(" = new ").append(registerClassName).append("();").append(System.lineSeparator()); |
| |
| source.append("/**").append(System.lineSeparator()); |
| source.append("* Register ").append(registerName).append(System.lineSeparator()); |
| source.append("*/").append(System.lineSeparator()); |
| source.append("public static final class ").append(registerClassName) |
| .append(" extends reg.Register {").append(System.lineSeparator()); |
| // constructor start |
| source.append("public ").append(registerClassName).append("() {") |
| .append(System.lineSeparator()); |
| source.append(" super(\"").append(registerName).append("\",") |
| .append("\"desc\", 0, 32, AccessType.readWrite, 0xf, 0x0);").append(System.lineSeparator()); |
| source.append("}").append(System.lineSeparator()); |
| // constructor end |
| |
| source.append("//fields").append(System.lineSeparator()); |
| |
| for (int field = 0; field < maxFields; field++) { |
| String fieldName = "field_" + field; |
| source.append("public ").append("reg.Field").append(" ").append(fieldName) |
| .append(" = new ").append("reg.Field").append("(\"").append(fieldName).append("\",") |
| .append("\"desc\", 0, AccessType.readWrite);").append(System.lineSeparator()); |
| |
| } |
| |
| source.append("}").append(System.lineSeparator()); |
| } |
| source.append("}").append(System.lineSeparator()); |
| } |
| |
| |
| source.append("}").append(System.lineSeparator()); |
| |
| return source.toString(); |
| |
| } |
| } |