[JS IR] Optimize JS AST metadata memory consumption

This commit is contained in:
Alexander Korepanov
2022-08-25 17:14:39 +02:00
committed by Space
parent c747d0e742
commit 14b7db0187
3 changed files with 89 additions and 22 deletions
@@ -16,16 +16,30 @@
package org.jetbrains.kotlin.js.backend.ast; package org.jetbrains.kotlin.js.backend.ast;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor; import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor;
import org.jetbrains.kotlin.js.backend.ast.metadata.HasMetadata; import org.jetbrains.kotlin.js.backend.ast.metadata.HasMetadata;
import org.jetbrains.kotlin.js.backend.ast.metadata.HasMetadataImpl;
import org.jetbrains.kotlin.js.util.TextOutputImpl; import org.jetbrains.kotlin.js.util.TextOutputImpl;
import java.util.LinkedList; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
abstract class AbstractNode extends HasMetadata implements JsNode { abstract class AbstractNode implements JsNode, HasMetadata {
private List<JsComment> commentsBefore = null; private static class Internals extends HasMetadataImpl {
private List<JsComment> commentsAfter = null; List<JsComment> commentsBefore = null;
List<JsComment> commentsAfter = null;
}
private Internals internals = null;
private Internals getInternals() {
if (internals == null) {
internals = new Internals();
}
return internals;
}
@Override @Override
public String toString() { public String toString() {
@@ -48,21 +62,56 @@ abstract class AbstractNode extends HasMetadata implements JsNode {
@Override @Override
public List<JsComment> getCommentsBeforeNode() { public List<JsComment> getCommentsBeforeNode() {
return commentsBefore; return internals == null ? null : internals.commentsBefore;
} }
@Override @Override
public List<JsComment> getCommentsAfterNode() { public List<JsComment> getCommentsAfterNode() {
return commentsAfter; return internals == null ? null : internals.commentsAfter;
} }
@Override @Override
public void setCommentsBeforeNode(List<JsComment> comments) { public void setCommentsBeforeNode(List<JsComment> comments) {
commentsBefore = comments; getInternals().commentsBefore = comments;
} }
@Override @Override
public void setCommentsAfterNode(List<JsComment> comments) { public void setCommentsAfterNode(List<JsComment> comments) {
commentsAfter = comments; getInternals().commentsAfter = comments;
}
@Override
public <T> T getData(@NotNull String key) {
return getInternals().getData(key);
}
@Override
public <T> void setData(@NotNull String key, T value) {
getInternals().setData(key, value);
}
@Override
public boolean hasData(@NotNull String key) {
return internals != null && internals.hasData(key);
}
@Override
public void removeData(@NotNull String key) {
if (internals != null) {
internals.removeData(key);
}
}
@Override
public void copyMetadataFrom(@NotNull HasMetadata other) {
if (!other.getRawMetadata().isEmpty()) {
getInternals().copyMetadataFrom(other);
}
}
@NotNull
@Override
public Map<String, Object> getRawMetadata() {
return internals != null ? internals.getRawMetadata() : Collections.emptyMap();
} }
} }
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.js.backend.ast; package org.jetbrains.kotlin.js.backend.ast;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.js.backend.ast.metadata.HasMetadata; import org.jetbrains.kotlin.js.backend.ast.metadata.HasMetadataImpl;
import org.jetbrains.kotlin.js.common.Symbol; import org.jetbrains.kotlin.js.common.Symbol;
/** /**
* An abstract base class for named JavaScript objects. * An abstract base class for named JavaScript objects.
*/ */
public class JsName extends HasMetadata implements Symbol { public class JsName extends HasMetadataImpl implements Symbol {
@NotNull @NotNull
private final String ident; private final String ident;
@@ -16,27 +16,45 @@
package org.jetbrains.kotlin.js.backend.ast.metadata package org.jetbrains.kotlin.js.backend.ast.metadata
abstract class HasMetadata { interface HasMetadata {
private val metadata: MutableMap<String, Any?> = hashMapOf() fun <T> getData(key: String): T
fun <T> setData(key: String, value: T)
fun hasData(key: String): Boolean
fun removeData(key: String)
fun copyMetadataFrom(other: HasMetadata)
fun getRawMetadata(): Map<String, Any?>
}
fun <T> getData(key: String): T { open class HasMetadataImpl : HasMetadata {
@Suppress("UNCHECKED_CAST") private var metadataImpl: MutableMap<String, Any?>? = null
return metadata[key] as T
private val metadata: MutableMap<String, Any?>
get() = metadataImpl ?: hashMapOf<String, Any?>().also { metadataImpl = it }
final override fun <T> getData(key: String): T {
@Suppress("UNCHECKED_CAST") return metadata[key] as T
} }
fun <T> setData(key: String, value: T) { final override fun <T> setData(key: String, value: T) {
metadata[key] = value metadata[key] = value
} }
fun hasData(key: String): Boolean { final override fun hasData(key: String): Boolean {
return metadata.containsKey(key) return metadataImpl?.containsKey(key) == true
} }
fun removeData(key: String) { final override fun removeData(key: String) {
metadata.remove(key) metadataImpl?.remove(key)
} }
fun copyMetadataFrom(other: HasMetadata) { final override fun copyMetadataFrom(other: HasMetadata) {
metadata.putAll(other.metadata) val otherRawMetadata = other.getRawMetadata()
if (otherRawMetadata.isNotEmpty()) {
metadata.putAll(otherRawMetadata)
}
}
final override fun getRawMetadata(): Map<String, Any?> {
return metadataImpl ?: emptyMap()
} }
} }