diff options
author | Stefan Xenos | 2017-03-27 21:47:10 +0000 |
---|---|---|
committer | Stefan Xenos | 2017-03-31 22:41:23 +0000 |
commit | 2c42a0df455cbd5ba153f806bdbdfa9b2c3c7fd2 (patch) | |
tree | f47e3c44909cad1ccd2d70b55a127fc07ef67730 | |
parent | c0a948b58471feb266ae2a43da866986b3f3b1b4 (diff) | |
download | eclipse.jdt.core-2c42a0df455cbd5ba153f806bdbdfa9b2c3c7fd2.tar.gz eclipse.jdt.core-2c42a0df455cbd5ba153f806bdbdfa9b2c3c7fd2.tar.xz eclipse.jdt.core-2c42a0df455cbd5ba153f806bdbdfa9b2c3c7fd2.zip |
Bug 512741 - Indexer is performing too many writes during indexingI20170331-2000
Implement a new FieldList class and use it to replace several
FieldOneToMany fields.
Change-Id: I44e4d415453d77d034be2da7cff2c2318e0a878f
47 files changed, 1279 insertions, 682 deletions
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldListTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldListTest.java new file mode 100644 index 0000000000..ad718cea77 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldListTest.java @@ -0,0 +1,320 @@ +/******************************************************************************* + * Copyright (c) 2017 Google, Inc and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Stefan Xenos (Google) - Initial implementation + *******************************************************************************/ +package org.eclipse.jdt.core.tests.nd; + +import java.util.List; + +import org.eclipse.jdt.core.tests.nd.util.BaseTestCase; +import org.eclipse.jdt.internal.core.nd.IDestructable; +import org.eclipse.jdt.internal.core.nd.Nd; +import org.eclipse.jdt.internal.core.nd.NdNode; +import org.eclipse.jdt.internal.core.nd.NdNodeTypeRegistry; +import org.eclipse.jdt.internal.core.nd.NdStruct; +import org.eclipse.jdt.internal.core.nd.db.IString; +import org.eclipse.jdt.internal.core.nd.field.FieldByte; +import org.eclipse.jdt.internal.core.nd.field.FieldList; +import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; +import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; +import org.eclipse.jdt.internal.core.nd.field.FieldString; +import org.eclipse.jdt.internal.core.nd.field.StructDef; + +import junit.framework.Test; + +public class FieldListTest extends BaseTestCase { + static int nodeDeletions; + static int structDeletions; + + public static class ElementNode extends NdNode { + public static final FieldString NAME; + public static final FieldOneToMany<TestStruct> RELATED_STRUCTS; + public static final FieldManyToOne<TestStruct> PARENT_NODE; + public static final FieldList<TestStruct> LIST_CONTENTS; + + @SuppressWarnings("hiding") + public static final StructDef<ElementNode> type; + + static { + type = StructDef.create(ElementNode.class, NdNode.type); + + NAME = type.addString(); + RELATED_STRUCTS = FieldOneToMany.create(type, TestStruct.RELATED_NODE); + PARENT_NODE = FieldManyToOne.createOwner(type, TestStruct.CHILD_NODES); + LIST_CONTENTS = FieldList.create(type, TestStruct.type, 3); + type.done(); + } + + public ElementNode(Nd nd, long record) { + super(nd, record); + } + + public ElementNode(Nd nd, String name, TestStruct parent) { + super(nd); + + NAME.put(nd, this.address, name); + PARENT_NODE.put(nd, this.address, parent); + } + + public TestStruct createChild(String name) { + TestStruct result = LIST_CONTENTS.append(this.nd, this.address); + result.setName(name); + return result; + } + + public List<TestStruct> getChildren() { + return LIST_CONTENTS.asList(getNd(), getAddress()); + } + + @Override + public void destruct() { + super.destruct(); + + FieldListTest.nodeDeletions++; + } + + public IString getName() { + return NAME.get(getNd(), getAddress()); + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + printStringTo(builder); + return builder.toString(); + } + + public void printStringTo(StringBuilder builder) { + builder.append(getName().getString()); + if (!RELATED_STRUCTS.isEmpty(getNd(), getAddress())) { + builder.append("->["); + boolean isFirst = true; + for (TestStruct struct : getRelatedStructs()) { + if (!isFirst) { + builder.append(", "); + } + isFirst = false; + builder.append(struct.getName()); + } + builder.append("]"); + } + + List<TestStruct> children = getChildren(); + if (!children.isEmpty()) { + builder.append("("); + boolean isFirst = true; + for (TestStruct struct : children) { + if (!isFirst) { + builder.append(", "); + } + isFirst = false; + struct.printStringTo(builder); + } + builder.append(")"); + } + } + + public List<TestStruct> getRelatedStructs() { + return RELATED_STRUCTS.asList(getNd(), getAddress()); + } + } + + public static class TestStruct extends NdStruct implements IDestructable { + public static final FieldString NAME; + public static final FieldOneToMany<ElementNode> CHILD_NODES; + public static final FieldManyToOne<ElementNode> RELATED_NODE; + public static final FieldByte EXTRA_BYTE; + + @SuppressWarnings("hiding") + public static final StructDef<TestStruct> type; + + static { + type = StructDef.create(TestStruct.class, NdStruct.type); + + NAME = type.addString(); + CHILD_NODES = FieldOneToMany.create(type, ElementNode.PARENT_NODE); + RELATED_NODE = FieldManyToOne.create(type, ElementNode.RELATED_STRUCTS); + EXTRA_BYTE = type.addByte(); + type.done(); + } + + public TestStruct(Nd nd, long record) { + super(nd, record); + } + + public void printStringTo(StringBuilder builder) { + builder.append(getName().getString()); + ElementNode related = RELATED_NODE.get(getNd(), getAddress()); + if (related != null) { + builder.append("->["); + builder.append(related.getName().getString()); + builder.append("]"); + } + + List<ElementNode> children = getChildren(); + if (!children.isEmpty()) { + builder.append("("); + boolean isFirst = true; + for (ElementNode struct : children) { + if (!isFirst) { + builder.append(", "); + } + isFirst = false; + struct.printStringTo(builder); + } + builder.append(")"); + } + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + printStringTo(builder); + return builder.toString(); + } + + public IString getName() { + return NAME.get(getNd(), getAddress()); + } + + public void setRelatedNode(ElementNode elementNode) { + RELATED_NODE.put(getNd(), getAddress(), elementNode); + } + + public ElementNode getRelatedNode() { + return RELATED_NODE.get(getNd(), getAddress()); + } + + public void setName(String name) { + NAME.put(getNd(), getAddress(), name); + } + + public List<ElementNode> getChildren() { + return CHILD_NODES.asList(getNd(), getAddress()); + } + + public ElementNode createChild(String name) { + return new ElementNode(getNd(), name, this); + } + + @Override + public void destruct() { + FieldListTest.structDeletions++; + } + } + + TestStruct referencer; + TestStruct owner; + private Nd nd; + private ElementNode root; + private boolean nodeDeleted; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + structDeletions = 0; + nodeDeletions = 0; + NdNodeTypeRegistry<NdNode> registry = new NdNodeTypeRegistry<>(); + registry.register(0, ElementNode.type.getFactory()); + this.nd = DatabaseTestUtil.createEmptyNd(getName(), registry); + this.nd.getDB().setExclusiveLock(); + this.root = new ElementNode(this.nd, "root", null); + } + + protected void freeAllMemory() throws Exception { + if (this.nodeDeleted) { + return; + } + this.nodeDeleted = true; + this.root.delete(); + this.nd.processDeletions(); + long freed = this.nd.getDB().getBytesFreed(); + long allocated = this.nd.getDB().getBytesAllocated(); + assertEquals("We should have freed all the bytes we allocated and no more", allocated, freed); + } + + @Override + protected void tearDown() throws Exception { + freeAllMemory(); + super.tearDown(); + } + + public void testEmptyList() throws Exception { + assertTrue("isEmpty() should return true if no children inserted", + this.root.getChildren().isEmpty()); + freeAllMemory(); + assertEquals("No structs should have been disposed during this test", 0, structDeletions); + assertEquals("One node should have been disposed during this test", 1, nodeDeletions); + } + + public void testOneChild() throws Exception { + TestStruct testStruct = this.root.createChild("child"); + assertEquals("root should be initialized properly", "child", testStruct.getName().getString()); + assertEquals("root should have correct contents", "root(child)", this.root.toString()); + freeAllMemory(); + assertEquals("No structs should have been disposed during this test", 1, structDeletions); + assertEquals("One node should have been disposed during this test", 1, nodeDeletions); + } + + public void testElementsInBlock() throws Exception { + this.root.createChild("child1"); + this.root.createChild("child2"); + assertEquals("root should have correct contents", "root(child1, child2)", this.root.toString()); + this.root.createChild("child3"); + assertEquals("root should have correct contents", "root(child1, child2, child3)", + this.root.toString()); + this.root.createChild("child4"); + assertEquals("root should have correct contents", "root(child1, child2, child3, child4)", + this.root.toString()); + this.root.createChild("child5"); + assertEquals("root should have correct contents", "root(child1, child2, child3, child4, child5)", + this.root.toString()); + freeAllMemory(); + assertEquals("No structs should have been disposed during this test", 5, structDeletions); + assertEquals("One node should have been disposed during this test", 1, nodeDeletions); + } + + public void testDestructorInPartiallyFilledBlock() throws Exception { + this.root.createChild("child1"); + this.root.createChild("child2"); + this.root.createChild("child3"); + this.root.createChild("child4"); + freeAllMemory(); + assertEquals("No structs should have been disposed during this test", 4, structDeletions); + assertEquals("One node should have been disposed during this test", 1, nodeDeletions); + } + + public void testListOwningNode() throws Exception { + TestStruct child1 = this.root.createChild("child1"); + child1.createChild("grandchild1"); + + assertEquals("root should have correct contents", "root(child1(grandchild1))", this.root.toString()); + + freeAllMemory(); + assertEquals("No structs should have been disposed during this test", 1, structDeletions); + assertEquals("One node should have been disposed during this test", 2, nodeDeletions); + } + + public void testListWithManyToOneNode() throws Exception { + TestStruct child1 = this.root.createChild("child1"); + ElementNode relatedNode = new ElementNode(this.nd, "relatedNode", null); + child1.setRelatedNode(relatedNode); + + assertEquals("Related node should have been set", relatedNode, child1.getRelatedNode()); + assertEquals("root should have correct contents", "root(child1->[relatedNode])", this.root.toString()); + + this.root.delete(); + this.nodeDeleted = true; + + assertEquals("Related node should be cleared", null, child1.getRelatedNode()); + } + + public static Test suite() { + return BaseTestCase.suite(FieldListTest.class); + } +} diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/RunIndexTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/RunIndexTests.java index f358ea0bb9..9bb4a9fb12 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/RunIndexTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/RunIndexTests.java @@ -30,6 +30,7 @@ public static Class[] getAllTestClasses() { ChunkWriterTests.class, DatabaseTest.class, FieldBackPointerTest.class, + FieldListTest.class, FieldOneToOneTest.class, IndexerTest.class, InheritenceTests.class, diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdNode.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdNode.java deleted file mode 100644 index ef24eb6fbe..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdNode.java +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015, 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd; - -import org.eclipse.jdt.internal.core.nd.db.IndexException; - -/** - * Interface for all nodes that can be visited by a {@link INdVisitor}. - * @noextend This interface is not intended to be extended by clients. - * @noimplement This interface is not intended to be implemented by clients. - */ -public interface INdNode { - - /** - * Visits the children of this node. - */ - public void accept(INdVisitor visitor) throws IndexException; -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdStruct.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdStruct.java new file mode 100644 index 0000000000..909fd562ce --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdStruct.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2017 Google, Inc and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Stefan Xenos (Google) - Initial implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.nd; + +/** + * Implementations of this interface wrap content in the database as a java object. + * All such objects have an address and a pointer to the database. + */ +public interface INdStruct { + /** + * Returns the database address at which the struct begins. + */ + public long getAddress(); + + /** + * Returns the database backing this struct. + */ + public Nd getNd(); + + /** + * Given a nullable {@link INdStruct}, this returns the address of the struct + * or 0 if the object was null. + */ + static long addressOf(INdStruct nullable) { + if (nullable == null) { + return 0; + } + return nullable.getAddress(); + } +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdVisitor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdVisitor.java deleted file mode 100644 index 034e233021..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdVisitor.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015, 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd; - -import org.eclipse.core.runtime.CoreException; - -public interface INdVisitor { - - /** - * Walk the nodes in a {@link Nd}. Return true to visit the children of - * this node, or false to skip to the next sibling of this node. - * Throw CoreException to stop the visit. - * - * @param node being visited - * @return whether to visit children - */ - public boolean visit(INdNode node) throws CoreException; - - /** - * All children have been visited, about to go back to the parent. - * - * @param node that has just completed visitation - * @throws CoreException - */ - public void leave(INdNode node) throws CoreException; - -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java index 42d9b5a491..7994234d9a 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java @@ -72,6 +72,9 @@ public final class IndexExceptionBuilder { */ public IndexException build(String description) { IndexException toThrow = new IndexException(description); + if (this.db.getLog().enabled()) { + toThrow.setTime(this.db.getLog().getWriteCount()); + } attachTo(toThrow); return toThrow; } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java index 9b20c451c0..a8acff19f7 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java @@ -650,7 +650,7 @@ public final class Nd { /** * Returns the type ID for the given class */ - public short getNodeType(Class<? extends NdNode> toQuery) { + public short getNodeType(Class<?> toQuery) { return this.fNodeTypeRegistry.getTypeForClass(toQuery); } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNode.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNode.java index d550751e3c..ddf646e6ed 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNode.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNode.java @@ -16,29 +16,22 @@ import org.eclipse.jdt.internal.core.nd.field.FieldShort; import org.eclipse.jdt.internal.core.nd.field.StructDef; /** - * This is a basic node in the network database. + * This is a basic polymorphic node in the network database. Pointers to NdNode or any of their + * subclasses will be resolved to the correct subclass of NdNode such that the correct version of an + * overloaded method will be invoked. */ -public abstract class NdNode implements IDestructable { +public abstract class NdNode extends NdStruct implements IDestructable { public static final FieldShort NODE_TYPE; + @SuppressWarnings("hiding") public static final StructDef<NdNode> type; static { - type = StructDef.create(NdNode.class); + type = StructDef.create(NdNode.class, NdStruct.type); NODE_TYPE = type.addShort(); type.done(); } - public final long address; - private Nd nd; - - public static long addressOf(NdNode nullable) { - if (nullable == null) { - return 0; - } - return nullable.address; - } - /** * Load a node from the specified address in the given database. Return null if a node cannot * be loaded. @@ -63,7 +56,7 @@ public abstract class NdNode implements IDestructable { } @SuppressWarnings("unchecked") - public static <T extends NdNode> T load(Nd nd, long address, StructDef<T> targetType) { + public static <T extends INdStruct> T load(Nd nd, long address, StructDef<T> typeToLoad) { if (address == 0) { return null; } @@ -78,7 +71,7 @@ public abstract class NdNode implements IDestructable { throw e; } - Class<T> clazz = targetType.getStructClass(); + Class<T> clazz = typeToLoad.getStructClass(); if (!clazz.isAssignableFrom(result.getClass())) { throw nd.describeProblem() .addProblemAddress(NODE_TYPE, address) @@ -86,7 +79,7 @@ public abstract class NdNode implements IDestructable { clazz + " but found " + result.getClass()); //$NON-NLS-1$ } - return (T)result; + return (T) result; } /** @@ -97,13 +90,12 @@ public abstract class NdNode implements IDestructable { } protected NdNode(Nd nd, long address) { - this.nd = nd; - this.address = address; + super(nd, address); } protected NdNode(Nd nd) { + super(nd, 0); Database db = nd.getDB(); - this.nd = nd; short nodeType = nd.getNodeType(getClass()); ITypeFactory<? extends NdNode> factory1 = nd.getTypeFactory(nodeType); @@ -113,14 +105,6 @@ public abstract class NdNode implements IDestructable { NODE_TYPE.put(nd, this.address, nodeType); } - protected Database getDB() { - return this.nd.getDB(); - } - - public final Nd getNd() { - return this.nd; - } - /** * Return a value to uniquely identify the node within the factory that is responsible for loading * instances of this node from the {@link Nd}. @@ -155,10 +139,6 @@ public abstract class NdNode implements IDestructable { return (int) (this.address >> Database.BLOCK_SIZE_DELTA_BITS); } - public void accept(INdVisitor visitor) { - // No children here. - } - /** * Return an value to globally identify the given node within the given linkage. This value * can be used for comparison with other {@link NdNode}s. diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNodeTypeRegistry.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNodeTypeRegistry.java index d15b7790b8..12c2fd72e8 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNodeTypeRegistry.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNodeTypeRegistry.java @@ -75,7 +75,11 @@ public class NdNodeTypeRegistry<R> { return typeFactory.create(nd, address); } - public short getTypeForClass(Class<? extends R> toQuery) { + public boolean isRegisteredClass(Class<?> toQuery) { + return this.registeredClasses.containsKey(toQuery); + } + + public short getTypeForClass(Class<?> toQuery) { Short classId = this.registeredClasses.get(toQuery); if (classId == null) { diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdStruct.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdStruct.java new file mode 100644 index 0000000000..5bdec2ab78 --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdStruct.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2017 Google, Inc and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Stefan Xenos (Google) - Initial implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.nd; + +import org.eclipse.jdt.internal.core.nd.db.Database; +import org.eclipse.jdt.internal.core.nd.field.StructDef; + +/** + * Base class for standard implementations of {@link INdStruct}. Holds the address of the struct + * and the pointer to the database. + */ +public class NdStruct implements INdStruct { + public long address; + protected final Nd nd; + + public static final StructDef<NdStruct> type; + + static { + type = StructDef.createAbstract(NdStruct.class); + type.done(); + } + + protected NdStruct(Nd nd, long address) { + this.nd = nd; + this.address = address; + } + + @Override + public long getAddress() { + return this.address; + } + + @Override + public Nd getNd() { + return this.nd; + } + + protected final Database getDB() { + return this.nd.getDB(); + } +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java index ac3ede103e..67117526e7 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java @@ -16,6 +16,7 @@ import org.eclipse.jdt.internal.core.nd.field.FieldInt; import org.eclipse.jdt.internal.core.nd.field.FieldPointer; import org.eclipse.jdt.internal.core.nd.field.FieldShort; import org.eclipse.jdt.internal.core.nd.field.StructDef; +import org.eclipse.jdt.internal.core.nd.util.MathUtils; /** * Implements a growable array of pointers that supports constant-time insertions and removals. Items are inserted at @@ -585,7 +586,7 @@ public final class RawGrowableArray { // For sizes larger than the max block size, we need to use a metablock. In this case, the allocated size // will be a multiple of the max block size. - return roundUpToMultipleOf(GrowableBlockHeader.MAX_GROWABLE_SIZE, growableRegionSize); + return MathUtils.roundUpToNearestMultiple(growableRegionSize, GrowableBlockHeader.MAX_GROWABLE_SIZE); } return nextGrowableSize; @@ -618,15 +619,6 @@ public final class RawGrowableArray { } /** - * Rounds a value up to the nearest multiple of another value - */ - private static int roundUpToMultipleOf(int unit, int valueToRound) { - int numberOfMetablocks = (valueToRound + unit - 1) / unit; - - return numberOfMetablocks * unit; - } - - /** * Returns the record size for a RawGrowableSize with the given number of inline records */ public int getRecordSize() { diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java index aa195b8b93..f971fb8db4 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java @@ -23,6 +23,7 @@ public class IndexException extends RuntimeException { private IStatus status; private List<RelatedAddress> relatedAddresses = new ArrayList<>(); + private long time = -1; public IndexException(IStatus status) { this.status = status; @@ -32,6 +33,16 @@ public class IndexException extends RuntimeException { this(new Status(IStatus.ERROR, "org.eclipse.jdt.core", message)); //$NON-NLS-1$ } + /** + * Sets the time that the exception occurred at (in terms of the write number + * from the modification log) + * + * @param writeNumber + */ + public void setTime(long writeNumber) { + this.time = writeNumber; + } + @Override public synchronized Throwable getCause() { return this.status.getException(); @@ -59,6 +70,11 @@ public class IndexException extends RuntimeException { @Override public String getMessage() { StringBuilder result = new StringBuilder(); + if (this.time != -1) { + result.append("(time "); //$NON-NLS-1$ + result.append(this.time); + result.append(") "); //$NON-NLS-1$ + } result.append(this.status.getMessage()); if (!this.relatedAddresses.isEmpty()) { diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java index 1229343ecb..b81b37fa83 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java @@ -311,7 +311,7 @@ public class ModificationLog { } } - private boolean enabled() { + public boolean enabled() { return this.buffer0 != null; } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java index efd6e8eb0f..f596d883de 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java @@ -12,6 +12,7 @@ package org.eclipse.jdt.internal.core.nd.field; import org.eclipse.jdt.internal.core.nd.ITypeFactory; import org.eclipse.jdt.internal.core.nd.Nd; +import org.eclipse.jdt.internal.core.nd.db.Database; /** * Used to represent a single field of an object stored in the database. Objects @@ -54,4 +55,31 @@ public final class Field<T> extends BaseField implements IDestructableField { public int getRecordSize() { return this.factory.getRecordSize(); } + + @Override + public int getAlignment() { + // This sort of field is almost always used for embedding NdStructs within + // other data types. Since most NdStructs allow incoming record pointers, they need to + // be properly aligned. If we ever want to use this sort of field for other data types + // that don't require alignment, we may want to replace this with something smarter + // that can figure out the correct alignment based on the requirements of the actual + // data type. + return Database.BLOCK_SIZE_DELTA; + } + + /** + * Creates a new {@link Field} in the given struct with the given type. + * + * @param struct the struct that will contain the newly-created field (must not have had + * {@link StructDef#done()} called on it yet). + * @param fieldType the data type for the contents of the newly created field + * @return the newly-constructed field + */ + public static <T> Field<T> create(StructDef<?> struct, StructDef<T> fieldType) { + Field<T> result = new Field<>(fieldType.getFactory(), struct.getStructName(), struct.getNumFields()); + struct.add(result); + struct.addDestructableField(result); + fieldType.addDependency(struct); + return result; + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java new file mode 100644 index 0000000000..b2c5ec70a6 --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java @@ -0,0 +1,327 @@ +/******************************************************************************* + * Copyright (c) 2017 Google, Inc and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Stefan Xenos (Google) - Initial implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.nd.field; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.internal.core.nd.ITypeFactory; +import org.eclipse.jdt.internal.core.nd.Nd; +import org.eclipse.jdt.internal.core.nd.db.Database; +import org.eclipse.jdt.internal.core.nd.db.ModificationLog; +import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag; +import org.eclipse.jdt.internal.core.nd.util.MathUtils; + +/** + * Stores a singly-linked list of blocks, each of which contains a variable number of embedded elements. + * Each block contains a header containing the size of the block and pointer to the next block, followed + * by the embedded elements themselves. + */ +public class FieldList<T> extends BaseField implements IDestructableField { + /** + * Pointer to the first block. + */ + public final static FieldPointer FIRST_BLOCK; + /** + * Pointer to the block where insertions are currently happening. This is only null if there are no allocated + * blocks. If there are any blocks containing elements, this points to the last block with a nonzero number of + * elements. + */ + public final static FieldPointer LAST_BLOCK_WITH_ELEMENTS; + + @SuppressWarnings("rawtypes") + private static final StructDef<FieldList> type; + private static final int LIST_HEADER_BYTES; + private static final long MAX_BYTES_IN_A_CHUNK = Database.getBytesThatFitInChunks(1); + + private final StructDef<T> elementType; + private final int elementsPerBlock; + private final StructDef<?> ownerType; + private final Tag allocateTag; + private final Tag appendTag; + private final Tag destructTag; + + static { + type = StructDef.createAbstract(FieldList.class); + FIRST_BLOCK = type.addPointer(); + LAST_BLOCK_WITH_ELEMENTS = type.addPointer(); + + type.done(); + LIST_HEADER_BYTES = MathUtils.roundUpToNearestMultipleOfPowerOfTwo(type.size(), Database.BLOCK_SIZE_DELTA); + } + + private static class BlockHeader { + // This points to the next block if there is one, or null if not. + public final static FieldPointer NEXT_BLOCK; + public final static FieldShort BLOCK_SIZE; + public final static FieldShort ELEMENTS_IN_USE; + public static final int BLOCK_HEADER_BYTES; + + @SuppressWarnings("hiding") + private static final StructDef<BlockHeader> type; + + static { + type = StructDef.createAbstract(BlockHeader.class); + + NEXT_BLOCK = type.addPointer(); + BLOCK_SIZE = type.addShort(); + ELEMENTS_IN_USE = type.addShort(); + type.done(); + + BLOCK_HEADER_BYTES = MathUtils.roundUpToNearestMultipleOfPowerOfTwo(type.size(), Database.BLOCK_SIZE_DELTA); + } + } + + private FieldList(StructDef<?> ownerType, StructDef<T> elementType, int elementsPerBlock) { + this.elementType = elementType; + this.elementsPerBlock = elementsPerBlock; + this.ownerType = ownerType; + int fieldNumber = ownerType.getNumFields(); + setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$ + + " in struct " + ownerType.getStructName());//$NON-NLS-1$ + this.allocateTag = ModificationLog.createTag("Allocating elements for " + getFieldName()); //$NON-NLS-1$ + this.appendTag = ModificationLog.createTag("Appending to " + getFieldName()); //$NON-NLS-1$ + this.destructTag = ModificationLog.createTag("Deallocating " + getFieldName()); //$NON-NLS-1$ + } + + /** + * Creates a new {@link FieldList} in the given struct which contains elements of the given type. The resulting list + * will grow by 1 element each time it overflows. + * + * @param ownerStruct + * the struct to which the new list field will be added. Must not have had {@link StructDef#done()} + * invoked on it yet. + * @param elementType + * the type of elements that will be contained in the struct. + * @return a newly-constructed list field in the given struct. + */ + public static <T> FieldList<T> create(StructDef<?> ownerStruct, StructDef<T> elementType) { + return create(ownerStruct, elementType, 1); + } + + /** + * Creates a new {@link FieldList} in the given struct which contains elements of the given type. The resulting list + * will grow by the given number of elements each time it overflows. + * + * @param ownerStruct + * the struct to which the new list field will be added. Must not have had {@link StructDef#done()} + * invoked on it yet. + * @param elementType + * the type of elements that will be contained in the struct. + * @param elementsPerBlock + * the number of elements that will be allocated each time the list overflows. + * @return a newly-constructed list field in the given struct. + */ + public static <T> FieldList<T> create(StructDef<?> ownerStruct, StructDef<T> elementType, int elementsPerBlock) { + FieldList<T> result = new FieldList<>(ownerStruct, elementType, elementsPerBlock); + ownerStruct.add(result); + ownerStruct.addDestructableField(result); + return result; + } + + private int getElementSize() { + int recordSize = this.elementType.getFactory().getRecordSize(); + return MathUtils.roundUpToNearestMultipleOfPowerOfTwo(recordSize, Database.BLOCK_SIZE_DELTA); + } + + @Override + public int getRecordSize() { + return LIST_HEADER_BYTES; + } + + /** + * Returns the contents of the receiver as a {@link List}. + * + * @param nd the database to be queried. + * @param address the address of the parent struct + */ + public List<T> asList(Nd nd, long address) { + long headerStartAddress = address + this.offset; + long firstBlockAddress = FIRST_BLOCK.get(nd, headerStartAddress); + + List<T> result = new ArrayList<>(); + + long nextBlockAddress = firstBlockAddress; + while (nextBlockAddress != 0) { + long currentBlockAddress = nextBlockAddress; + nextBlockAddress = BlockHeader.NEXT_BLOCK.get(nd, currentBlockAddress); + int elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, currentBlockAddress); + long firstElementInBlockAddress = currentBlockAddress + BlockHeader.BLOCK_HEADER_BYTES; + + readElements(result, nd, firstElementInBlockAddress, elementsInBlock); + } + + return result; + } + + private void readElements(List<T> result, Nd nd, long nextElementAddress, int count) { + ITypeFactory<T> factory = this.elementType.getFactory(); + + int size = getElementSize(); + for (; count > 0; count--) { + result.add(factory.create(nd, nextElementAddress)); + nextElementAddress += size; + } + } + + public T append(Nd nd, long address) { + Database db = nd.getDB(); + db.getLog().start(this.appendTag); + try { + long headerStartAddress = address + this.offset; + long nextBlockAddress = LAST_BLOCK_WITH_ELEMENTS.get(nd, headerStartAddress); + + // Ensure that there's at least one block + long insertionBlockAddress = nextBlockAddress; + if (nextBlockAddress == 0) { + long newBlockAddress = allocateNewBlock(nd, this.elementsPerBlock); + LAST_BLOCK_WITH_ELEMENTS.put(nd, headerStartAddress, newBlockAddress); + FIRST_BLOCK.put(nd, headerStartAddress, newBlockAddress); + insertionBlockAddress = newBlockAddress; + } + + // Check if there's any free space in this block + int elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, insertionBlockAddress); + int blockSize = BlockHeader.BLOCK_SIZE.get(nd, insertionBlockAddress); + + if (elementsInBlock >= blockSize) { + long nextBlock = BlockHeader.NEXT_BLOCK.get(nd, insertionBlockAddress); + if (nextBlock == 0) { + nextBlock = allocateNewBlock(nd, this.elementsPerBlock); + BlockHeader.NEXT_BLOCK.put(nd, insertionBlockAddress, nextBlock); + } + LAST_BLOCK_WITH_ELEMENTS.put(nd, headerStartAddress, nextBlock); + insertionBlockAddress = nextBlock; + elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, insertionBlockAddress); + } + + BlockHeader.ELEMENTS_IN_USE.put(nd, insertionBlockAddress, (short) (elementsInBlock + 1)); + int elementSize = getElementSize(); + + long resultAddress = insertionBlockAddress + BlockHeader.BLOCK_HEADER_BYTES + elementsInBlock * elementSize; + assert ((resultAddress - Database.BLOCK_HEADER_SIZE) & (Database.BLOCK_SIZE_DELTA - 1)) == 0; + return this.elementType.getFactory().create(nd, resultAddress); + } finally { + db.getLog().end(this.appendTag); + } + } + + /** + * Ensures that the receiver will have space for the given number of elements without additional + * allocation. Callers should invoke this prior to a sequence of {@link FieldList#append(Nd, long)} + * calls if they know in advance how many elements will be appended. Will create the minimum number + * of extra blocks needed to the given number of additional elements. + */ + public void allocate(Nd nd, long address, int numElements) { + Database db = nd.getDB(); + db.getLog().start(this.allocateTag); + try { + if (numElements == 0) { + // Not an error, but there's nothing to do if the caller didn't actually ask for anything to be allocated. + return; + } + long headerStartAddress = address + this.offset; + long nextBlockAddress = LAST_BLOCK_WITH_ELEMENTS.get(nd, headerStartAddress); + + int maxBlockSizeThatFitsInAChunk = (int) ((MAX_BYTES_IN_A_CHUNK - BlockHeader.BLOCK_HEADER_BYTES) + / getElementSize()); + + // Ensure that there's at least one block + if (nextBlockAddress == 0) { + int firstAllocation = Math.min(numElements, maxBlockSizeThatFitsInAChunk); + nextBlockAddress = allocateNewBlock(nd, firstAllocation); + LAST_BLOCK_WITH_ELEMENTS.put(nd, headerStartAddress, nextBlockAddress); + FIRST_BLOCK.put(nd, headerStartAddress, nextBlockAddress); + } + + // Check if there's any free space in this block + int remainingToAllocate = numElements; + while (true) { + long currentBlockAddress = nextBlockAddress; + nextBlockAddress = BlockHeader.NEXT_BLOCK.get(nd, currentBlockAddress); + int elementsInUse = BlockHeader.ELEMENTS_IN_USE.get(nd, currentBlockAddress); + int blockSize = BlockHeader.BLOCK_SIZE.get(nd, currentBlockAddress); + + remainingToAllocate -= (blockSize - elementsInUse); + if (remainingToAllocate <= 0) { + break; + } + + if (nextBlockAddress == 0) { + nextBlockAddress = allocateNewBlock(nd, Math.min(maxBlockSizeThatFitsInAChunk, numElements)); + BlockHeader.NEXT_BLOCK.put(nd, currentBlockAddress, nextBlockAddress); + } + } + } finally { + db.getLog().end(this.allocateTag); + } + } + + private long allocateNewBlock(Nd nd, int blockSize) { + short poolId = getMemoryPoolId(nd); + int elementSize = getElementSize(); + long bytesNeeded = BlockHeader.BLOCK_HEADER_BYTES + blockSize * elementSize; + // If we're close enough to filling the chunk that we wouldn't be able to fit any more elements anyway, allocate + // the entire chunk. Although it wastes a small amount of space, it ensures that the blocks can be more easily + // reused rather than being fragmented. It also allows freed blocks to be merged via the large block allocator. + if (MAX_BYTES_IN_A_CHUNK - bytesNeeded < elementSize) { + bytesNeeded = MAX_BYTES_IN_A_CHUNK; + } + long result = nd.getDB().malloc(bytesNeeded, poolId); + BlockHeader.BLOCK_SIZE.put(nd, result, (short) blockSize); + return result; + } + + private short getMemoryPoolId(Nd nd) { + short poolId = Database.POOL_LINKED_LIST; + if (this.ownerType != null) { + Class<?> structClass = this.ownerType.getStructClass(); + if (nd.getTypeRegistry().isRegisteredClass(structClass)) { + poolId = (short) (Database.POOL_FIRST_NODE_TYPE + nd.getNodeType(structClass)); + } + } + return poolId; + } + + @Override + public void destruct(Nd nd, long address) { + Database db = nd.getDB(); + db.getLog().start(this.destructTag); + try { + short poolId = getMemoryPoolId(nd); + long headerStartAddress = address + this.offset; + long firstBlockAddress = FIRST_BLOCK.get(nd, headerStartAddress); + + long nextBlockAddress = firstBlockAddress; + while (nextBlockAddress != 0) { + long currentBlockAddress = nextBlockAddress; + nextBlockAddress = BlockHeader.NEXT_BLOCK.get(nd, currentBlockAddress); + int elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, currentBlockAddress); + destructElements(nd, currentBlockAddress + BlockHeader.BLOCK_HEADER_BYTES, elementsInBlock); + db.free(currentBlockAddress, poolId); + } + + db.clearRange(headerStartAddress, getRecordSize()); + } finally { + db.getLog().end(this.destructTag); + } + } + + private void destructElements(Nd nd, long nextElementAddress, int count) { + ITypeFactory<T> factory = this.elementType.getFactory(); + + int size = getElementSize(); + while (--count >= 0) { + factory.destruct(nd, nextElementAddress); + nextElementAddress += size; + } + } +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java index 41216cfb87..4d3d4b1acb 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.jdt.internal.core.nd.field; +import org.eclipse.jdt.internal.core.nd.INdStruct; import org.eclipse.jdt.internal.core.nd.ITypeFactory; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.NdNode; @@ -23,12 +24,12 @@ import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag; * {@link FieldManyToOne} points to an object, the inverse pointer is automatically inserted into the matching back * pointer list. */ -public class FieldManyToOne<T extends NdNode> extends BaseField implements IDestructableField, IRefCountedField { +public class FieldManyToOne<T extends INdStruct> extends BaseField implements IDestructableField, IRefCountedField { public final static FieldPointer TARGET; public final static FieldInt BACKPOINTER_INDEX; StructDef<T> targetType; - final StructDef<? extends NdNode> localType; + final StructDef<? extends INdStruct> localType; FieldOneToMany<?> backPointer; @SuppressWarnings("rawtypes") private final static StructDef<FieldManyToOne> type; @@ -38,6 +39,7 @@ public class FieldManyToOne<T extends NdNode> extends BaseField implements IDest public final boolean pointsToOwner; private final Tag putTag; private final Tag destructTag; + private boolean permitsNull = true; static { type = StructDef.createAbstract(FieldManyToOne.class); @@ -47,7 +49,7 @@ public class FieldManyToOne<T extends NdNode> extends BaseField implements IDest } @SuppressWarnings({ "unchecked", "rawtypes" }) - private FieldManyToOne(StructDef<? extends NdNode> localType, FieldOneToMany<?> backPointer, boolean pointsToOwner) { + private FieldManyToOne(StructDef<? extends INdStruct> localType, FieldOneToMany<?> backPointer, boolean pointsToOwner) { this.localType = localType; this.pointsToOwner = pointsToOwner; @@ -68,7 +70,14 @@ public class FieldManyToOne<T extends NdNode> extends BaseField implements IDest this.destructTag = ModificationLog.createTag("Destructing " + getFieldName()); //$NON-NLS-1$ } - public static <T extends NdNode, B extends NdNode> FieldManyToOne<T> create(StructDef<B> builder, + public static <T extends INdStruct, B extends INdStruct> FieldManyToOne<T> createNonNull(StructDef<B> builder, + FieldOneToMany<B> forwardPointer) { + FieldManyToOne<T> result = create(builder, forwardPointer); + result.permitsNull = false; + return result; + } + + public static <T extends INdStruct, B extends INdStruct> FieldManyToOne<T> create(StructDef<B> builder, FieldOneToMany<B> forwardPointer) { FieldManyToOne<T> result = new FieldManyToOne<T>(builder, forwardPointer, false); builder.add(result); @@ -84,8 +93,17 @@ public class FieldManyToOne<T extends NdNode> extends BaseField implements IDest * @param forwardPointer the field which holds the pointer in the other direction * @return a newly constructed field */ - public static <T extends NdNode, B extends NdNode> FieldManyToOne<T> createOwner(StructDef<B> builder, + public static <T extends INdStruct, B extends INdStruct> FieldManyToOne<T> createOwner(StructDef<B> builder, FieldOneToMany<B> forwardPointer) { + // Although it would work to have a non-NdNode owned in this manner, we currently have no legitimate use-cases + // for this to occur. If this happens it is almost certainly an accidental copy-paste error where someone + // intended to call create but called this method instead. If we ever discover a legitimate use-case for it, + // this could be removed and things would probably still work. + if (!NdNode.class.isAssignableFrom(builder.getStructClass())) { + throw new IllegalArgumentException(FieldManyToOne.class.getSimpleName() + " can't be the owner of " //$NON-NLS-1$ + + builder.getStructClass().getSimpleName() + " because the latter isn't a subclass of " //$NON-NLS-1$ + + NdNode.class.getSimpleName()); + } FieldManyToOne<T> result = new FieldManyToOne<T>(builder, forwardPointer, true); builder.add(result); @@ -94,12 +112,29 @@ public class FieldManyToOne<T extends NdNode> extends BaseField implements IDest return result; } + /** + * Sets whether or not this field permits nulls to be assigned. + * + * @param permitted true iff the field permits nulls + * @return this + */ + public FieldManyToOne<T> permitNull(boolean permitted) { + this.permitsNull = permitted; + return this; + } + public T get(Nd nd, long address) { return NdNode.load(nd, getAddress(nd, address), this.targetType); } public long getAddress(Nd nd, long address) { - return nd.getDB().getRecPtr(address + this.offset); + long result = nd.getDB().getRecPtr(address + this.offset); + if (!this.permitsNull && result == 0) { + throw nd.describeProblem() + .addProblemAddress(this, address) + .build("Database contained a null in a non-null field"); //$NON-NLS-1$ + } + return result; } /** @@ -109,8 +144,10 @@ public class FieldManyToOne<T extends NdNode> extends BaseField implements IDest public void put(Nd nd, long address, T value) { if (value != null) { put(nd, address, value.getAddress()); - } else { + } else if (this.permitsNull) { put(nd, address, 0); + } else { + throw new IllegalArgumentException("Attempted to write a null into a non-null field"); //$NON-NLS-1$ } } @@ -153,13 +190,14 @@ public class FieldManyToOne<T extends NdNode> extends BaseField implements IDest this.backPointer.remove(nd, oldTargetAddress, oldIndex); - short targetTypeId = NdNode.NODE_TYPE.get(nd, oldTargetAddress); + if (this.targetType.isNdNode()) { + short targetTypeId = NdNode.NODE_TYPE.get(nd, oldTargetAddress); + ITypeFactory<? extends NdNode> typeFactory = nd.getTypeFactory(targetTypeId); - ITypeFactory<T> typeFactory = nd.getTypeFactory(targetTypeId); - - if (typeFactory.getDeletionSemantics() == StructDef.DeletionSemantics.REFCOUNTED - && typeFactory.isReadyForDeletion(nd, oldTargetAddress)) { - nd.scheduleDeletion(oldTargetAddress); + if (typeFactory.getDeletionSemantics() == StructDef.DeletionSemantics.REFCOUNTED + && typeFactory.isReadyForDeletion(nd, oldTargetAddress)) { + nd.scheduleDeletion(oldTargetAddress); + } } } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java index 19c085db46..5b3952fabd 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java @@ -13,6 +13,7 @@ package org.eclipse.jdt.internal.core.nd.field; import java.util.ArrayList; import java.util.List; +import org.eclipse.jdt.internal.core.nd.INdStruct; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.NdNode; import org.eclipse.jdt.internal.core.nd.RawGrowableArray; @@ -21,9 +22,9 @@ import org.eclipse.jdt.internal.core.nd.RawGrowableArray; * Holds the 1 side of a 1..n relationship between two objects. FieldNodePointer and FieldBackPointer fields always go * together in pairs. */ -public class FieldOneToMany<T extends NdNode> extends BaseField implements IDestructableField, IRefCountedField { +public class FieldOneToMany<T extends INdStruct> extends BaseField implements IDestructableField, IRefCountedField { public StructDef<T> targetType; - public final StructDef<? extends NdNode> localType; + public final StructDef<? extends INdStruct> localType; private final RawGrowableArray backPointerArray; FieldManyToOne<?> forwardPointer; @@ -32,7 +33,7 @@ public class FieldOneToMany<T extends NdNode> extends BaseField implements IDest } @SuppressWarnings({ "rawtypes", "unchecked" }) - private FieldOneToMany(StructDef<? extends NdNode> localType, FieldManyToOne<? extends NdNode> forwardPointer, + private FieldOneToMany(StructDef<? extends INdStruct> localType, FieldManyToOne<? extends INdStruct> forwardPointer, int inlineElements) { this.localType = localType; @@ -42,8 +43,8 @@ public class FieldOneToMany<T extends NdNode> extends BaseField implements IDest "Attempted to construct a FieldBackPointer referring to a forward pointer that is already in use" //$NON-NLS-1$ + " by another field"); //$NON-NLS-1$ } - forwardPointer.targetType = (StructDef)localType; - this.targetType = (StructDef)forwardPointer.localType; + forwardPointer.targetType = (StructDef) localType; + this.targetType = (StructDef) forwardPointer.localType; forwardPointer.backPointer = this; } this.forwardPointer = forwardPointer; @@ -64,7 +65,7 @@ public class FieldOneToMany<T extends NdNode> extends BaseField implements IDest * offer a performance improvement. For relationships that will normally be empty, this should be 0. * @return the newly constructed backpointer field */ - public static <T extends NdNode, B extends NdNode> FieldOneToMany<T> create(StructDef<B> builder, + public static <T extends INdStruct, B extends INdStruct> FieldOneToMany<T> create(StructDef<B> builder, FieldManyToOne<B> forwardPointer, int inlineElementCount) { FieldOneToMany<T> result = new FieldOneToMany<T>(builder, forwardPointer, inlineElementCount); builder.add(result); @@ -73,11 +74,11 @@ public class FieldOneToMany<T extends NdNode> extends BaseField implements IDest return result; } - public static <T extends NdNode, B extends NdNode> FieldOneToMany<T> create(StructDef<B> builder, + public static <T extends INdStruct, B extends INdStruct> FieldOneToMany<T> create(StructDef<B> builder, FieldManyToOne<B> forwardPointer) { return create(builder, forwardPointer, 0); } - + public void accept(Nd nd, long address, Visitor<T> visitor) { int size = size(nd, address); diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java index ca7fa19009..47d1d714dd 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.jdt.internal.core.nd.field; +import org.eclipse.jdt.internal.core.nd.INdStruct; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.NdNode; import org.eclipse.jdt.internal.core.nd.db.ModificationLog; @@ -19,7 +20,7 @@ import org.eclipse.jdt.internal.core.nd.db.Database; /** * Represents a 1-to-0..1 relationship in a Nd database. */ -public class FieldOneToOne<T extends NdNode> extends BaseField implements IDestructableField, IRefCountedField { +public class FieldOneToOne<T extends INdStruct> extends BaseField implements IDestructableField, IRefCountedField { public final StructDef<T> nodeType; FieldOneToOne<?> backPointer; private boolean pointsToOwner; @@ -49,7 +50,7 @@ public class FieldOneToOne<T extends NdNode> extends BaseField implements IDestr this.destructTag = ModificationLog.createTag("Destructing " + getFieldName()); //$NON-NLS-1$ } - public static <T extends NdNode, B extends NdNode> FieldOneToOne<T> create(StructDef<B> builder, + public static <T extends INdStruct, B extends INdStruct> FieldOneToOne<T> create(StructDef<B> builder, StructDef<T> nodeType, FieldOneToOne<B> forwardPointer) { FieldOneToOne<T> result = new FieldOneToOne<T>(nodeType, forwardPointer, false); @@ -58,7 +59,7 @@ public class FieldOneToOne<T extends NdNode> extends BaseField implements IDestr return result; } - public static <T extends NdNode, B extends NdNode> FieldOneToOne<T> createOwner(StructDef<B> builder, + public static <T extends INdStruct, B extends INdStruct> FieldOneToOne<T> createOwner(StructDef<B> builder, StructDef<T> nodeType, FieldOneToOne<B> forwardPointer) { FieldOneToOne<T> result = new FieldOneToOne<T>(nodeType, forwardPointer, true); @@ -84,8 +85,8 @@ public class FieldOneToOne<T extends NdNode> extends BaseField implements IDestr nd.scheduleDeletion(address); } } else { - db.putRecPtr(address + this.offset, target.address); - db.putRecPtr(target.address + this.backPointer.offset, address); + db.putRecPtr(address + this.offset, target.getAddress()); + db.putRecPtr(target.getAddress() + this.backPointer.offset, address); } } finally { db.getLog().end(this.putTag); diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IField.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IField.java index 6796a46c1e..78a793e4e5 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IField.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IField.java @@ -14,7 +14,15 @@ import org.eclipse.jdt.internal.core.nd.db.Database; /** * Represents a single field of a struct in the {@link Database}. Holds metadata for that field - * and permits laziy initialization of the field offset. + * and permits laziy initialization of the field offset. Fields are normally instantiated as static + * variables. Collectively, they describe the database schema but they are not associated with any + * particular instance of data in the database. + * <p> + * Fields are temporarily mutable. On construction, a number of attributes (such as offset) are + * computed in a second pass or are initialized as other fields are constructed. Generally such + * attributes can't be computed in the constructor since they depend on knowledge of other fields + * that must be instantiated first. However, once {@link StructDef#done()} has been called on the + * last {@link StructDef}, fields are immutable and should not ever be modified again. */ public interface IField { /** @@ -22,12 +30,20 @@ public interface IField { * after the sizes of all preceeding fields are known. */ void setOffset(int offset); + /** * Returns the size of the field, in bytes. */ int getRecordSize(); /** + * Returns the required byte alignment for the field. + */ + default int getAlignment() { + return 1; + } + + /** * Returns the name of the field. This is mainly used for error messages, debug output, and diagnostic tools. * Meant to be programmer-readable but not user-readable. */ diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java index b5fddf3426..9fe5571b50 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java @@ -15,14 +15,18 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.eclipse.jdt.internal.core.nd.IDestructable; import org.eclipse.jdt.internal.core.nd.ITypeFactory; import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.db.ModificationLog; +import org.eclipse.jdt.internal.core.nd.NdNode; import org.eclipse.jdt.internal.core.nd.db.Database; +import org.eclipse.jdt.internal.core.nd.db.ModificationLog; import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag; +import org.eclipse.jdt.internal.core.nd.util.MathUtils; /** * Defines a data structure that will appear in the database. @@ -46,10 +50,11 @@ import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag; public final class StructDef<T> { Class<T> clazz; private StructDef<? super T> superClass; + private Set<StructDef<?>> dependencies = new HashSet<>(); private List<IField> fields = new ArrayList<>(); private boolean doneCalled; private boolean offsetsComputed; - private List<StructDef<? extends T>> subClasses = new ArrayList<>(); + private List<StructDef<? extends T>> dependents = new ArrayList<>(); private int size; List<IDestructableField> destructableFields = new ArrayList<>(); boolean refCounted; @@ -60,6 +65,7 @@ public final class StructDef<T> { protected boolean hasUserDestructor; private DeletionSemantics deletionSemantics; final Tag destructTag; + private boolean isNdNode; public static enum DeletionSemantics { EXPLICIT, OWNED, REFCOUNTED @@ -76,9 +82,10 @@ public final class StructDef<T> { private StructDef(Class<T> clazz, StructDef<? super T> superClass, boolean isAbstract) { this.destructTag = ModificationLog.createTag("Destructing struct " + clazz.getSimpleName()); //$NON-NLS-1$ this.clazz = clazz; + this.isNdNode = NdNode.class.isAssignableFrom(clazz); this.superClass = superClass; if (this.superClass != null) { - this.superClass.subClasses.add(this); + addDependency(this.superClass); } this.isAbstract = isAbstract; final String fullyQualifiedClassName = clazz.getName(); @@ -162,6 +169,32 @@ public final class StructDef<T> { }; } + public void addDependency(StructDef<?> newDependency) { + if (newDependency.hasIndirectDependent(new HashSet<>(), this)) { + throw new IllegalArgumentException("Circular dependency detected. Struct " //$NON-NLS-1$ + + getStructName() + " and struct " + newDependency.getStructName() //$NON-NLS-1$ + + " both depend on one another"); //$NON-NLS-1$ + } + if (this.dependencies.add(newDependency)) { + this.superClass.dependents.add(this); + } + } + + private boolean hasIndirectDependent(Set<StructDef<?>> visited, StructDef<?> structDef) { + for (StructDef<?> next : this.dependents) { + if (!visited.add(next)) { + continue; + } + if (next.equals(structDef)) { + return true; + } + if (next.hasIndirectDependent(visited, structDef)) { + return true; + } + } + return false; + } + public Class<T> getStructClass() { return this.clazz; } @@ -217,6 +250,15 @@ public final class StructDef<T> { return this.deletionSemantics; } + private boolean areAllDependenciesResolved() { + for (StructDef<?> next : this.dependencies) { + if (!next.areOffsetsComputed()) { + return false; + } + } + return true; + } + /** * Call this once all the fields have been added to the struct definition and it is * ready to use. @@ -227,7 +269,7 @@ public final class StructDef<T> { } this.doneCalled = true; - if (this.superClass == null || this.superClass.areOffsetsComputed()) { + if (areAllDependenciesResolved()) { computeOffsets(); } } @@ -286,12 +328,13 @@ public final class StructDef<T> { /** * Invoked on all StructDef after both {@link #done()} has been called on the struct and - * {@link #computeOffsets()} has been called on their base class. + * {@link #computeOffsets()} has been called on every dependency of this struct. */ private void computeOffsets() { int offset = this.superClass == null ? 0 : this.superClass.size(); for (IField next : this.fields) { + offset = MathUtils.roundUpToNearestMultiple(offset, next.getAlignment()); next.setOffset(offset); offset += next.getRecordSize(); } @@ -320,7 +363,7 @@ public final class StructDef<T> { this.offsetsComputed = true; - for (StructDef<? extends T> next : this.subClasses) { + for (StructDef<? extends T> next : this.dependents) { if (next.doneCalled) { next.computeOffsets(); } @@ -409,6 +452,10 @@ public final class StructDef<T> { } } + public boolean isNdNode() { + return this.isNdNode; + } + public int getNumFields() { return this.fields.size(); } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java index 38cacb1d98..2ba44b183c 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java @@ -36,11 +36,6 @@ import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.java.JavaIndex; import org.eclipse.jdt.internal.core.nd.java.JavaNames; import org.eclipse.jdt.internal.core.nd.java.NdAnnotation; -import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInConstant; -import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInMethod; -import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInMethodParameter; -import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInType; -import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInVariable; import org.eclipse.jdt.internal.core.nd.java.NdAnnotationValuePair; import org.eclipse.jdt.internal.core.nd.java.NdBinding; import org.eclipse.jdt.internal.core.nd.java.NdComplexTypeSignature; @@ -50,17 +45,12 @@ import org.eclipse.jdt.internal.core.nd.java.NdConstantArray; import org.eclipse.jdt.internal.core.nd.java.NdConstantClass; import org.eclipse.jdt.internal.core.nd.java.NdConstantEnum; import org.eclipse.jdt.internal.core.nd.java.NdMethod; -import org.eclipse.jdt.internal.core.nd.java.NdMethodException; import org.eclipse.jdt.internal.core.nd.java.NdMethodId; import org.eclipse.jdt.internal.core.nd.java.NdMethodParameter; import org.eclipse.jdt.internal.core.nd.java.NdResourceFile; import org.eclipse.jdt.internal.core.nd.java.NdType; import org.eclipse.jdt.internal.core.nd.java.NdTypeAnnotation; -import org.eclipse.jdt.internal.core.nd.java.NdTypeAnnotationInMethod; -import org.eclipse.jdt.internal.core.nd.java.NdTypeAnnotationInType; -import org.eclipse.jdt.internal.core.nd.java.NdTypeAnnotationInVariable; import org.eclipse.jdt.internal.core.nd.java.NdTypeArgument; -import org.eclipse.jdt.internal.core.nd.java.NdTypeBound; import org.eclipse.jdt.internal.core.nd.java.NdTypeId; import org.eclipse.jdt.internal.core.nd.java.NdTypeInterface; import org.eclipse.jdt.internal.core.nd.java.NdTypeParameter; @@ -77,7 +67,7 @@ public final class ClassFileToIndexConverter { private static final char[] COMMA = new char[]{','}; private static final char[][] EMPTY_CHAR_ARRAY_ARRAY = new char[0][]; private static final boolean ENABLE_LOGGING = false; - private static final char[] EMPTY_CHAR_ARRAY = new char[0]; + static final char[] EMPTY_CHAR_ARRAY = new char[0]; private static final char[] PATH_SEPARATOR = new char[]{'/'}; private static final char[] ARRAY_FIELD_DESCRIPTOR_PREFIX = new char[] { '[' }; private NdResourceFile resource; @@ -135,8 +125,9 @@ public final class ClassFileToIndexConverter { IBinaryTypeAnnotation[] typeAnnotations = binaryType.getTypeAnnotations(); if (typeAnnotations != null) { + type.allocateTypeAnnotations(typeAnnotations.length); for (IBinaryTypeAnnotation typeAnnotation : typeAnnotations) { - NdTypeAnnotationInType annotation = new NdTypeAnnotationInType(getNd(), type); + NdTypeAnnotation annotation = type.createTypeAnnotation(); initTypeAnnotation(annotation, typeAnnotation); } @@ -194,6 +185,7 @@ public final class ClassFileToIndexConverter { IBinaryField[] fields = binaryType.getFields(); if (fields != null) { + type.allocateVariables(fields.length); for (IBinaryField nextField : fields) { addField(type, nextField); } @@ -251,8 +243,9 @@ public final class ClassFileToIndexConverter { private void attachAnnotations(NdMethod method, IBinaryAnnotation[] annotations) { if (annotations != null) { + method.allocateAnnotations(annotations.length); for (IBinaryAnnotation next : annotations) { - NdAnnotationInMethod annotation = new NdAnnotationInMethod(getNd(), method); + NdAnnotation annotation = method.createAnnotation(); initAnnotation(annotation, next); } } @@ -260,8 +253,9 @@ public final class ClassFileToIndexConverter { private void attachAnnotations(NdType type, IBinaryAnnotation[] annotations) { if (annotations != null) { + type.allocateAnnotations(annotations.length); for (IBinaryAnnotation next : annotations) { - NdAnnotationInType annotation = new NdAnnotationInType(getNd(), type); + NdAnnotation annotation = type.createAnnotation(); initAnnotation(annotation, next); } } @@ -269,8 +263,9 @@ public final class ClassFileToIndexConverter { private void attachAnnotations(NdVariable variable, IBinaryAnnotation[] annotations) { if (annotations != null) { + variable.allocateAnnotations(annotations.length); for (IBinaryAnnotation next : annotations) { - NdAnnotationInVariable annotation = new NdAnnotationInVariable(getNd(), variable); + NdAnnotation annotation = variable.createAnnotation(); initAnnotation(annotation, next); } } @@ -278,8 +273,9 @@ public final class ClassFileToIndexConverter { private void attachAnnotations(NdMethodParameter variable, IBinaryAnnotation[] annotations) { if (annotations != null) { + variable.allocateAnnotations(annotations.length); for (IBinaryAnnotation next : annotations) { - NdAnnotationInMethodParameter annotation = new NdAnnotationInMethodParameter(getNd(), variable); + NdAnnotation annotation = variable.createAnnotation(); initAnnotation(annotation, next); } } @@ -306,8 +302,9 @@ public final class ClassFileToIndexConverter { IBinaryTypeAnnotation[] typeAnnotations = next.getTypeAnnotations(); if (typeAnnotations != null) { + method.allocateTypeAnnotations(typeAnnotations.length); for (IBinaryTypeAnnotation typeAnnotation : typeAnnotations) { - NdTypeAnnotationInMethod annotation = new NdTypeAnnotationInMethod(getNd(), method); + NdTypeAnnotation annotation = method.createTypeAnnotation(); initTypeAnnotation(annotation, typeAnnotation); } @@ -349,6 +346,10 @@ public final class ClassFileToIndexConverter { int parameterNameIdx = 0; int annotatedParametersCount = next.getAnnotatedParametersCount(); + int namedParameterCount = parameterNames == null ? 0 : parameterNames.length; + int estimatedParameterCount = Math.max(Math.max(Math.max(numArgumentsInGenericSignature, namedParameterCount), + annotatedParametersCount), parameterFieldDescriptors.size()); + method.allocateParameters(estimatedParameterCount); short descriptorParameterIdx = 0; char[] binaryTypeName = binaryType.getName(); @@ -367,8 +368,8 @@ public final class ClassFileToIndexConverter { if (isCompilerDefined && !compilerDefinedParametersAreIncludedInSignature) { nextFieldSignature = new SignatureWrapper(nextFieldDescriptor); } - NdMethodParameter parameter = new NdMethodParameter(method, - createTypeSignature(nextFieldSignature, nextFieldDescriptor)); + NdMethodParameter parameter = method.createNewParameter(); + parameter.setType(createTypeSignature(nextFieldSignature, nextFieldDescriptor)); parameter.setCompilerDefined(isCompilerDefined); @@ -378,7 +379,7 @@ public final class ClassFileToIndexConverter { attachAnnotations(parameter, parameterAnnotations); } - if (!isCompilerDefined && parameterNames != null && parameterNames.length > parameterNameIdx) { + if (!isCompilerDefined && namedParameterCount > parameterNameIdx) { parameter.setName(parameterNames[parameterNameIdx++]); } descriptorParameterIdx++; @@ -393,11 +394,12 @@ public final class ClassFileToIndexConverter { if (exceptionTypes == null) { exceptionTypes = CharArrayUtils.EMPTY_ARRAY_OF_CHAR_ARRAYS; } + method.allocateExceptions(exceptionTypes.length); int throwsIdx = 0; if (hasExceptionsInSignature) { while (hasAnotherException(signature)) { signature.start++; - new NdMethodException(method, createTypeSignature(signature, + method.createException(createTypeSignature(signature, JavaNames.binaryNameToFieldDescriptor(exceptionTypes[throwsIdx]))); throwsIdx++; } @@ -405,7 +407,7 @@ public final class ClassFileToIndexConverter { for (;throwsIdx < exceptionTypes.length; throwsIdx++) { char[] fieldDescriptor = JavaNames.binaryNameToFieldDescriptor(exceptionTypes[throwsIdx]); SignatureWrapper convertedWrapper = new SignatureWrapper(fieldDescriptor); - new NdMethodException(method, createTypeSignature(convertedWrapper, + method.createException(createTypeSignature(convertedWrapper, JavaNames.binaryNameToFieldDescriptor(exceptionTypes[throwsIdx]))); } } @@ -439,7 +441,7 @@ public final class ClassFileToIndexConverter { * Adds the given field to the given type */ private void addField(NdType type, IBinaryField nextField) throws CoreException { - NdVariable variable = new NdVariable(type); + NdVariable variable = type.createVariable(); variable.setName(nextField.getName()); @@ -455,18 +457,23 @@ public final class ClassFileToIndexConverter { IBinaryTypeAnnotation[] typeAnnotations = nextField.getTypeAnnotations(); if (typeAnnotations != null) { + variable.allocateTypeAnnotations(typeAnnotations.length); for (IBinaryTypeAnnotation next : typeAnnotations) { - NdTypeAnnotationInVariable annotation = new NdTypeAnnotationInVariable(getNd(), variable); + NdTypeAnnotation annotation = variable.createTypeAnnotation(); initTypeAnnotation(annotation, next); } } variable.setType(createTypeSignature(nextTypeSignature, nextField.getTypeName())); variable.setTagBits(nextField.getTagBits()); + } - // char[] fieldDescriptor = nextField.getTypeName(); - // // DO NOT SUBMIT: - // IBinaryField bf = IndexBinaryType.createBinaryField(variable); + private static class TypeParameter { + public TypeParameter() { + } + public List<NdTypeSignature> bounds = new ArrayList<>(); + public char[] identifier = ClassFileToIndexConverter.EMPTY_CHAR_ARRAY; + public boolean firstBoundIsClass; } /** @@ -482,25 +489,40 @@ public final class ClassFileToIndexConverter { return; } + List<TypeParameter> typeParameters = new ArrayList<>(); + int indexOfClosingBracket = wrapper.skipAngleContents(wrapper.start) - 1; wrapper.start++; - NdTypeParameter parameter = null; + TypeParameter parameter = null; while (wrapper.start < indexOfClosingBracket) { int colonPos = CharOperation.indexOf(':', genericSignature, wrapper.start, indexOfClosingBracket); if (colonPos > wrapper.start) { char[] identifier = CharOperation.subarray(genericSignature, wrapper.start, colonPos); - parameter = new NdTypeParameter(type, identifier); + parameter = new TypeParameter(); + typeParameters.add(parameter); + parameter.identifier = identifier; wrapper.start = colonPos + 1; // The first bound is a class as long as it doesn't start with a double-colon - parameter.setFirstBoundIsClass(wrapper.charAtStart() != ':'); + parameter.firstBoundIsClass = (wrapper.charAtStart() != ':'); } skipChar(wrapper, ':'); NdTypeSignature boundSignature = createTypeSignature(wrapper, JAVA_LANG_OBJECT_FIELD_DESCRIPTOR); - new NdTypeBound(parameter, boundSignature); + parameter.bounds.add(boundSignature); + } + + type.allocateTypeParameters(typeParameters.size()); + for (TypeParameter param : typeParameters) { + NdTypeParameter ndParam = type.createTypeParameter(); + ndParam.setIdentifier(param.identifier); + ndParam.setFirstBoundIsClass(param.firstBoundIsClass); + ndParam.allocateBounds(param.bounds.size()); + for (NdTypeSignature bound : param.bounds) { + ndParam.createBound(bound); + } } skipChar(wrapper, '>'); @@ -854,8 +876,9 @@ public final class ClassFileToIndexConverter { IBinaryElementValuePair[] pairs = next.getElementValuePairs(); if (pairs != null) { + annotation.allocateValuePairs(pairs.length); for (IBinaryElementValuePair element : pairs) { - NdAnnotationValuePair nextPair = new NdAnnotationValuePair(annotation, element.getName()); + NdAnnotationValuePair nextPair = annotation.createValuePair(element.getName()); nextPair.setValue(createConstantFromMixedType(element.getValue())); } } @@ -894,9 +917,9 @@ public final class ClassFileToIndexConverter { } else if (value instanceof IBinaryAnnotation) { IBinaryAnnotation binaryAnnotation = (IBinaryAnnotation) value; - NdAnnotationInConstant annotation = new NdAnnotationInConstant(getNd()); - initAnnotation(annotation, binaryAnnotation); - return NdConstantAnnotation.create(getNd(), annotation); + NdConstantAnnotation constant = new NdConstantAnnotation(getNd()); + initAnnotation(constant.getValue(), binaryAnnotation); + return constant; } else if (value instanceof Object[]) { NdConstantArray result = new NdConstantArray(getNd()); Object[] array = (Object[]) value; diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java index 877713cb0f..08bd027304 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java @@ -75,7 +75,6 @@ import org.eclipse.jdt.internal.core.nd.java.NdResourceFile; import org.eclipse.jdt.internal.core.nd.java.NdType; import org.eclipse.jdt.internal.core.nd.java.NdTypeId; import org.eclipse.jdt.internal.core.nd.java.NdWorkspaceLocation; -import org.eclipse.jdt.internal.core.nd.java.NdZipEntry; import org.eclipse.jdt.internal.core.nd.java.TypeRef; import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeDescriptor; import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeFactory; @@ -704,6 +703,13 @@ public final class Indexer { } subMonitor.setWorkRemaining(zipFile.size()); + // Preallocate memory for the zipfile entries + this.nd.acquireWriteLock(subMonitor.split(5)); + try { + resourceFile.allocateZipEntries(zipFile.size()); + } finally { + this.nd.releaseWriteLock(); + } for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements();) { SubMonitor nextEntry = subMonitor.split(1).setWorkRemaining(2); ZipEntry member = e.nextElement(); @@ -717,7 +723,7 @@ public final class Indexer { Package.logInfo("Inserting non-class file " + fileName + " into " //$NON-NLS-1$//$NON-NLS-2$ + resourceFile.getLocation().getString() + " " + resourceFile.address); //$NON-NLS-1$ } - new NdZipEntry(resourceFile, fileName); + resourceFile.addZipEntry(fileName); if (fileName.equals("META-INF/MANIFEST.MF")) { //$NON-NLS-1$ try (InputStream inputStream = zipFile.getInputStream(member)) { diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java index 2c416a6a47..9c9f94a90d 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java @@ -38,9 +38,9 @@ import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils; public class JavaIndex { // Version constants - static final int CURRENT_VERSION = Nd.version(1, 47); - static final int MAX_SUPPORTED_VERSION = Nd.version(1, 47); - static final int MIN_SUPPORTED_VERSION = Nd.version(1, 47); + static final int CURRENT_VERSION = Nd.version(1, 48); + static final int MAX_SUPPORTED_VERSION = Nd.version(1, 48); + static final int MIN_SUPPORTED_VERSION = Nd.version(1, 48); // Fields for the search header public static final FieldSearchIndex<NdResourceFile> FILES; @@ -289,13 +289,7 @@ public class JavaIndex { static NdNodeTypeRegistry<NdNode> createTypeRegistry() { NdNodeTypeRegistry<NdNode> registry = new NdNodeTypeRegistry<>(); - registry.register(0x0001, NdAnnotation.type.getFactory()); - registry.register(0x0004, NdAnnotationInConstant.type.getFactory()); - registry.register(0x0008, NdAnnotationInMethod.type.getFactory()); - registry.register(0x000c, NdAnnotationInMethodParameter.type.getFactory()); - registry.register(0x0010, NdAnnotationInType.type.getFactory()); - registry.register(0x0014, NdAnnotationInVariable.type.getFactory()); - registry.register(0x0020, NdAnnotationValuePair.type.getFactory()); + registry.register(0x0028, NdBinding.type.getFactory()); registry.register(0x0030, NdComplexTypeSignature.type.getFactory()); registry.register(0x0038, NdConstant.type.getFactory()); @@ -314,25 +308,16 @@ public class JavaIndex { registry.register(0x0100, NdConstantString.type.getFactory()); registry.register(0x0110, NdMethod.type.getFactory()); registry.register(0x0118, NdMethodAnnotationData.type.getFactory()); - registry.register(0x0120, NdMethodException.type.getFactory()); registry.register(0x0130, NdMethodId.type.getFactory()); - registry.register(0x0140, NdMethodParameter.type.getFactory()); registry.register(0x0150, NdResourceFile.type.getFactory()); registry.register(0x0170, NdType.type.getFactory()); - registry.register(0x0180, NdTypeAnnotation.type.getFactory()); - registry.register(0x0184, NdTypeAnnotationInMethod.type.getFactory()); - registry.register(0x0188, NdTypeAnnotationInType.type.getFactory()); - registry.register(0x018c, NdTypeAnnotationInVariable.type.getFactory()); registry.register(0x0190, NdTypeArgument.type.getFactory()); - registry.register(0x0194, NdTypeBound.type.getFactory()); registry.register(0x01A0, NdTypeInterface.type.getFactory()); - registry.register(0x01B0, NdTypeParameter.type.getFactory()); registry.register(0x01C0, NdTypeSignature.type.getFactory()); registry.register(0x01D0, NdTypeId.type.getFactory()); registry.register(0x01E0, NdTypeInterface.type.getFactory()); registry.register(0x01F0, NdVariable.type.getFactory()); registry.register(0x0200, NdWorkspaceLocation.type.getFactory()); - registry.register(0x0210, NdZipEntry.type.getFactory()); return registry; } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java index 9715c100e1..7248ce4708 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java @@ -13,22 +13,22 @@ package org.eclipse.jdt.internal.core.nd.java; import java.util.List; import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.NdNode; +import org.eclipse.jdt.internal.core.nd.NdStruct; +import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; import org.eclipse.jdt.internal.core.nd.field.StructDef; -public class NdAnnotation extends NdNode { +public class NdAnnotation extends NdStruct { public static final FieldManyToOne<NdTypeSignature> ANNOTATION_TYPE; - public static final FieldOneToMany<NdAnnotationValuePair> ELEMENT_VALUE_PAIRS; + public static final FieldList<NdAnnotationValuePair> ELEMENT_VALUE_PAIRS; @SuppressWarnings("hiding") public static final StructDef<NdAnnotation> type; static { - type = StructDef.create(NdAnnotation.class, NdNode.type); + type = StructDef.create(NdAnnotation.class, NdStruct.type); ANNOTATION_TYPE = FieldManyToOne.create(type, NdTypeSignature.ANNOTATIONS_OF_THIS_TYPE); - ELEMENT_VALUE_PAIRS = FieldOneToMany.create(type, NdAnnotationValuePair.APPLIES_TO); + ELEMENT_VALUE_PAIRS = FieldList.create(type, NdAnnotationValuePair.type); type.done(); } @@ -36,10 +36,6 @@ public class NdAnnotation extends NdNode { super(nd, address); } - public NdAnnotation(Nd nd) { - super(nd); - } - public NdTypeSignature getType() { return ANNOTATION_TYPE.get(getNd(), this.address); } @@ -51,4 +47,14 @@ public class NdAnnotation extends NdNode { public List<NdAnnotationValuePair> getElementValuePairs() { return ELEMENT_VALUE_PAIRS.asList(getNd(), this.address); } + + public NdAnnotationValuePair createValuePair(char[] name) { + NdAnnotationValuePair result = ELEMENT_VALUE_PAIRS.append(getNd(), getAddress()); + result.setName(name); + return result; + } + + public void allocateValuePairs(int length) { + ELEMENT_VALUE_PAIRS.allocate(getNd(), getAddress(), length); + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java deleted file mode 100644 index d3ee914d11..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd.java; - -import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne; -import org.eclipse.jdt.internal.core.nd.field.StructDef; - -public class NdAnnotationInConstant extends NdAnnotation { - public static final FieldOneToOne<NdConstantAnnotation> OWNER; - - @SuppressWarnings("hiding") - public static final StructDef<NdAnnotationInConstant> type; - - static { - type = StructDef.create(NdAnnotationInConstant.class, NdAnnotation.type); - OWNER = FieldOneToOne.createOwner(type, NdConstantAnnotation.type, NdConstantAnnotation.VALUE); - type.done(); - } - - public NdAnnotationInConstant(Nd nd, long address) { - super(nd, address); - } - - public NdAnnotationInConstant(Nd nd) { - super(nd); - } - -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java deleted file mode 100644 index c1b524ec79..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd.java; - -import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.StructDef; - -public class NdAnnotationInMethod extends NdAnnotation { - public static final FieldManyToOne<NdMethodAnnotationData> OWNER; - - @SuppressWarnings("hiding") - public static final StructDef<NdAnnotationInMethod> type; - - static { - type = StructDef.create(NdAnnotationInMethod.class, NdAnnotation.type); - OWNER = FieldManyToOne.createOwner(type, NdMethodAnnotationData.ANNOTATIONS); - type.done(); - } - - public NdAnnotationInMethod(Nd nd, long address) { - super(nd, address); - } - - public NdAnnotationInMethod(Nd nd, NdMethod owner) { - super(nd); - - OWNER.put(getNd(), this.address, owner.createAnnotationData()); - } - -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java deleted file mode 100644 index 0a4f3fb688..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd.java; - -import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.StructDef; - -public class NdAnnotationInMethodParameter extends NdAnnotation { - public static final FieldManyToOne<NdMethodParameter> OWNER; - - @SuppressWarnings("hiding") - public static final StructDef<NdAnnotationInMethodParameter> type; - - static { - type = StructDef.create(NdAnnotationInMethodParameter.class, NdAnnotation.type); - OWNER = FieldManyToOne.createOwner(type, NdMethodParameter.ANNOTATIONS); - type.done(); - } - - public NdAnnotationInMethodParameter(Nd nd, long address) { - super(nd, address); - } - - public NdAnnotationInMethodParameter(Nd nd, NdMethodParameter owner) { - super(nd); - - OWNER.put(getNd(), this.address, owner); - } - -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java deleted file mode 100644 index c220ed9f01..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd.java; - -import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.StructDef; - -public class NdAnnotationInType extends NdAnnotation { - public static final FieldManyToOne<NdType> OWNER; - - @SuppressWarnings("hiding") - public static final StructDef<NdAnnotationInType> type; - - static { - type = StructDef.create(NdAnnotationInType.class, NdAnnotation.type); - OWNER = FieldManyToOne.createOwner(type, NdType.ANNOTATIONS); - type.done(); - } - - public NdAnnotationInType(Nd nd, long address) { - super(nd, address); - } - - public NdAnnotationInType(Nd nd, NdType owner) { - super(nd); - - OWNER.put(getNd(), this.address, owner); - } - -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java deleted file mode 100644 index 378b2d44a2..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd.java; - -import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.StructDef; - -public class NdAnnotationInVariable extends NdAnnotation { - public static final FieldManyToOne<NdVariable> OWNER; - - @SuppressWarnings("hiding") - public static final StructDef<NdAnnotationInVariable> type; - - static { - type = StructDef.create(NdAnnotationInVariable.class, NdAnnotation.type); - OWNER = FieldManyToOne.createOwner(type, NdVariable.ANNOTATIONS); - type.done(); - } - - public NdAnnotationInVariable(Nd nd, long address) { - super(nd, address); - } - - public NdAnnotationInVariable(Nd nd, NdVariable owner) { - super(nd); - - OWNER.put(getNd(), this.address, owner); - } - -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java index 303a0bcb61..eb5d3c20a8 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java @@ -11,15 +11,13 @@ package org.eclipse.jdt.internal.core.nd.java; import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.NdNode; +import org.eclipse.jdt.internal.core.nd.NdStruct; import org.eclipse.jdt.internal.core.nd.db.IString; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne; import org.eclipse.jdt.internal.core.nd.field.FieldString; import org.eclipse.jdt.internal.core.nd.field.StructDef; -public class NdAnnotationValuePair extends NdNode { - public static final FieldManyToOne<NdAnnotation> APPLIES_TO; +public class NdAnnotationValuePair extends NdStruct { public static final FieldString NAME; public static final FieldOneToOne<NdConstant> VALUE; @@ -27,8 +25,7 @@ public class NdAnnotationValuePair extends NdNode { public static final StructDef<NdAnnotationValuePair> type; static { - type = StructDef.create(NdAnnotationValuePair.class, NdNode.type); - APPLIES_TO = FieldManyToOne.createOwner(type, NdAnnotation.ELEMENT_VALUE_PAIRS); + type = StructDef.create(NdAnnotationValuePair.class, NdStruct.type); NAME = type.addString(); VALUE = FieldOneToOne.create(type, NdConstant.type, NdConstant.PARENT_ANNOTATION_VALUE); type.done(); @@ -38,22 +35,11 @@ public class NdAnnotationValuePair extends NdNode { super(nd, address); } - public NdAnnotationValuePair(NdAnnotation annotation, char[] name) { - super(annotation.getNd()); - Nd nd = annotation.getNd(); - APPLIES_TO.put(nd, this.address, annotation); - NAME.put(nd, this.address, name); - } - - public NdAnnotation getAnnotation() { - return APPLIES_TO.get(getNd(), this.address); - } - public IString getName() { return NAME.get(getNd(), this.address); } - public void setName(String name) { + public void setName(char[] name) { NAME.put(getNd(), this.address, name); } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java index 3c48fc92db..6fb38a9bf2 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java @@ -17,7 +17,7 @@ import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.NdNode; import org.eclipse.jdt.internal.core.nd.field.FieldInt; -import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; +import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.StructDef; import org.eclipse.jdt.internal.core.util.CharArrayBuffer; @@ -26,8 +26,7 @@ import org.eclipse.jdt.internal.core.util.CharArrayBuffer; */ public abstract class NdBinding extends NdNode implements IAdaptable { public static final FieldInt MODIFIERS; - public static final FieldOneToMany<NdTypeParameter> TYPE_PARAMETERS; - public static final FieldOneToMany<NdVariable> VARIABLES; + public static final FieldList<NdTypeParameter> TYPE_PARAMETERS; @SuppressWarnings("hiding") public static final StructDef<NdBinding> type; @@ -35,8 +34,7 @@ public abstract class NdBinding extends NdNode implements IAdaptable { static { type = StructDef.create(NdBinding.class, NdNode.type); MODIFIERS = type.addInt(); - TYPE_PARAMETERS = FieldOneToMany.create(type, NdTypeParameter.PARENT); - VARIABLES = FieldOneToMany.create(type, NdVariable.PARENT); + TYPE_PARAMETERS = FieldList.create(type, NdTypeParameter.type); type.done(); } @@ -48,10 +46,6 @@ public abstract class NdBinding extends NdNode implements IAdaptable { super(nd); } - public List<NdVariable> getVariables() { - return VARIABLES.asList(getNd(), this.address); - } - /** * Tests whether this binding has one of the flags defined in {@link Flags} */ @@ -106,4 +100,12 @@ public abstract class NdBinding extends NdNode implements IAdaptable { public List<NdTypeParameter> getTypeParameters() { return TYPE_PARAMETERS.asList(getNd(), this.address); } + + public NdTypeParameter createTypeParameter() { + return TYPE_PARAMETERS.append(getNd(), getAddress()); + } + + public void allocateTypeParameters(int elements) { + TYPE_PARAMETERS.allocate(getNd(), getAddress(), elements); + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java index a231458df6..35a0da423b 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java @@ -12,18 +12,18 @@ package org.eclipse.jdt.internal.core.nd.java; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne; +import org.eclipse.jdt.internal.core.nd.field.Field; import org.eclipse.jdt.internal.core.nd.field.StructDef; public final class NdConstantAnnotation extends NdConstant { - public static final FieldOneToOne<NdAnnotationInConstant> VALUE; + public static final Field<NdAnnotation> VALUE; @SuppressWarnings("hiding") public static StructDef<NdConstantAnnotation> type; static { type = StructDef.create(NdConstantAnnotation.class, NdConstant.type); - VALUE = FieldOneToOne.create(type, NdAnnotationInConstant.type, NdAnnotationInConstant.OWNER); + VALUE = Field.create(type, NdAnnotation.type); type.done(); } @@ -31,20 +31,10 @@ public final class NdConstantAnnotation extends NdConstant { super(nd, address); } - protected NdConstantAnnotation(Nd nd) { + public NdConstantAnnotation(Nd nd) { super(nd); } - public static NdConstantAnnotation create(Nd nd, NdAnnotationInConstant value) { - NdConstantAnnotation result = new NdConstantAnnotation(nd); - result.setValue(value); - return result; - } - - public void setValue(NdAnnotationInConstant value) { - VALUE.put(getNd(), this.address, value); - } - public NdAnnotation getValue() { return VALUE.get(getNd(), this.address); } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java index d7d49b8c24..2ff6c3edfc 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java @@ -14,6 +14,7 @@ import java.util.Collections; import java.util.List; import org.eclipse.jdt.internal.core.nd.Nd; +import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne; @@ -27,9 +28,9 @@ public class NdMethod extends NdBinding { public static final FieldShort METHOD_FLAGS; public static final FieldManyToOne<NdType> PARENT; public static final FieldOneToMany<NdVariable> DECLARED_VARIABLES; - public static final FieldOneToMany<NdMethodParameter> PARAMETERS; + public static final FieldList<NdMethodParameter> PARAMETERS; public static final FieldOneToOne<NdConstant> DEFAULT_VALUE; - public static final FieldOneToMany<NdMethodException> EXCEPTIONS; + public static final FieldList<NdMethodException> EXCEPTIONS; public static final FieldManyToOne<NdTypeSignature> RETURN_TYPE; public static final FieldOneToOne<NdMethodAnnotationData> ANNOTATION_DATA; @@ -41,10 +42,10 @@ public class NdMethod extends NdBinding { METHOD_ID = FieldManyToOne.create(type, NdMethodId.METHODS); METHOD_FLAGS = type.addShort(); PARENT = FieldManyToOne.createOwner(type, NdType.METHODS); - PARAMETERS = FieldOneToMany.create(type, NdMethodParameter.PARENT); + PARAMETERS = FieldList.create(type, NdMethodParameter.type); DECLARED_VARIABLES = FieldOneToMany.create(type, NdVariable.DECLARING_METHOD); DEFAULT_VALUE = FieldOneToOne.create(type, NdConstant.type, NdConstant.PARENT_METHOD); - EXCEPTIONS = FieldOneToMany.create(type, NdMethodException.PARENT); + EXCEPTIONS = FieldList.create(type, NdMethodException.type); RETURN_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_RETURN_TYPE); ANNOTATION_DATA = FieldOneToOne.create(type, NdMethodAnnotationData.type, NdMethodAnnotationData.METHOD); type.done(); @@ -63,6 +64,14 @@ public class NdMethod extends NdBinding { PARENT.put(getNd(), this.address, parent); } + public NdMethodParameter createNewParameter() { + return PARAMETERS.append(getNd(), getAddress()); + } + + public void allocateParameters(int numParameters) { + PARAMETERS.allocate(this.nd, this.address, numParameters); + } + public NdMethodId getMethodId() { return METHOD_ID.get(getNd(), this.address); } @@ -90,7 +99,7 @@ public class NdMethod extends NdBinding { return PARAMETERS.asList(getNd(), this.address); } - public List<NdAnnotationInMethod> getAnnotations() { + public List<NdAnnotation> getAnnotations() { NdMethodAnnotationData annotationData = getAnnotationData(); if (annotationData != null) { return annotationData.getAnnotations(); @@ -114,7 +123,7 @@ public class NdMethod extends NdBinding { METHOD_ID.put(getNd(), this.address, methodId); } - public List<NdTypeAnnotationInMethod> getTypeAnnotations() { + public List<NdTypeAnnotation> getTypeAnnotations() { NdMethodAnnotationData annotationData = getAnnotationData(); if (annotationData != null) { return annotationData.getTypeAnnotations(); @@ -220,4 +229,34 @@ public class NdMethod extends NdBinding { private NdMethodAnnotationData getAnnotationData() { return ANNOTATION_DATA.get(getNd(), getAddress()); } + + public NdMethodException createException(NdTypeSignature createTypeSignature) { + NdMethodException result = EXCEPTIONS.append(getNd(), getAddress()); + result.setExceptionType(createTypeSignature); + return result; + } + + public void allocateExceptions(int length) { + EXCEPTIONS.allocate(this.nd, this.address, length); + } + + public NdAnnotation createAnnotation() { + return createAnnotationData().createAnnotation(); + } + + public NdTypeAnnotation createTypeAnnotation() { + return createAnnotationData().createTypeAnnotation(); + } + + public void allocateAnnotations(int length) { + if (length > 0) { + createAnnotationData().allocateAnnotations(length); + } + } + + public void allocateTypeAnnotations(int length) { + if (length > 0) { + createAnnotationData().allocateTypeAnnotations(length); + } + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodAnnotationData.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodAnnotationData.java index d7d62a32f2..a06518a635 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodAnnotationData.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodAnnotationData.java @@ -14,8 +14,8 @@ import java.util.List; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.NdNode; +import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.FieldLong; -import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne; import org.eclipse.jdt.internal.core.nd.field.StructDef; @@ -26,8 +26,8 @@ import org.eclipse.jdt.internal.core.nd.field.StructDef; public class NdMethodAnnotationData extends NdNode { public static final FieldOneToOne<NdMethod> METHOD; public static final FieldLong TAG_BITS; - public static final FieldOneToMany<NdAnnotationInMethod> ANNOTATIONS; - public static final FieldOneToMany<NdTypeAnnotationInMethod> TYPE_ANNOTATIONS; + public static final FieldList<NdAnnotation> ANNOTATIONS; + public static final FieldList<NdTypeAnnotation> TYPE_ANNOTATIONS; @SuppressWarnings("hiding") public static final StructDef<NdMethodAnnotationData> type; @@ -36,8 +36,8 @@ public class NdMethodAnnotationData extends NdNode { type = StructDef.create(NdMethodAnnotationData.class, NdNode.type); METHOD = FieldOneToOne.createOwner(type, NdMethod.type, NdMethod.ANNOTATION_DATA); TAG_BITS = type.addLong(); - ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInMethod.OWNER); - TYPE_ANNOTATIONS = FieldOneToMany.create(type, NdTypeAnnotationInMethod.OWNER); + ANNOTATIONS = FieldList.create(type, NdAnnotation.type); + TYPE_ANNOTATIONS = FieldList.create(type, NdTypeAnnotation.type); type.done(); } @@ -59,11 +59,27 @@ public class NdMethodAnnotationData extends NdNode { return TAG_BITS.get(getNd(), this.address); } - public List<NdTypeAnnotationInMethod> getTypeAnnotations() { + public List<NdTypeAnnotation> getTypeAnnotations() { return TYPE_ANNOTATIONS.asList(getNd(), this.address); } - public List<NdAnnotationInMethod> getAnnotations() { + public List<NdAnnotation> getAnnotations() { return ANNOTATIONS.asList(getNd(), this.address); } + + public NdAnnotation createAnnotation() { + return ANNOTATIONS.append(getNd(), getAddress()); + } + + public void allocateAnnotations(int length) { + ANNOTATIONS.allocate(getNd(), getAddress(), length); + } + + public NdTypeAnnotation createTypeAnnotation() { + return TYPE_ANNOTATIONS.append(getNd(), getAddress()); + } + + public void allocateTypeAnnotations(int length) { + TYPE_ANNOTATIONS.allocate(getNd(), getAddress(), length); + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java index 4c7cfe5a26..a90d63d9c3 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java @@ -11,21 +11,19 @@ package org.eclipse.jdt.internal.core.nd.java; import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.NdNode; +import org.eclipse.jdt.internal.core.nd.NdStruct; import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; import org.eclipse.jdt.internal.core.nd.field.StructDef; -public class NdMethodException extends NdNode { +public class NdMethodException extends NdStruct { - public static final FieldManyToOne<NdMethod> PARENT; public static final FieldManyToOne<NdTypeSignature> EXCEPTION_TYPE; @SuppressWarnings("hiding") public static StructDef<NdMethodException> type; static { - type = StructDef.create(NdMethodException.class, NdNode.type); - PARENT = FieldManyToOne.createOwner(type, NdMethod.EXCEPTIONS); + type = StructDef.create(NdMethodException.class); EXCEPTION_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_EXCEPTION); type.done(); } @@ -34,21 +32,14 @@ public class NdMethodException extends NdNode { super(nd, address); } - public NdMethodException(NdMethod method, NdTypeSignature createTypeSignature) { - super(method.getNd()); - - PARENT.put(getNd(), this.address, method); - EXCEPTION_TYPE.put(getNd(), this.address, createTypeSignature); + public void setExceptionType(NdTypeSignature signature) { + EXCEPTION_TYPE.put(getNd(), this.address, signature); } public NdTypeSignature getExceptionType() { return EXCEPTION_TYPE.get(getNd(), this.address); } - public NdMethod getParent() { - return PARENT.get(getNd(), this.address); - } - public String toString() { try { return getExceptionType().toString(); diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java index bdcd8324df..47d5df26de 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java @@ -13,20 +13,19 @@ package org.eclipse.jdt.internal.core.nd.java; import java.util.List; import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.NdNode; +import org.eclipse.jdt.internal.core.nd.NdStruct; import org.eclipse.jdt.internal.core.nd.db.IString; import org.eclipse.jdt.internal.core.nd.field.FieldByte; +import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; import org.eclipse.jdt.internal.core.nd.field.FieldString; import org.eclipse.jdt.internal.core.nd.field.StructDef; import org.eclipse.jdt.internal.core.util.CharArrayBuffer; -public class NdMethodParameter extends NdNode { - public static final FieldManyToOne<NdMethod> PARENT; +public class NdMethodParameter extends NdStruct { public static final FieldManyToOne<NdTypeSignature> ARGUMENT_TYPE; public static final FieldString NAME; - public static final FieldOneToMany<NdAnnotationInMethodParameter> ANNOTATIONS; + public static final FieldList<NdAnnotation> ANNOTATIONS; public static final FieldByte FLAGS; private static final byte FLG_COMPILER_DEFINED = 0x01; @@ -35,11 +34,10 @@ public class NdMethodParameter extends NdNode { public static StructDef<NdMethodParameter> type; static { - type = StructDef.create(NdMethodParameter.class, NdNode.type); - PARENT = FieldManyToOne.create(type, NdMethod.PARAMETERS); + type = StructDef.create(NdMethodParameter.class); ARGUMENT_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_METHOD_ARGUMENT); NAME = type.addString(); - ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInMethodParameter.OWNER); + ANNOTATIONS = FieldList.create(type, NdAnnotation.type); FLAGS = type.addByte(); type.done(); } @@ -48,10 +46,7 @@ public class NdMethodParameter extends NdNode { super(nd, address); } - public NdMethodParameter(NdMethod parent, NdTypeSignature argumentType) { - super(parent.getNd()); - - PARENT.put(getNd(), this.address, parent); + public void setType(NdTypeSignature argumentType) { ARGUMENT_TYPE.put(getNd(), this.address, argumentType); } @@ -67,7 +62,7 @@ public class NdMethodParameter extends NdNode { return NAME.get(getNd(), this.address); } - public List<NdAnnotationInMethodParameter> getAnnotations() { + public List<NdAnnotation> getAnnotations() { return ANNOTATIONS.asList(getNd(), this.address); } @@ -102,4 +97,12 @@ public class NdMethodParameter extends NdNode { return super.toString(); } } + + public NdAnnotation createAnnotation() { + return ANNOTATIONS.append(getNd(), getAddress()); + } + + public void allocateAnnotations(int length) { + ANNOTATIONS.allocate(getNd(), getAddress(), length); + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java index 8a81f10353..9c8e979795 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java @@ -22,6 +22,7 @@ import org.eclipse.jdt.internal.core.nd.NdNode; import org.eclipse.jdt.internal.core.nd.db.Database; import org.eclipse.jdt.internal.core.nd.db.IString; import org.eclipse.jdt.internal.core.nd.db.IndexException; +import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.FieldLong; import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany.Visitor; @@ -45,7 +46,7 @@ public class NdResourceFile extends NdNode { public static final FieldOneToMany<NdWorkspaceLocation> WORKSPACE_MAPPINGS; public static final FieldString JAVA_ROOT; public static final FieldLong JDK_LEVEL; - public static final FieldOneToMany<NdZipEntry> ZIP_ENTRIES; + public static final FieldList<NdZipEntry> ZIP_ENTRIES; public static final FieldString MANIFEST_CONTENT; public static final FieldShort FILE_FLAGS; @@ -68,7 +69,7 @@ public class NdResourceFile extends NdNode { WORKSPACE_MAPPINGS = FieldOneToMany.create(type, NdWorkspaceLocation.RESOURCE); JAVA_ROOT = type.addString(); JDK_LEVEL = type.addLong(); - ZIP_ENTRIES = FieldOneToMany.create(type, NdZipEntry.JAR_FILE); + ZIP_ENTRIES = FieldList.create(type, NdZipEntry.type, 1); MANIFEST_CONTENT = type.addString(); FILE_FLAGS = type.addShort(); @@ -148,16 +149,16 @@ public class NdResourceFile extends NdNode { */ public boolean isInIndex() { try { - Nd nd = getNd(); // In the common case where the resource file was deleted and the memory hasn't yet been reused, // this will fail. - if (!nd.isValidAddress(this.address) || NODE_TYPE.get(nd, this.address) != nd.getNodeType(getClass())) { + if (!this.nd.isValidAddress(this.address) + || NODE_TYPE.get(this.nd, this.address) != this.nd.getNodeType(getClass())) { return false; } char[] filename = FILENAME.get(getNd(), this.address).getChars(); - NdResourceFile result = JavaIndex.FILES.findBest(nd, Database.DATA_AREA_OFFSET, + NdResourceFile result = JavaIndex.FILES.findBest(this.nd, Database.DATA_AREA_OFFSET, SearchCriteria.create(filename), new IResultRank() { @Override public long getRank(Nd testNd, long testAddress) { @@ -327,4 +328,14 @@ public class NdResourceFile extends NdNode { return super.toString(); } } + + public void allocateZipEntries(int expectedNumberOfZipEntries) { + ZIP_ENTRIES.allocate(this.nd, this.address, expectedNumberOfZipEntries); + } + + public NdZipEntry addZipEntry(String fileName) { + NdZipEntry result = ZIP_ENTRIES.append(getNd(), getAddress()); + result.setFilename(fileName); + return result; + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java index d83f37a4f1..2594136c49 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java @@ -12,11 +12,10 @@ package org.eclipse.jdt.internal.core.nd.java; import java.util.List; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.internal.core.nd.INdVisitor; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.db.IString; import org.eclipse.jdt.internal.core.nd.field.FieldByte; +import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.FieldLong; import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; @@ -32,8 +31,9 @@ public class NdType extends NdBinding { public static final FieldManyToOne<NdTypeId> DECLARING_TYPE; public static final FieldManyToOne<NdMethodId> DECLARING_METHOD; public static final FieldOneToMany<NdMethod> METHODS; - public static final FieldOneToMany<NdTypeAnnotationInType> TYPE_ANNOTATIONS; - public static final FieldOneToMany<NdAnnotationInType> ANNOTATIONS; + public static final FieldList<NdTypeAnnotation> TYPE_ANNOTATIONS; + public static final FieldList<NdAnnotation> ANNOTATIONS; + public static final FieldList<NdVariable> VARIABLES; public static final FieldString MISSING_TYPE_NAMES; public static final FieldString SOURCE_FILE_NAME; public static final FieldString INNER_CLASS_SOURCE_NAME; @@ -58,8 +58,9 @@ public class NdType extends NdBinding { SUPERCLASS = FieldManyToOne.create(type, NdTypeSignature.SUBCLASSES); DECLARING_METHOD = FieldManyToOne.create(type, NdMethodId.DECLARED_TYPES); METHODS = FieldOneToMany.create(type, NdMethod.PARENT, 6); - TYPE_ANNOTATIONS = FieldOneToMany.create(type, NdTypeAnnotationInType.OWNER); - ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInType.OWNER); + TYPE_ANNOTATIONS = FieldList.create(type, NdTypeAnnotation.type); + ANNOTATIONS = FieldList.create(type, NdAnnotation.type); + VARIABLES = FieldList.create(type, NdVariable.type); MISSING_TYPE_NAMES = type.addString(); SOURCE_FILE_NAME = type.addString(); INNER_CLASS_SOURCE_NAME = type.addString(); @@ -84,13 +85,6 @@ public class NdType extends NdBinding { FILE.put(nd, this.address, resource); } - /** - * Called to populate the cache for the bindings in the class scope. - */ - public void acceptUncached(INdVisitor visitor) throws CoreException { - super.accept(visitor); - } - public NdTypeId getTypeId() { return TYPENAME.get(getNd(), this.address); } @@ -221,6 +215,10 @@ public class NdType extends NdBinding { return JavaNames.simpleNameToSourceName(simpleName); } + public List<NdVariable> getVariables() { + return VARIABLES.asList(getNd(), this.address); + } + public NdMethodId getDeclaringMethod() { return DECLARING_METHOD.get(getNd(), this.address); } @@ -230,14 +228,22 @@ public class NdType extends NdBinding { return TYPE_PARAMETERS.asList(getNd(), this.address); } - public List<NdTypeAnnotationInType> getTypeAnnotations() { + public List<NdTypeAnnotation> getTypeAnnotations() { return TYPE_ANNOTATIONS.asList(getNd(), this.address); } - public List<NdAnnotationInType> getAnnotations() { + public List<NdAnnotation> getAnnotations() { return ANNOTATIONS.asList(getNd(), this.address); } + public NdAnnotation createAnnotation() { + return ANNOTATIONS.append(getNd(), getAddress()); + } + + public void allocateAnnotations(int length) { + ANNOTATIONS.allocate(getNd(), getAddress(), length); + } + public List<NdMethod> getMethods() { return METHODS.asList(getNd(), this.address); } @@ -275,4 +281,20 @@ public class NdType extends NdBinding { } return descriptorFromClass; } + + public NdTypeAnnotation createTypeAnnotation() { + return TYPE_ANNOTATIONS.append(getNd(), getAddress()); + } + + public void allocateTypeAnnotations(int length) { + TYPE_ANNOTATIONS.allocate(getNd(), getAddress(), length); + } + + public NdVariable createVariable() { + return VARIABLES.append(getNd(), getAddress()); + } + + public void allocateVariables(int length) { + VARIABLES.allocate(getNd(), getAddress(), length); + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java index e9bfa4a4d6..b6c0908eb1 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java @@ -11,13 +11,14 @@ package org.eclipse.jdt.internal.core.nd.java; import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants; +import org.eclipse.jdt.internal.core.nd.IDestructable; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.db.Database; import org.eclipse.jdt.internal.core.nd.field.FieldByte; import org.eclipse.jdt.internal.core.nd.field.FieldPointer; import org.eclipse.jdt.internal.core.nd.field.StructDef; -public class NdTypeAnnotation extends NdAnnotation { +public class NdTypeAnnotation extends NdAnnotation implements IDestructable { public static final FieldByte TARGET_TYPE; public static final FieldByte TARGET_ARG0; public static final FieldByte TARGET_ARG1; @@ -43,18 +44,13 @@ public class NdTypeAnnotation extends NdAnnotation { super(nd, address); } - public NdTypeAnnotation(Nd nd) { - super(nd); - } - public void setPath(byte[] path) { freePath(); - Nd nd = getNd(); - PATH_LENGTH.put(nd, this.address, (byte)path.length); + PATH_LENGTH.put(this.nd, this.address, (byte) path.length); if (path.length > 0) { - long pathArray = nd.getDB().malloc(path.length, Database.POOL_MISC); - PATH.put(nd, this.address, pathArray); - nd.getDB().putBytes(pathArray, path, path.length); + long pathArray = this.nd.getDB().malloc(path.length, Database.POOL_MISC); + PATH.put(this.nd, this.address, pathArray); + this.nd.getDB().putBytes(pathArray, path, path.length); } } @@ -111,12 +107,10 @@ public class NdTypeAnnotation extends NdAnnotation { @Override public void destruct() { freePath(); - super.destruct(); } private void freePath() { - Nd nd = getNd(); - long pathPointer = PATH.get(nd, this.address); - nd.getDB().free(pathPointer, Database.POOL_MISC); + long pathPointer = PATH.get(this.nd, this.address); + this.nd.getDB().free(pathPointer, Database.POOL_MISC); } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java deleted file mode 100644 index 06dcce393a..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd.java; - -import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.StructDef; - -public class NdTypeAnnotationInMethod extends NdTypeAnnotation { - public static final FieldManyToOne<NdMethodAnnotationData> OWNER; - - @SuppressWarnings("hiding") - public static final StructDef<NdTypeAnnotationInMethod> type; - - static { - type = StructDef.create(NdTypeAnnotationInMethod.class, NdTypeAnnotation.type); - OWNER = FieldManyToOne.createOwner(type, NdMethodAnnotationData.TYPE_ANNOTATIONS); - type.done(); - } - - public NdTypeAnnotationInMethod(Nd nd, long address) { - super(nd, address); - } - - public NdTypeAnnotationInMethod(Nd nd, NdMethod method) { - super(nd); - - OWNER.put(getNd(), this.address, method.createAnnotationData()); - } - -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java deleted file mode 100644 index 7aff109084..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd.java; - -import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.StructDef; - -public class NdTypeAnnotationInType extends NdTypeAnnotation { - public static final FieldManyToOne<NdType> OWNER; - - @SuppressWarnings("hiding") - public static final StructDef<NdTypeAnnotationInType> type; - - static { - type = StructDef.create(NdTypeAnnotationInType.class, NdTypeAnnotation.type); - OWNER = FieldManyToOne.createOwner(type, NdType.TYPE_ANNOTATIONS); - type.done(); - } - - public NdTypeAnnotationInType(Nd nd, long address) { - super(nd, address); - } - - public NdTypeAnnotationInType(Nd nd, NdType type) { - super(nd); - - OWNER.put(getNd(), this.address, type); - } - -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java deleted file mode 100644 index eb591fe06e..0000000000 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Google, Inc and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Stefan Xenos (Google) - Initial implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.core.nd.java; - -import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.StructDef; - -public class NdTypeAnnotationInVariable extends NdTypeAnnotation { - public static final FieldManyToOne<NdVariable> OWNER; - - @SuppressWarnings("hiding") - public static final StructDef<NdTypeAnnotationInVariable> type; - - static { - type = StructDef.create(NdTypeAnnotationInVariable.class, NdTypeAnnotation.type); - OWNER = FieldManyToOne.createOwner(type, NdVariable.TYPE_ANNOTATIONS); - type.done(); - } - - public NdTypeAnnotationInVariable(Nd nd, long address) { - super(nd, address); - } - - public NdTypeAnnotationInVariable(Nd nd, NdVariable variable) { - super(nd); - - OWNER.put(getNd(), this.address, variable); - } - -} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java index c6c827eeef..1a5e0ef395 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java @@ -11,7 +11,7 @@ package org.eclipse.jdt.internal.core.nd.java; import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.NdNode; +import org.eclipse.jdt.internal.core.nd.NdStruct; import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; import org.eclipse.jdt.internal.core.nd.field.StructDef; import org.eclipse.jdt.internal.core.util.CharArrayBuffer; @@ -20,16 +20,14 @@ import org.eclipse.jdt.internal.core.util.CharArrayBuffer; * Represents the bound on a generic parameter (a ClassBound or InterfaceBound in * the sense of the Java VM spec Java SE 8 Edition, section 4.7.9.1). */ -public class NdTypeBound extends NdNode { - public static final FieldManyToOne<NdTypeParameter> PARENT; +public class NdTypeBound extends NdStruct { public static final FieldManyToOne<NdTypeSignature> TYPE; @SuppressWarnings("hiding") public static final StructDef<NdTypeBound> type; static { - type = StructDef.create(NdTypeBound.class, NdNode.type); - PARENT = FieldManyToOne.createOwner(type, NdTypeParameter.BOUNDS); + type = StructDef.create(NdTypeBound.class, NdStruct.type); TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_TYPE_BOUND); type.done(); @@ -39,17 +37,10 @@ public class NdTypeBound extends NdNode { super(nd, address); } - public NdTypeBound(NdTypeParameter parent, NdTypeSignature signature) { - super(parent.getNd()); - - PARENT.put(getNd(), this.address, parent); + public void setType(NdTypeSignature signature) { TYPE.put(getNd(), this.address, signature); } - public NdTypeParameter getParent() { - return PARENT.get(getNd(), this.address); - } - public NdTypeSignature getType() { return TYPE.get(getNd(), this.address); } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java index fda4676b18..8809b841ad 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java @@ -13,10 +13,9 @@ package org.eclipse.jdt.internal.core.nd.java; import java.util.List; import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.NdNode; +import org.eclipse.jdt.internal.core.nd.NdStruct; import org.eclipse.jdt.internal.core.nd.field.FieldByte; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; +import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.FieldString; import org.eclipse.jdt.internal.core.nd.field.StructDef; import org.eclipse.jdt.internal.core.util.CharArrayBuffer; @@ -24,10 +23,9 @@ import org.eclipse.jdt.internal.core.util.CharArrayBuffer; /** * Represents a TypeParameter, as described in Section 4.7.9.1 of the java VM specification, Java SE 8 edititon. */ -public class NdTypeParameter extends NdNode { - public static final FieldManyToOne<NdBinding> PARENT; +public class NdTypeParameter extends NdStruct { public static final FieldString IDENTIFIER; - public static final FieldOneToMany<NdTypeBound> BOUNDS; + public static final FieldList<NdTypeBound> BOUNDS; public static final FieldByte TYPE_PARAMETER_FLAGS; public static final byte FLG_FIRST_BOUND_IS_A_CLASS = 0x01; @@ -36,10 +34,9 @@ public class NdTypeParameter extends NdNode { public static final StructDef<NdTypeParameter> type; static { - type = StructDef.create(NdTypeParameter.class, NdNode.type); - PARENT = FieldManyToOne.createOwner(type, NdBinding.TYPE_PARAMETERS); + type = StructDef.create(NdTypeParameter.class, NdStruct.type); IDENTIFIER = type.addString(); - BOUNDS = FieldOneToMany.create(type, NdTypeBound.PARENT); + BOUNDS = FieldList.create(type, NdTypeBound.type); TYPE_PARAMETER_FLAGS = type.addByte(); type.done(); @@ -49,10 +46,7 @@ public class NdTypeParameter extends NdNode { super(nd, address); } - public NdTypeParameter(NdBinding parent, char[] identifier) { - super(parent.getNd()); - - PARENT.put(getNd(), this.address, parent); + public void setIdentifier(char[] identifier) { IDENTIFIER.put(getNd(), this.address, identifier); } @@ -108,4 +102,12 @@ public class NdTypeParameter extends NdNode { buffer.append('>'); } } + + public void createBound(NdTypeSignature boundSignature) { + BOUNDS.append(getNd(), getAddress()).setType(boundSignature); + } + + public void allocateBounds(int numBounds) { + BOUNDS.allocate(getNd(), getAddress(), numBounds); + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java index 0ab3beefc0..1006637b2c 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java @@ -16,9 +16,9 @@ import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.db.IString; import org.eclipse.jdt.internal.core.nd.field.FieldByte; import org.eclipse.jdt.internal.core.nd.field.FieldInt; +import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.FieldLong; import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; -import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne; import org.eclipse.jdt.internal.core.nd.field.FieldString; import org.eclipse.jdt.internal.core.nd.field.StructDef; @@ -27,13 +27,12 @@ public class NdVariable extends NdBinding { public static final FieldManyToOne<NdTypeSignature> TYPE; public static final FieldInt VARIABLE_ID; public static final FieldManyToOne<NdMethod> DECLARING_METHOD; - public static final FieldManyToOne<NdBinding> PARENT; public static final FieldString NAME; public static final FieldOneToOne<NdConstant> CONSTANT; public static final FieldLong TAG_BITS; public static final FieldByte VARIABLE_FLAGS; - public static final FieldOneToMany<NdAnnotationInVariable> ANNOTATIONS; - public static final FieldOneToMany<NdTypeAnnotationInVariable> TYPE_ANNOTATIONS; + public static final FieldList<NdAnnotation> ANNOTATIONS; + public static final FieldList<NdTypeAnnotation> TYPE_ANNOTATIONS; @SuppressWarnings("hiding") public static StructDef<NdVariable> type; @@ -45,13 +44,12 @@ public class NdVariable extends NdBinding { TYPE = FieldManyToOne.create(type, NdTypeSignature.VARIABLES_OF_TYPE); VARIABLE_ID = type.addInt(); DECLARING_METHOD = FieldManyToOne.create(type, NdMethod.DECLARED_VARIABLES); - PARENT = FieldManyToOne.createOwner(type, NdBinding.VARIABLES); NAME = type.addString(); CONSTANT = FieldOneToOne.create(type, NdConstant.type, NdConstant.PARENT_VARIABLE); TAG_BITS = type.addLong(); VARIABLE_FLAGS = type.addByte(); - ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInVariable.OWNER); - TYPE_ANNOTATIONS = FieldOneToMany.create(type, NdTypeAnnotationInVariable.OWNER); + ANNOTATIONS = FieldList.create(type, NdAnnotation.type); + TYPE_ANNOTATIONS = FieldList.create(type, NdTypeAnnotation.type); type.done(); } @@ -59,12 +57,6 @@ public class NdVariable extends NdBinding { super(nd, bindingRecord); } - public NdVariable(NdBinding parent) { - super(parent.getNd()); - - PARENT.put(getNd(), this.address, parent); - } - public boolean hasVariableFlag(int toTest) { return (VARIABLE_FLAGS.get(getNd(), this.address) & toTest) != 0; } @@ -106,14 +98,22 @@ public class NdVariable extends NdBinding { TAG_BITS.put(getNd(), this.address, tagBits); } - public List<NdTypeAnnotationInVariable> getTypeAnnotations() { + public List<NdTypeAnnotation> getTypeAnnotations() { return TYPE_ANNOTATIONS.asList(getNd(), this.address); } - public List<NdAnnotationInVariable> getAnnotations() { + public List<NdAnnotation> getAnnotations() { return ANNOTATIONS.asList(getNd(), this.address); } + public NdAnnotation createAnnotation() { + return ANNOTATIONS.append(this.getNd(), this.getAddress()); + } + + public void allocateAnnotations(int length) { + ANNOTATIONS.allocate(getNd(), getAddress(), length); + } + public String toString() { try { StringBuilder result = new StringBuilder(); @@ -138,4 +138,12 @@ public class NdVariable extends NdBinding { return super.toString(); } } + + public NdTypeAnnotation createTypeAnnotation() { + return TYPE_ANNOTATIONS.append(getNd(), getAddress()); + } + + public void allocateTypeAnnotations(int length) { + TYPE_ANNOTATIONS.allocate(getNd(), getAddress(), length); + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdZipEntry.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdZipEntry.java index e0086ab193..4e4f82cf52 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdZipEntry.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdZipEntry.java @@ -11,25 +11,22 @@ package org.eclipse.jdt.internal.core.nd.java; import org.eclipse.jdt.internal.core.nd.Nd; -import org.eclipse.jdt.internal.core.nd.NdNode; +import org.eclipse.jdt.internal.core.nd.NdStruct; import org.eclipse.jdt.internal.core.nd.db.IString; -import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; import org.eclipse.jdt.internal.core.nd.field.FieldString; import org.eclipse.jdt.internal.core.nd.field.StructDef; /** * Stores a (non-class) file within a .jar file. */ -public class NdZipEntry extends NdNode { - public static final FieldManyToOne<NdResourceFile> JAR_FILE; +public class NdZipEntry extends NdStruct { public static final FieldString FILE_NAME; @SuppressWarnings("hiding") public static final StructDef<NdZipEntry> type; static { - type = StructDef.create(NdZipEntry.class, NdNode.type); - JAR_FILE = FieldManyToOne.createOwner(type, NdResourceFile.ZIP_ENTRIES); + type = StructDef.create(NdZipEntry.class, NdStruct.type); FILE_NAME = type.addString(); type.done(); @@ -39,14 +36,11 @@ public class NdZipEntry extends NdNode { super(nd, address); } - public NdZipEntry(NdResourceFile nd, String path) { - super(nd.getNd()); - - JAR_FILE.put(nd.getNd(), getAddress(), nd); - FILE_NAME.put(nd.getNd(), getAddress(), path); + public void setFilename(String filename) { + FILE_NAME.put(this.nd, this.address, filename); } public IString getFileName() { - return FILE_NAME.get(getNd(), getAddress()); + return FILE_NAME.get(this.nd, this.address); } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/MathUtils.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/MathUtils.java new file mode 100644 index 0000000000..25c94e8084 --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/MathUtils.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2017 Google, Inc and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Stefan Xenos (Google) - Initial implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.nd.util; + +public class MathUtils { + /** + * Rounds the one number up to the nearest multiple of another + * + * @param numberToRound + * number to round + * @param toMultipleOfThis the result will be divisible by this number + * @return the result will be the smallest multiple of toMultipleOfThis that is no smaller than numberToRound + */ + public static int roundUpToNearestMultiple(int numberToRound, int toMultipleOfThis) { + return ((numberToRound + toMultipleOfThis - 1) / toMultipleOfThis) * toMultipleOfThis; + } + + /** + * Rounds the one number up to the nearest multiple of another, where the second number is a power of two. + * + * @param numberToRound + * number to round + * @param aPowerOfTwo + * the result will be divisible by this + * @return the result will be the smallest multiple of aPowerOfTwo that is no smaller than numberToRound + */ + public static int roundUpToNearestMultipleOfPowerOfTwo(int numberToRound, int aPowerOfTwo) { + return ((numberToRound + aPowerOfTwo - 1) & ~(aPowerOfTwo - 1)); + } +} |