diff --git a/libraries/ReadMe.md b/libraries/ReadMe.md
index 3492aaebe1f..c74443858b1 100644
--- a/libraries/ReadMe.md
+++ b/libraries/ReadMe.md
@@ -6,7 +6,7 @@ This part of the project contains the sources of the following libraries:
- [kotlin-reflect](reflect), the library for full reflection support
- [kotlin-test](kotlin.test), the library for multiplatform unit testing
- [kotlin-annotations-jvm](tools/kotlin-annotations-jvm), the annotations to improve types in the Java code to look better when being consumed in the Kotlin code.
-
+
These libraries are built as a part of the [root](../) Gradle project.
@@ -16,13 +16,13 @@ These libraries are built as a part of the [root](../) Gradle project.
-This area of the project is the root for Maven build.
+This area of the project is the root for Maven build.
You can work with the maven modules of this maven project in IDEA from the [root IDEA project](../ReadMe.md#working-in-idea). After importing you'll be able to explore maven projects and run goals directly from IDEA with the instruments on the right sidebar.
### Building
-You need to install a recent (at least 3.3) [Maven](http://maven.apache.org/) distribution.
+You need to install a recent (at least 3.3) [Maven](http://maven.apache.org/) distribution.
Before building this Maven project you need to build and install the required artifacts built with Gradle to the local maven repository, by issuing the following command in the root project:
@@ -33,7 +33,7 @@ Before building this Maven project you need to build and install the required ar
This command assembles and puts the artifacts to the local maven repository to be used by the subsequent maven build.
See also [root ReadMe.md, section "Building"](../ReadMe.md#building).
-
+
Then you can build maven artifacts with Maven:
mvn install
@@ -42,3 +42,42 @@ If your maven build is failing with Out-Of-Memory errors, set JVM options for ma
MAVEN_OPTS="-Xmx2G"
+
+
+## Kotlin serialization Gradle Plugin
+
+To build it, first **build all the above** and then, `cd` to `tools/kotlin-serialization`
+and run `mvn install`
+
+So, all build sequence will look like:
+
+```bash
+# Assuming you are in the kotlin/libraries folder
+./gradlew build install
+mvn install
+cd tools/gradle-tools
+./gradlew clean install
+cd ../kotlin-serialization
+mvn install
+```
+
+When it is installed in local maven repository, you can add it as a dependency in buildscript classpath and apply it:
+
+```
+buildscript {
+
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1-SNAPSHOT"
+ classpath "org.jetbrains.kotlinx:kotlinx-serialization:1.1-SNAPSHOT"
+ }
+}
+
+apply plugin: 'kotlin'
+apply plugin: 'kotlin-serialization'
+
+```
diff --git a/libraries/tools/kotlin-serialization/pom.xml b/libraries/tools/kotlin-serialization/pom.xml
new file mode 100644
index 00000000000..1daf15055a5
--- /dev/null
+++ b/libraries/tools/kotlin-serialization/pom.xml
@@ -0,0 +1,158 @@
+
+
+
+ 4.0.0
+
+ 3.0.4
+ ${basedir}/../../../plugins/kotlin-serialization/kotlin-serialization-compiler/src
+ ${basedir}/src/main/kotlin
+ ${basedir}/src/main/resources
+ ${basedir}/target/src/main/kotlin
+ ${basedir}/target/resource
+
+
+
+ org.jetbrains.kotlin
+ kotlin-project
+ 1.1-SNAPSHOT
+ ../../pom.xml
+
+
+ org.jetbrains.kotlinx
+ kotlinx-serialization
+ jar
+
+ Serialization plugin for Gradle
+
+
+
+ jetbrains-utils
+ http://repository.jetbrains.com/utils
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ ${project.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-compiler-embeddable
+ ${project.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-gradle-plugin-api
+ ${project.version}
+ provided
+
+
+ org.jetbrains.kotlin
+ gradle-api
+ 2.2
+ provided
+
+
+
+
+ ${serialization.target-src}
+
+
+ ${serialization.target-resources}
+
+
+
+
+
+ maven-resources-plugin
+ 3.0.0
+
+
+ copy-sources
+ validate
+
+ copy-resources
+
+
+ ${serialization.target-src}
+
+
+ ${serialization.src}
+
+
+ ${serialization.gradle.plugin.src}
+
+
+
+
+
+ copy-resources
+ validate
+
+ copy-resources
+
+
+ ${serialization.target-resources}/META-INF
+
+
+ ${serialization.src}/META-INF
+
+
+ ${serialization.gradle.plugin.resources}/META-INF
+
+
+
+
+
+
+
+ com.google.code.maven-replacer-plugin
+ replacer
+ 1.5.3
+
+
+ generate-sources
+
+ replace
+
+
+
+
+
+ ${serialization.target-src}/**
+
+
+
+ (?<!\.)com\.intellij
+ org.jetbrains.kotlin.com.intellij
+
+
+
+
+
+ kotlin-maven-plugin
+ org.jetbrains.kotlin
+ ${project.version}
+
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ ${serialization.target-src}
+
+
+
+
+
+
+
+
diff --git a/libraries/tools/kotlin-serialization/src/main/kotlin/org/jetbrains/kotlinx/serialization/gradle/SerializationSubplugin.kt b/libraries/tools/kotlin-serialization/src/main/kotlin/org/jetbrains/kotlinx/serialization/gradle/SerializationSubplugin.kt
new file mode 100644
index 00000000000..1a8bf46916f
--- /dev/null
+++ b/libraries/tools/kotlin-serialization/src/main/kotlin/org/jetbrains/kotlinx/serialization/gradle/SerializationSubplugin.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlinx.serialization.gradle
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.artifacts.ResolvedArtifact
+import org.gradle.api.internal.AbstractTask
+import org.gradle.api.tasks.SourceSet
+import org.gradle.api.tasks.compile.AbstractCompile
+import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
+import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
+
+class SerializationGradleSubplugin : Plugin {
+ companion object {
+ fun isEnabled(project: Project) = project.plugins.findPlugin(SerializationGradleSubplugin::class.java) != null
+ }
+
+ override fun apply(project: Project) {
+ // nothing here
+ }
+}
+
+class SerializationKotlinGradleSubplugin : KotlinGradleSubplugin {
+ companion object {
+ val SERIALIZATION_GROUP_NAME = "org.jetbrains.kotlinx"
+ val SERIALIZATION_ARTIFACT_NAME = "kotlinx-serialization"
+ }
+
+ override fun isApplicable(project: Project, task: AbstractCompile) = SerializationGradleSubplugin.isEnabled(project)
+
+ override fun apply(
+ project: Project, kotlinCompile: AbstractCompile, javaCompile: AbstractCompile, variantData: Any?, androidProjectHandler: Any?, javaSourceSet: SourceSet?)
+ : List {
+ if (!SerializationGradleSubplugin.isEnabled(project)) return emptyList()
+ val options = mutableListOf()
+ // nothing here
+ return options
+ }
+
+ override fun getGroupName() = SERIALIZATION_GROUP_NAME
+ override fun getArtifactName() = SERIALIZATION_ARTIFACT_NAME
+ override fun getCompilerPluginId() = "org.jetbrains.kotlinx.serialization"
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-serialization/src/main/resources/META-INF/gradle-plugins/kotlin-serialization.properties b/libraries/tools/kotlin-serialization/src/main/resources/META-INF/gradle-plugins/kotlin-serialization.properties
new file mode 100644
index 00000000000..63de8aedfc5
--- /dev/null
+++ b/libraries/tools/kotlin-serialization/src/main/resources/META-INF/gradle-plugins/kotlin-serialization.properties
@@ -0,0 +1 @@
+implementation-class=org.jetbrains.kotlinx.serialization.gradle.SerializationGradleSubplugin
\ No newline at end of file
diff --git a/libraries/tools/kotlin-serialization/src/main/resources/META-INF/gradle-plugins/org.jetbrains.kotlin.plugin.serialization.properties b/libraries/tools/kotlin-serialization/src/main/resources/META-INF/gradle-plugins/org.jetbrains.kotlin.plugin.serialization.properties
new file mode 100644
index 00000000000..63de8aedfc5
--- /dev/null
+++ b/libraries/tools/kotlin-serialization/src/main/resources/META-INF/gradle-plugins/org.jetbrains.kotlin.plugin.serialization.properties
@@ -0,0 +1 @@
+implementation-class=org.jetbrains.kotlinx.serialization.gradle.SerializationGradleSubplugin
\ No newline at end of file
diff --git a/libraries/tools/kotlin-serialization/src/main/resources/META-INF/services/org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin b/libraries/tools/kotlin-serialization/src/main/resources/META-INF/services/org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
new file mode 100644
index 00000000000..29016e56c80
--- /dev/null
+++ b/libraries/tools/kotlin-serialization/src/main/resources/META-INF/services/org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
@@ -0,0 +1,17 @@
+#
+# Copyright 2010-2017 JetBrains s.r.o.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.jetbrains.kotlinx.serialization.gradle.SerializationKotlinGradleSubplugin
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/README.md b/plugins/kotlin-serialization/kotlin-serialization-compiler/README.md
new file mode 100644
index 00000000000..fde63f60ace
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/README.md
@@ -0,0 +1,30 @@
+# Kotlin serialization IDEA plugin
+
+Kotlin serialization plugin consists of three parts: a gradle compiler plugin, an IntelliJ plugin and a runtime library.
+This is the IDEA plugin. Gradle plugin can be found in `libraries` folder.
+
+Please note that this plugin currently works only for highlighting and resolving symbols, and it doesn't work with embedded IDEA compiler.
+To build any project with serialization within IDEA, you'll need to delegate all build actions to gradle:
+`File - Settings - Build, Execution, Deployment - Build Tools - Gradle - Runner -` tick `Delegate IDE build/run actions to gradle`.
+Maven and IntelliJ projects currently are not supported.
+
+## Building and usage
+
+### Prerequisites:
+Before all, follow the instructions from root README.md to download dependencies and build Kotlin compiler. (`ant -f update_dependencies.xml && ant dist`)
+
+**Plugin works only with IntelliJIDEA 2017.2 and higher.**
+
+Make sure you have latest dev version of Kotlin plugin installed:
+Open `Settings - Plugins - Browse Repositories... - Manage repositories` and add `https://teamcity.jetbrains.com/guestAuth/repository/download/Kotlin_master_CompilerAndPlugin_NoTests/.lastSuccessful/updatePlugins-IJ2017.2.xml`.
+Update Kotlin plugin from new repository.
+
+### With gradle:
+
+Run `./gradlew buildPlugin`.
+In IDEA, open `Settings - Plugins - Install plugin from disk...` and choose `build/distributions/Kotlin-serialization-0.1-SNAPSHOT.zip`
+
+### From within IDE (for development):
+
+Open whole Kotlin project. Choose run configuration `IDEA` and run it. You'll get a fresh copy of IDEA with Kotlin and Kotlin-serialization plugins built from sources.
+
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle b/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle
new file mode 100644
index 00000000000..2cdb3a7e0db
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle
@@ -0,0 +1,63 @@
+buildscript {
+ ext {
+ kotlin_root = "$rootDir/../../../"
+ distDir = file("$kotlin_root/dist")
+ bootstrapCompilerFile = file("$distDir/kotlin-compiler-for-maven.jar")
+ kotlin_version = "1.1.3"
+ }
+
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}"
+ }
+}
+
+plugins {
+ id "org.jetbrains.intellij" version "0.2.15"
+}
+
+group 'org.jetbrains.kotlinx'
+version '0.1-SNAPSHOT'
+
+
+apply plugin: 'kotlin'
+apply plugin: 'maven-publish'
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compileOnly "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"
+ compileOnly files(bootstrapCompilerFile.toString())
+}
+
+sourceSets {
+ main {
+ java {
+ srcDir 'src'
+ }
+ }
+}
+
+tasks.withType(org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile) {
+ compilerJarFile = bootstrapCompilerFile
+}
+
+jar {
+ from ('./src') {
+ include 'META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar'
+ include 'META-INF/plugin.xml'
+ }
+}
+
+
+apply plugin: 'org.jetbrains.intellij'
+
+intellij {
+ localPath "$kotlin_root/ideaSDK"
+ pluginName 'Kotlin-serialization'
+ downloadSources false
+}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/gradle/wrapper/gradle-wrapper.jar b/plugins/kotlin-serialization/kotlin-serialization-compiler/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000000..9553fe277ab
Binary files /dev/null and b/plugins/kotlin-serialization/kotlin-serialization-compiler/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/gradle/wrapper/gradle-wrapper.properties b/plugins/kotlin-serialization/kotlin-serialization-compiler/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000000..5c80a8d804b
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jul 31 13:14:07 MSK 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/gradlew b/plugins/kotlin-serialization/kotlin-serialization-compiler/gradlew
new file mode 100755
index 00000000000..4453ccea33d
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save ( ) {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/gradlew.bat b/plugins/kotlin-serialization/kotlin-serialization-compiler/gradlew.bat
new file mode 100644
index 00000000000..e95643d6a2c
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/kotlin-serialization-compiler.iml b/plugins/kotlin-serialization/kotlin-serialization-compiler/kotlin-serialization-compiler.iml
new file mode 100644
index 00000000000..0946ca030d9
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/kotlin-serialization-compiler.iml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/settings.gradle b/plugins/kotlin-serialization/kotlin-serialization-compiler/settings.gradle
new file mode 100644
index 00000000000..82367d8bce4
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/settings.gradle
@@ -0,0 +1 @@
+rootProject.name='serialization-plugin'
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml
new file mode 100644
index 00000000000..79a80811a0d
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml
@@ -0,0 +1,13 @@
+
+ Kotlin-serialization
+ org.jetbrains.kotlinx.serialization
+ 0.1-SNAPSHOT
+
+ org.jetbrains.kotlin
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
new file mode 100644
index 00000000000..1fb46ede97c
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
@@ -0,0 +1,17 @@
+#
+# Copyright 2010-2017 JetBrains s.r.o.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt
new file mode 100644
index 00000000000..028ebf1ae87
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlinx.serialization.compiler.backend.common
+
+import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
+import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
+import org.jetbrains.kotlin.psi.KtPureClassOrObject
+import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
+import org.jetbrains.kotlin.resolve.BindingContext
+
+/**
+ * @author Leonid Startsev
+ * sandwwraith@gmail.com
+ */
+
+abstract class SerializableCodegen(declaration: KtPureClassOrObject, private val bindingContext: BindingContext) {
+ protected val serializableDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
+ protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
+
+ fun generate() {
+ generateSyntheticInternalConstructor()
+ generateSyntheticMethods()
+ }
+
+ private fun generateSyntheticInternalConstructor() {
+ val constrDesc = KSerializerDescriptorResolver.createLoadConstructorDescriptor(serializableDescriptor, bindingContext)
+ generateInternalConstructor(constrDesc)
+ }
+
+ private fun generateSyntheticMethods() {
+ val func = KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(serializableDescriptor)
+ generateWriteSelfMethod(func)
+ }
+
+ protected abstract fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor)
+
+ protected abstract fun generateWriteSelfMethod(methodDescriptor: FunctionDescriptor)
+}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt
new file mode 100644
index 00000000000..732adf7bcc6
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlinx.serialization.compiler.backend.common
+
+import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberToGenerate
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlinx.serialization.compiler.resolve.*
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.psi.KtPureClassOrObject
+import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
+import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
+
+abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
+ protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
+ protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
+ protected val serialName: String = serializableDescriptor.fqNameUnsafe.asString()
+ protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
+ protected val orderedProperties = properties.serializableProperties
+
+ fun generate() {
+ check(properties.isExternallySerializable) { "Class ${serializableDescriptor.name} is not externally serializable" }
+ generateSerializableClassPropertyIfNeeded()
+ val save = generateSaveIfNeeded()
+ val load = generateLoadIfNeeded()
+ if (save || load)
+ generateSerialDesc()
+ }
+
+ protected abstract fun generateSerialDesc()
+
+ protected abstract fun generateSerializableClassProperty(property: PropertyDescriptor)
+
+ protected abstract fun generateSave(function: FunctionDescriptor)
+
+ protected abstract fun generateLoad(function: FunctionDescriptor)
+
+ private fun generateSerializableClassPropertyIfNeeded() {
+ val property = getPropertyToGenerate(serializerDescriptor, KSerializerDescriptorResolver.SERIAL_DESC_FIELD,
+ serializerDescriptor::checkSerializableClassPropertyResult)
+ ?: return
+ generateSerializableClassProperty(property)
+ }
+
+ private fun generateSaveIfNeeded(): Boolean {
+ val function = getMemberToGenerate(serializerDescriptor, KSerializerDescriptorResolver.SAVE,
+ serializerDescriptor::checkSaveMethodResult, serializerDescriptor::checkSaveMethodParameters)
+ ?: return false
+ generateSave(function)
+ return true
+ }
+
+ private fun generateLoadIfNeeded(): Boolean {
+ val function = getMemberToGenerate(serializerDescriptor, KSerializerDescriptorResolver.LOAD,
+ serializerDescriptor::checkLoadMethodResult, serializerDescriptor::checkLoadMethodParameters)
+ ?: return false
+ generateLoad(function)
+ return true
+ }
+
+ fun getPropertyToGenerate(
+ classDescriptor: ClassDescriptor,
+ name: String,
+ isReturnTypeOk: (KotlinType) -> Boolean
+ ): PropertyDescriptor? =
+ classDescriptor.unsubstitutedMemberScope.getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_BACKEND)
+ .singleOrNull { property ->
+ property.kind.let { kind -> kind == CallableMemberDescriptor.Kind.SYNTHESIZED || kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE } &&
+ property.modality != Modality.FINAL &&
+ property.returnType != null &&
+ isReturnTypeOk(property.returnType!!)
+ }
+}
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt
new file mode 100644
index 00000000000..539e866fc99
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
+
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.codegen.*
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.resolve.descriptorUtil.classId
+import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
+import org.jetbrains.kotlin.resolve.jvm.AsmTypes
+import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
+import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments
+import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperty
+import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
+import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
+import org.jetbrains.kotlinx.serialization.compiler.resolve.typeSerializer
+import org.jetbrains.org.objectweb.asm.Type
+import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
+
+/**
+ * @author Leonid Startsev
+ * sandwwraith@gmail.com
+ */
+
+internal val internalPackageFqName = FqName("kotlinx.serialization.internal")
+internal val descType = Type.getObjectType("kotlinx/serialization/KSerialClassDesc")
+internal val descImplType = Type.getObjectType("kotlinx/serialization/internal/SerialClassDescImpl")
+internal val kOutputType = Type.getObjectType("kotlinx/serialization/KOutput")
+internal val kInputType = Type.getObjectType("kotlinx/serialization/KInput")
+
+
+internal val kSerialSaverType = Type.getObjectType("kotlinx/serialization/KSerialSaver")
+internal val kSerialLoaderType = Type.getObjectType("kotlinx/serialization/KSerialLoader")
+internal val kSerializerType = Type.getObjectType("kotlinx/serialization/KSerializer")
+internal val kSerializerArrayType = Type.getObjectType("[Lkotlinx/serialization/KSerializer;")
+
+internal val serializationExceptionName = "kotlinx/serialization/SerializationException"
+internal val serializationExceptionMissingFieldName = "kotlinx/serialization/MissingFieldException"
+
+val OPT_MASK_TYPE: Type = Type.INT_TYPE
+val OPT_MASK_BITS = 32
+
+// compare with zero. if result == 0, property was not seen.
+internal fun InstructionAdapter.genValidateProperty(index: Int, bitMaskPos: (Int) -> Int) {
+ val addr = bitMaskPos(index)
+ load(addr, OPT_MASK_TYPE)
+ iconst(1 shl (index % OPT_MASK_BITS))
+ and(OPT_MASK_TYPE)
+ iconst(0)
+}
+
+internal fun InstructionAdapter.genExceptionThrow(exceptionClass: String, message: String) {
+ anew(Type.getObjectType(exceptionClass))
+ dup()
+ aconst(message)
+ invokespecial(exceptionClass, "", "(Ljava/lang/String;)V", false)
+ checkcast(Type.getObjectType("java/lang/Throwable"))
+ athrow()
+}
+
+fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen, propertyOwnerType: Type, ownerVar: Int) {
+ val propertyType = classCodegen.typeMapper.mapType(property.type)
+ val sti = getSerialTypeInfo(property, propertyType)
+ val useSerializer = stackValueSerializerInstance(classCodegen, sti)
+ if (!sti.unit) classCodegen.genPropertyOnStack(this, expressionCodegen.context, property.descriptor, propertyOwnerType, ownerVar)
+ invokevirtual(kOutputType.internalName,
+ "write" + sti.nn + (if (useSerializer) "Serializable" else "") + "ElementValue",
+ "(" + descType.descriptor + "I" +
+ (if (useSerializer) kSerialSaverType.descriptor else "") +
+ (if (sti.unit) "" else sti.type.descriptor) + ")V", false)
+}
+
+internal fun InstructionAdapter.buildInternalConstructorDesc(propsStartVar: Int, bitMaskBase: Int, codegen: ClassBodyCodegen, args: List): String {
+ val constructorDesc = StringBuilder("(I")
+ load(bitMaskBase, OPT_MASK_TYPE)
+ var propVar = propsStartVar
+ for (property in args) {
+ val propertyType = codegen.typeMapper.mapType(property.type)
+ constructorDesc.append(propertyType.descriptor)
+ load(propVar, propertyType)
+ propVar += propertyType.size
+ }
+ constructorDesc.append("Lkotlinx/serialization/SerializationConstructorMarker;)V")
+ aconst(null)
+ return constructorDesc.toString()
+}
+
+internal fun ImplementationBodyCodegen.generateMethod(function: FunctionDescriptor,
+ block: InstructionAdapter.(JvmMethodSignature, ExpressionCodegen) -> Unit) {
+ this.functionCodegen.generateMethod(OtherOrigin(this.myClass.psiOrParent, function), function,
+ object : FunctionGenerationStrategy.CodegenBased(this.state) {
+ override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
+ codegen.v.block(signature, codegen)
+ }
+ })
+}
+
+
+internal val enumSerializerId = ClassId(internalPackageFqName, Name.identifier("EnumSerializer"))
+internal val polymorphicSerializerId = ClassId(internalPackageFqName, Name.identifier("PolymorphicSerializer"))
+internal val referenceArraySerializerId = ClassId(internalPackageFqName, Name.identifier("ReferenceArraySerializer"))
+
+// returns false is property should not use serializer
+internal fun InstructionAdapter.stackValueSerializerInstance(codegen: ClassBodyCodegen, sti: SerialTypeInfo): Boolean {
+ val serializer = sti.serializer ?: return false
+ return stackValueSerializerInstance(codegen, sti.property.module, sti.property.type, serializer, this)
+}
+
+// returns false is cannot not use serializer
+// use iv == null to check only (do not emit serializer onto stack)
+internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, serializer: ClassDescriptor,
+ iv: InstructionAdapter?): Boolean {
+ if (serializer.kind == ClassKind.OBJECT) {
+ // singleton serializer -- just get it
+ if (iv != null)
+ StackValue.singleton(serializer, codegen.typeMapper).put(kSerializerType, iv)
+ return true
+ }
+ // serializer is not singleton object and shall be instantiated
+ val argSerializers = kType.arguments.map { projection ->
+ // bail out from stackValueSerializerInstance if any type argument is not serializable
+ val argSerializer = findTypeSerializer(module, projection.type, codegen.typeMapper.mapType(projection.type)) ?: return false
+ // check if it can be properly serialized with its args recursively
+ if (!stackValueSerializerInstance(codegen, module, projection.type, argSerializer, null))
+ return false
+ Pair(projection.type, argSerializer)
+ }
+ // new serializer if needed
+ iv?.apply {
+ val serializerType = codegen.typeMapper.mapClass(serializer)
+ // todo: support static factory methods for serializers for shorter bytecode
+ anew(serializerType)
+ dup()
+ // instantiate all arg serializers on stack
+ val signature = StringBuilder("(")
+ when (serializer.classId) {
+ enumSerializerId -> {
+ // a special way to instantiate enum -- need a enum KClass reference
+ aconst(codegen.typeMapper.mapType(kType))
+ AsmUtil.wrapJavaClassIntoKClass(this)
+ signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
+ }
+ referenceArraySerializerId -> {
+ // a special way to instantiate reference array serializer -- need an element java.lang.Class reference
+ aconst(codegen.typeMapper.mapType(kType.arguments[0].type, null, TypeMappingMode.GENERIC_ARGUMENT))
+ signature.append("Ljava/lang/Class;")
+ }
+ }
+ // all serializers get arguments with serializers of their generic types
+ argSerializers.forEach { (argType, argSerializer) ->
+ assert(stackValueSerializerInstance(codegen, module, argType, argSerializer, this))
+ // wrap into nullable serializer if argType is nullable
+ if (argType.isMarkedNullable) {
+ invokestatic("kotlinx/serialization/internal/BuiltinSerializersKt", "makeNullable",
+ "(" + kSerializerType.descriptor + ")" + kSerializerType.descriptor, false)
+
+ }
+ signature.append(kSerializerType.descriptor)
+ }
+ signature.append(")V")
+ // invoke constructor
+ invokespecial(serializerType.internalName, "", signature.toString(), false)
+ }
+ return true
+}
+
+//
+// ======= Serializers Resolving =======
+//
+
+
+class SerialTypeInfo(
+ val property: SerializableProperty,
+ val type: Type,
+ val nn: String,
+ val serializer: ClassDescriptor? = null,
+ val unit: Boolean = false
+)
+
+fun getSerialTypeInfo(property: SerializableProperty, type: Type): SerialTypeInfo {
+ when (type.sort) {
+ BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, CHAR -> {
+ val name = type.className
+ return SerialTypeInfo(property, type, Character.toUpperCase(name[0]) + name.substring(1))
+ }
+ ARRAY -> {
+ // check for explicit serialization annotation on this property
+ var serializer = property.serializer.toClassDescriptor
+ if (serializer == null) {
+ // no explicit serializer for this property. Select strategy by element type
+ when (type.elementType.sort) {
+ OBJECT, ARRAY -> {
+ // reference elements
+ serializer = property.module.findClassAcrossModuleDependencies(referenceArraySerializerId)
+ }
+ // primitive elements are not supported yet
+ }
+ }
+ return SerialTypeInfo(property, Type.getType("Ljava/lang/Object;"),
+ if (property.type.isMarkedNullable) "Nullable" else "", serializer)
+ }
+ OBJECT -> {
+ // no explicit serializer for this property. Check other built in types
+ if (KotlinBuiltIns.isString(property.type))
+ return SerialTypeInfo(property, Type.getType("Ljava/lang/String;"), "String")
+ if (KotlinBuiltIns.isUnit(property.type))
+ return SerialTypeInfo(property, Type.getType("Lkotlin/Unit;"), "Unit", unit = true)
+ // todo: more efficient enum support here, but only for enums that don't define custom serializer
+ // otherwise, it is a serializer for some other type
+ val serializer = findTypeSerializer(property.module, property.type, type)
+ return SerialTypeInfo(property, Type.getType("Ljava/lang/Object;"),
+ if (property.type.isMarkedNullable) "Nullable" else "", serializer)
+ }
+ else -> throw AssertionError("Unexpected sort for $type") // should not happen
+ }
+}
+
+fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType, asmType: Type): ClassDescriptor? {
+ return if (kType.requiresPolymorphism()) findPolymorphicSerializer(module)
+ else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type
+ ?: findStandardAsmTypeSerializer(module, asmType) // otherwise see if there is a standard serializer
+ ?: findStandardKotlinTypeSerializer(module, kType)
+}
+
+fun KotlinType.requiresPolymorphism(): Boolean {
+ return this.toClassDescriptor?.getSuperClassNotAny()?.isInternalSerializable == true
+ || this.toClassDescriptor?.modality == Modality.OPEN
+ || this.containsTypeProjectionsInTopLevelArguments() // List<*>
+}
+
+fun findPolymorphicSerializer(module: ModuleDescriptor): ClassDescriptor {
+ return requireNotNull(module.findClassAcrossModuleDependencies(polymorphicSerializerId)) { "Can't locate polymorphic serializer definition" }
+}
+
+fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
+ val classDescriptor = kType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
+ return if (classDescriptor.kind == ClassKind.ENUM_CLASS) module.findClassAcrossModuleDependencies(enumSerializerId) else null
+}
+
+fun findStandardAsmTypeSerializer(module: ModuleDescriptor, asmType: Type): ClassDescriptor? {
+ val name = asmType.standardSerializer ?: return null
+ return module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, Name.identifier(name)))
+}
+
+internal val org.jetbrains.org.objectweb.asm.Type.standardSerializer: String? get() = when (this.descriptor) {
+ "Lkotlin/Unit;" -> "UnitSerializer"
+ "Z", "Ljava/lang/Boolean;" -> "BooleanSerializer"
+ "B", "Ljava/lang/Byte;" -> "ByteSerializer"
+ "S", "Ljava/lang/Short;" -> "ShortSerializer"
+ "I", "Ljava/lang/Integer;" -> "IntSerializer"
+ "J", "Ljava/lang/Long;" -> "LongSerializer"
+ "F", "Ljava/lang/Float;" -> "FloatSerializer"
+ "D", "Ljava/lang/Double;" -> "DoubleSerializer"
+ "C", "Ljava/lang/Character;" -> "CharSerializer"
+ "Ljava/lang/String;" -> "StringSerializer"
+ "Ljava/util/Collection;", "Ljava/util/List;", "Ljava/util/ArrayList;" -> "ArrayListSerializer"
+ "Ljava/util/Set;", "Ljava/util/LinkedHashSet;" -> "LinkedHashSetSerializer"
+ "Ljava/util/HashSet;" -> "HashSetSerializer"
+ "Ljava/util/Map;", "Ljava/util/LinkedHashMap;" -> "LinkedHashMapSerializer"
+ "Ljava/util/HashMap;" -> "HashMapSerializer"
+ "Ljava/util/Map\$Entry;" -> "MapEntrySerializer"
+ else -> null
+}
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerialInfoCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerialInfoCodegenImpl.kt
new file mode 100644
index 00000000000..cf23f80708b
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerialInfoCodegenImpl.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
+
+import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.descriptors.annotations.Annotations
+import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
+import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
+import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
+import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
+import org.jetbrains.org.objectweb.asm.Opcodes
+import org.jetbrains.org.objectweb.asm.Type
+
+/**
+ * @author Leonid Startsev
+ * sandwwraith@gmail.com
+ */
+
+class SerialInfoCodegenImpl(val codegen: ImplementationBodyCodegen, val thisClass: ClassDescriptor, val bindingContext: BindingContext) {
+ val thisAsmType = codegen.typeMapper.mapClass(thisClass)
+
+ fun generate() {
+ val props = thisClass.unsubstitutedMemberScope.getDescriptorsFiltered().filterIsInstance()
+ generateFieldsAndSetters(props)
+ generateConstructor(props)
+ }
+
+ private fun generateFieldsAndSetters(props: List) {
+ props.forEach { prop ->
+ val propType = codegen.typeMapper.mapType(prop.type)
+ val propFieldName = "_" + prop.name.identifier
+ codegen.v.newField(OtherOrigin(codegen.myClass.psiOrParent), Opcodes.ACC_PRIVATE or Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC,
+ propFieldName, propType.descriptor, null, null)
+ val f = SimpleFunctionDescriptorImpl.create(thisClass, Annotations.EMPTY, prop.name, CallableMemberDescriptor.Kind.SYNTHESIZED, thisClass.source)
+ f.initialize(null, thisClass.thisAsReceiverParameter, emptyList(), emptyList(), prop.type, Modality.FINAL, Visibilities.PUBLIC)
+ codegen.generateMethod(f, { _, _ ->
+ load(0, thisAsmType)
+ getfield(thisAsmType.internalName, propFieldName, propType.descriptor)
+ areturn(propType)
+ })
+ }
+ }
+
+ private fun generateConstructor(props: List) {
+ val constr = ClassConstructorDescriptorImpl.createSynthesized(
+ thisClass,
+ Annotations.EMPTY,
+ false,
+ thisClass.source
+ )
+ val args = mutableListOf()
+ var i = 0
+ props.forEach { prop ->
+ args.add(ValueParameterDescriptorImpl(constr, null, i++, Annotations.EMPTY, prop.name, prop.type, false, false, false, null, constr.source))
+ }
+ constr.initialize(
+ args,
+ Visibilities.PUBLIC
+ )
+
+ constr.returnType = thisClass.defaultType
+
+ codegen.generateMethod(constr, { _, _ ->
+ load(0, thisAsmType)
+ invokespecial("java/lang/Object", "", "()V", false)
+ props.forEachIndexed { index, prop ->
+ val propType = codegen.typeMapper.mapType(prop.type)
+ val propFieldName = "_" + prop.name.identifier
+ load(0, thisAsmType)
+ load(index + 1, propType)
+ putfield(thisAsmType.internalName, propFieldName, propType.descriptor)
+ }
+ areturn(Type.VOID_TYPE)
+ })
+ }
+
+ companion object {
+ fun generateSerialInfoImplBody(codegen: ImplementationBodyCodegen) {
+ val thisClass = codegen.descriptor
+ if (KSerializerDescriptorResolver.isSerialInfoImpl(thisClass))
+ SerialInfoCodegenImpl(codegen, thisClass, codegen.bindingContext).generate()
+ }
+ }
+}
+
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt
new file mode 100644
index 00000000000..13214487fdd
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
+
+import org.jetbrains.kotlin.codegen.CompilationException
+import org.jetbrains.kotlin.codegen.ExpressionCodegen
+import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
+import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.descriptors.PropertyDescriptor
+import org.jetbrains.kotlin.psi.KtAnonymousInitializer
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
+import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
+import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
+import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
+import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperty
+import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
+import org.jetbrains.org.objectweb.asm.Label
+import org.jetbrains.org.objectweb.asm.Type
+import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
+
+/**
+ * @author Leonid Startsev
+ * sandwwraith@gmail.com
+ */
+
+class SerializableCodegenImpl(
+ private val classCodegen: ImplementationBodyCodegen,
+ serializableClass: ClassDescriptor
+) : SerializableCodegen(classCodegen.myClass, classCodegen.bindingContext) {
+
+ private val thisAsmType = classCodegen.typeMapper.mapClass(serializableDescriptor)
+
+ companion object {
+ fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
+ val serializableClass = codegen.descriptor
+ if (serializableClass.isInternalSerializable)
+ SerializableCodegenImpl(codegen, serializableClass).generate()
+ }
+ }
+
+ private val descToProps = classCodegen.myClass.declarations
+ .asSequence()
+ .filterIsInstance()
+ .associateBy { classCodegen.bindingContext[BindingContext.VARIABLE, it]!! }
+
+ private val paramsToProps: Map = classCodegen.myClass.primaryConstructorParameters
+ .asSequence()
+ .filter { it.hasValOrVar() }
+ .associateBy { classCodegen.bindingContext[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it]!! }
+
+ private fun getProp(prop: SerializableProperty) = descToProps[prop.descriptor]
+ private fun getParam(prop: SerializableProperty) = paramsToProps[prop.descriptor]
+ private val SerializableProperty.asmType get() = classCodegen.typeMapper.mapType(this.type)
+
+ override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) {
+ classCodegen.generateMethod(constructorDescriptor, { sig, expr -> doGenerateConstructorImpl(expr) })
+ }
+
+ override fun generateWriteSelfMethod(methodDescriptor: FunctionDescriptor) {
+ classCodegen.generateMethod(methodDescriptor, { sig, expr -> doGenerateWriteSelf(expr, sig) })
+ }
+
+ private fun InstructionAdapter.doGenerateWriteSelf(exprCodegen: ExpressionCodegen, signature: JvmMethodSignature) {
+ val thisI = 0
+ val outputI = 1
+ val serialDescI = 2
+// val offsetI = 3
+
+ val superClass = serializableDescriptor.getSuperClassOrAny()
+ val myPropsStart: Int
+ if (superClass.isInternalSerializable) {
+ myPropsStart = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties.size
+ //super.writeSelf(output, serialDesc)
+ load(thisI, thisAsmType)
+ load(outputI, kOutputType)
+ load(serialDescI, descType)
+ invokespecial(classCodegen.typeMapper.mapType(superClass).internalName, signature.asmMethod.name, signature.asmMethod.descriptor, false)
+ }
+ else {
+ myPropsStart = 0
+ // offset = 0
+// iconst(0)
+ }
+
+ for (i in myPropsStart until properties.serializableProperties.size) {
+ val property = properties[i]
+ // output.writeXxxElementValue (desc, index, value)
+ load(outputI, kOutputType)
+ load(serialDescI, descType)
+ iconst(i)
+ genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI)
+ }
+
+ areturn(Type.VOID_TYPE)
+ }
+
+ private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) {
+ val seenMask = 1
+// var propOffset = 2
+ var (propIndex, propOffset) = generateSuperSerializableCall(2)
+ for (i in propIndex until properties.serializableProperties.size) {
+ val prop = properties[i]
+ if (prop.transient) {
+ if (!needInitProperty(prop)) throw CompilationException("transient without default value", null, null)
+ exprCodegen.genInitProperty(prop)
+ propOffset += prop.asmType.size
+ continue
+ }
+ val propType = prop.asmType
+ if (!prop.optional) {
+ // primary were validated before constructor call
+ genValidateProperty(i) { seenMask }
+ val nonThrowLabel = Label()
+ ificmpne(nonThrowLabel)
+ genExceptionThrow(serializationExceptionMissingFieldName, prop.name)
+ visitLabel(nonThrowLabel)
+ // setting field
+ load(0, thisAsmType)
+ load(propOffset, propType)
+ putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
+ }
+ else {
+ genValidateProperty(i) { seenMask }
+ val setLbl = Label()
+ val nextLabel = Label()
+ ificmpeq(setLbl)
+ // setting field
+ // todo: validate nullability
+ load(0, thisAsmType)
+ load(propOffset, propType)
+ putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
+ goTo(nextLabel)
+ visitLabel(setLbl)
+ // setting defaultValue
+ exprCodegen.genInitProperty(prop)
+ visitLabel(nextLabel)
+ }
+ propOffset += prop.asmType.size
+ }
+
+ // these properties required to be manually invoked, because they are not in serializableProperties
+ val serializedProps = properties.serializableProperties.map { it.descriptor }
+
+ (descToProps - serializedProps)
+ .forEach { _, prop -> classCodegen.initializeProperty(exprCodegen, prop) }
+ (paramsToProps - serializedProps)
+ .forEach { t, u -> exprCodegen.genInitParam(t, u) }
+
+ // init blocks
+ // todo: proper order with other initializers
+ classCodegen.myClass.declarations
+ .asSequence()
+ .filterIsInstance()
+ .mapNotNull { it.body }
+ .forEach { exprCodegen.gen(it, Type.VOID_TYPE) }
+ areturn(Type.VOID_TYPE)
+ }
+
+ private fun InstructionAdapter.generateSuperSerializableCall(propStartVar: Int): Pair {
+ val superClass = serializableDescriptor.getSuperClassOrAny()
+ val superType = classCodegen.typeMapper.mapType(superClass).internalName
+
+ load(0, thisAsmType)
+
+ if (!superClass.isInternalSerializable) {
+ require(superClass.constructors.firstOrNull { it.valueParameters.isEmpty() } != null) { "Non-serializable parent of serializable class must have no arg constructor" }
+
+ // call
+ invokespecial(superType, "", "()V", false)
+ return 0 to propStartVar
+ }
+ else {
+ val superProps = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties
+ val creator = buildInternalConstructorDesc(propStartVar, 1, classCodegen, superProps)
+ invokespecial(superType, "", creator, false)
+ return superProps.size to propStartVar + superProps.sumBy { it.asmType.size }
+ }
+ }
+
+ private fun needInitProperty(prop: SerializableProperty) = getProp(prop)?.let { classCodegen.shouldInitializeProperty(it) }
+ ?: getParam(prop)?.hasDefaultValue() ?: throw IllegalStateException()
+
+ private fun ExpressionCodegen.genInitProperty(prop: SerializableProperty)
+ = getProp(prop)?.let {
+ classCodegen.initializeProperty(this, it)
+ }
+ ?: getParam(prop)?.let {
+ this.v.load(0, thisAsmType)
+ this.gen(it.defaultValue, prop.asmType)
+ this.v.putfield(thisAsmType.internalName, prop.name, prop.asmType.descriptor)
+ }
+ ?: throw IllegalStateException()
+
+ private fun ExpressionCodegen.genInitParam(prop: PropertyDescriptor, param: KtParameter) {
+ this.v.load(0, thisAsmType)
+ val mapType = classCodegen.typeMapper.mapType(prop.type)
+ this.gen(param.defaultValue, mapType)
+ this.v.putfield(thisAsmType.internalName, prop.name.asString(), mapType.descriptor)
+ }
+}
\ No newline at end of file
diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt
new file mode 100644
index 00000000000..831ca90ac62
--- /dev/null
+++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
+
+import org.jetbrains.kotlin.codegen.CompilationException
+import org.jetbrains.kotlin.codegen.ExpressionCodegen
+import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
+import org.jetbrains.kotlin.codegen.StackValue
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.descriptors.PropertyDescriptor
+import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
+import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
+import org.jetbrains.kotlin.psi.ValueArgument
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
+import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor
+import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorBySerializer
+import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
+import org.jetbrains.org.objectweb.asm.Label
+import org.jetbrains.org.objectweb.asm.Opcodes.*
+import org.jetbrains.org.objectweb.asm.Type
+import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
+
+class SerializerCodegenImpl(
+ private val codegen: ImplementationBodyCodegen,
+ serializableClass: ClassDescriptor
+) : SerializerCodegen(codegen.myClass, codegen.bindingContext) {
+
+
+ private val serialDescField = "\$\$serialDesc"
+
+ private val serializerAsmType = codegen.typeMapper.mapClass(codegen.descriptor)
+ private val serializableAsmType = codegen.typeMapper.mapClass(serializableClass)
+
+ companion object {
+ fun generateSerializerExtensions(codegen: ImplementationBodyCodegen) {
+ val serializableClass = getSerializableClassDescriptorBySerializer(codegen.descriptor) ?: return
+ SerializerCodegenImpl(codegen, serializableClass).generate()
+ }
+ }
+
+ override fun generateSerialDesc() {
+ codegen.v.newField(OtherOrigin(codegen.myClass.psiOrParent), ACC_PRIVATE or ACC_STATIC or ACC_FINAL or ACC_SYNTHETIC,
+ serialDescField, descType.descriptor, null, null)
+ // todo: lazy initialization of $$serialDesc that is performed only when save/load is invoked first time
+ val expr = codegen.createOrGetClInitCodegen()
+ with(expr.v) {
+ val classDescVar = 0
+ anew(descImplType)
+ dup()
+ aconst(serialName)
+ invokespecial(descImplType.internalName, "", "(Ljava/lang/String;)V", false)
+ store(classDescVar, descImplType)
+ for (property in orderedProperties) {
+ if (property.transient) continue
+ load(classDescVar, descImplType)
+ aconst(property.name)
+ invokevirtual(descImplType.internalName, "addElement", "(Ljava/lang/String;)V", false)
+ // pushing annotations
+ for (annotationClass in property.annotations) {
+ load(classDescVar, descImplType)
+ val implType = codegen.typeMapper.mapType(annotationClass).internalName + "\$" + KSerializerDescriptorResolver.IMPL_NAME.identifier
+ // new Annotation$Impl(...)
+ anew(Type.getObjectType(implType))
+ dup()
+ val sb = StringBuilder("(")
+ val args: List = (property.descriptor.annotations.findAnnotation(annotationClass.fqNameSafe) as? LazyAnnotationDescriptor)?.annotationEntry?.valueArguments.orEmpty()
+ val consParams = annotationClass.unsubstitutedPrimaryConstructor?.valueParameters.orEmpty()
+ if (args.size != consParams.size) throw IllegalArgumentException("Can't use arguments with defaults for serializable annotations yet")
+ for (i in consParams.indices) {
+ val decl = args[i]
+ val desc = consParams[i]
+ val valAsmType = codegen.typeMapper.mapType(desc.type)
+ expr.gen(decl.getArgumentExpression(), valAsmType)
+ sb.append(valAsmType.descriptor)
+ }
+ sb.append(")V")
+ invokespecial(implType, "", sb.toString(), false)
+ // serialDesc.pushAnnotation(..)
+ invokevirtual(descImplType.internalName, "pushAnnotation", "(Ljava/lang/annotation/Annotation;)V", false)
+ }
+ }
+ load(classDescVar, descImplType)
+ putstatic(serializerAsmType.internalName, serialDescField, descType.descriptor)
+ }
+ }
+
+ private fun InstructionAdapter.serialCLassDescToLocalVar(classDescVar: Int) {
+ getstatic(serializerAsmType.internalName, serialDescField, descType.descriptor)
+ store(classDescVar, descType)
+ }
+
+ override fun generateSerializableClassProperty(property: PropertyDescriptor) {
+ codegen.generateMethod(property.getter!!) { signature, expressionCodegen ->
+ getstatic(serializerAsmType.internalName, serialDescField, descType.descriptor)
+ areturn(descType)
+ }
+ }
+
+ override fun generateSave(
+ function: FunctionDescriptor
+ ) {
+ codegen.generateMethod(function) { signature, expressionCodegen ->
+ // fun save(output: KOutput, obj : T)
+ val outputVar = 1
+ val objVar = 2
+ val descVar = 3
+ serialCLassDescToLocalVar(descVar)
+ val objType = signature.valueParameters[1].asmType
+ // output = output.writeBegin(classDesc, new KSerializer[0])
+ load(outputVar, kOutputType)
+ load(descVar, descType)
+ iconst(0)
+ newarray(kSerializerType) // todo: use some predefined empty array
+ invokevirtual(kOutputType.internalName, "writeBegin",
+ "(" + descType.descriptor + kSerializerArrayType.descriptor +
+ ")" + kOutputType.descriptor, false)
+ store(outputVar, kOutputType)
+ if (serializableDescriptor.isInternalSerializable) {
+ // call obj.write$Self(output, classDesc)
+ load(objVar, objType)
+ load(outputVar, kOutputType)
+ load(descVar, descType)
+ invokevirtual(objType.internalName, KSerializerDescriptorResolver.WRITE_SELF_NAME.asString(),
+ "(${kOutputType.descriptor}${descType.descriptor})V", false)
+ }
+ else {
+ // loop for all properties
+ val labeledProperties = orderedProperties.filter { !it.transient }
+ for (index in labeledProperties.indices) {
+ val property = labeledProperties[index]
+ if (property.transient) continue
+ // output.writeXxxElementValue(classDesc, index, value)
+ load(outputVar, kOutputType)
+ load(descVar, descType)
+ iconst(index)
+ genKOutputMethodCall(property, codegen, expressionCodegen, objType, objVar)
+ }
+ }
+ // output.writeEnd(classDesc)
+ load(outputVar, kOutputType)
+ load(descVar, descType)
+ invokevirtual(kOutputType.internalName, "writeEnd",
+ "(" + descType.descriptor + ")V", false)
+ // return
+ areturn(Type.VOID_TYPE)
+ }
+ }
+
+ override fun generateLoad(
+ function: FunctionDescriptor
+ ) {
+ codegen.generateMethod(function) { signature, expressionCodegen ->
+ // fun load(input: KInput): T
+ val inputVar = 1
+ val descVar = 2
+ val indexVar = 3
+ val readAllVar = 4
+ val bitMaskBase = 5
+ val blocksCnt = orderedProperties.size / OPT_MASK_BITS + 1
+ fun bitMaskOff(i: Int) = bitMaskBase + (i / OPT_MASK_BITS) * OPT_MASK_TYPE.size
+ val propsStartVar = bitMaskBase + OPT_MASK_TYPE.size * blocksCnt
+ serialCLassDescToLocalVar(descVar)
+ // boolean readAll = false
+ iconst(0)
+ store(readAllVar, Type.BOOLEAN_TYPE)
+ // initialize bit mask
+ for (i in 0 until blocksCnt) {
+ //int bitMaskN = 0
+ iconst(0)
+ store(bitMaskBase + i * OPT_MASK_TYPE.size, OPT_MASK_TYPE)
+ }
+ // initialize all prop vars
+ var propVar = propsStartVar
+ for (property in orderedProperties) {
+ val propertyType = codegen.typeMapper.mapType(property.type)
+ stackValueDefault(propertyType)
+ store(propVar, propertyType)
+ propVar += propertyType.size
+ }
+ // input = input.readBegin(classDesc, new KSerializer[0])
+ load(inputVar, kInputType)
+ load(descVar, descType)
+ iconst(0)
+ newarray(kSerializerType) // todo: use some predefined empty array
+ invokevirtual(kInputType.internalName, "readBegin",
+ "(" + descType.descriptor + kSerializerArrayType.descriptor +
+ ")" + kInputType.descriptor, false)
+ store(inputVar, kInputType)
+ // readElement: int index = input.readElement(classDesc)
+ val readElementLabel = Label()
+ visitLabel(readElementLabel)
+ load(inputVar, kInputType)
+ load(descVar, descType)
+ invokevirtual(kInputType.internalName, "readElement",
+ "(" + descType.descriptor + ")I", false)
+ store(indexVar, Type.INT_TYPE)
+ // switch(index)
+ val labeledProperties = orderedProperties.filter { !it.transient }
+ val readAllLabel = Label()
+ val readEndLabel = Label()
+ val labels = arrayOfNulls