[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;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor;
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 java.util.LinkedList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
abstract class AbstractNode extends HasMetadata implements JsNode {
private List<JsComment> commentsBefore = null;
private List<JsComment> commentsAfter = null;
abstract class AbstractNode implements JsNode, HasMetadata {
private static class Internals extends HasMetadataImpl {
List<JsComment> commentsBefore = null;
List<JsComment> commentsAfter = null;
}
private Internals internals = null;
private Internals getInternals() {
if (internals == null) {
internals = new Internals();
}
return internals;
}
@Override
public String toString() {
@@ -48,21 +62,56 @@ abstract class AbstractNode extends HasMetadata implements JsNode {
@Override
public List<JsComment> getCommentsBeforeNode() {
return commentsBefore;
return internals == null ? null : internals.commentsBefore;
}
@Override
public List<JsComment> getCommentsAfterNode() {
return commentsAfter;
return internals == null ? null : internals.commentsAfter;
}
@Override
public void setCommentsBeforeNode(List<JsComment> comments) {
commentsBefore = comments;
getInternals().commentsBefore = comments;
}
@Override
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;
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;
/**
* An abstract base class for named JavaScript objects.
*/
public class JsName extends HasMetadata implements Symbol {
public class JsName extends HasMetadataImpl implements Symbol {
@NotNull
private final String ident;
@@ -16,27 +16,45 @@
package org.jetbrains.kotlin.js.backend.ast.metadata
abstract class HasMetadata {
private val metadata: MutableMap<String, Any?> = hashMapOf()
interface HasMetadata {
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 {
@Suppress("UNCHECKED_CAST")
return metadata[key] as T
open class HasMetadataImpl : HasMetadata {
private var metadataImpl: MutableMap<String, Any?>? = null
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
}
fun hasData(key: String): Boolean {
return metadata.containsKey(key)
final override fun hasData(key: String): Boolean {
return metadataImpl?.containsKey(key) == true
}
fun removeData(key: String) {
metadata.remove(key)
final override fun removeData(key: String) {
metadataImpl?.remove(key)
}
fun copyMetadataFrom(other: HasMetadata) {
metadata.putAll(other.metadata)
final override fun copyMetadataFrom(other: HasMetadata) {
val otherRawMetadata = other.getRawMetadata()
if (otherRawMetadata.isNotEmpty()) {
metadata.putAll(otherRawMetadata)
}
}
final override fun getRawMetadata(): Map<String, Any?> {
return metadataImpl ?: emptyMap()
}
}