Commit Graph

4188 Commits

Author SHA1 Message Date
Dmitry Petrov 4365084645 Lookup for local variables taking into account uninitialized this
Consider a context with uninitialized this, e.g.:

  fun foo() {
    val x = "..."
    class Local(y: String) : Base(L@{ x + y })
  }

Lambda 'L' is an argument of a super class constructor call.
Here 'this@Local' is not initialized yet. Thus local variables captured
in 'Local' can't be used. Instead, they should be captured by lambda 'L'
itself.

Note that lambda 'L' sees both 'x' and 'y' as local variables that
should be captured.

When in context with uninitialized this (generating arguments for super
type constructor or delegating constructor call), and a variable in
question is not found in the current context, use enclosing local lookup
to determine whether a local variable should be captured by a closure.
2017-11-14 09:33:28 +03:00
Dmitry Petrov ff0a2562e0 Minor: LocalLookup: lookupLocal -> isLocal 2017-11-14 09:33:28 +03:00
Dmitry Petrov 2d56837409 Minor: answer -> capturedVariable 2017-11-14 09:33:28 +03:00
Dmitry Petrov 47b59496da Minor: CodegenContext.isContextWithUninitializedThis() 2017-11-14 09:33:28 +03:00
Dmitry Petrov bbb0389c51 Fix determining enclosing class for closure
Enclosing class for closure is a class whose instance is captured by
closure as an outer 'this', and stored in a field 'this$0'.
Usually enclosing class for closure is an immediate outer class,
including classes for nested closures. For example:

  class C {
    fun foo() {}
    val example1 = L1@ { foo() }
    // Enclosing class for lambda 'L1' is 'C'
    val example2 = L2a@ { L2b@ { foo() } }
    // Enclosing class for nested lambda 'L2b'
    // is a closure class for outer lambda 'L2a'
  }

However, if the closure is created in a super type constructor call for
the outer class, corresponding instance is considered "uninitialized",
and can't be used as a proper class instance, and can't be referenced:
corresponding code is rejected by front-end.

  class Outer {
    fun foo() {}
    inner class Inner : Base(L3@ { foo() })
    // Enclosing class for lambda 'L3' is 'Outer',
    // because 'Inner' is uninitialized in super type constructor call.
  }

In CodegenAnnotatingVisitor, we maintain a stack of currently
uninitialized classes, and chose enclosing class for closure
as an inner-most surrounding class with initialized instance.

When generating code for this or outer class instance, we skip
contexts corresponding to classes with uninitialized instances.

This fixes a number of bytecode verification errors caused by incorrect
enclosing class for closure.

 #KT-4174 Fixed Target versions 1.2.20
 #KT-13454 Fixed Target versions 1.2.20
 #KT-14148 Fixed Target versions 1.2.20
2017-11-14 09:33:28 +03:00
Dmitry Petrov ac761a03c5 Minor: calleeContainingClass -> thisOrOuterClass 2017-11-14 09:33:28 +03:00
Dmitry Petrov 92e0ea2553 Minor: CodegenContext utils 2017-11-14 09:33:28 +03:00
Mikhael Bogdanov dff6e943bb Always do stack spilling during inline cause of dex problem
Dex issue: https://issuetracker.google.com/issues/68796377

  #KT-20844 Fixed
2017-11-13 16:50:24 +01:00
Mikhael Bogdanov ad80d1239f Properly process special names for local function in LocalLookup 2017-11-10 13:42:40 +01:00
Mikhael Bogdanov 416392bb74 Don't propagate reified markers for special enum functions
#KT-18254 Fixed
2017-11-08 15:35:44 +01:00
Mikhael Bogdanov 800cc63347 Remove external finally block interval on splitting during inline
#KT-20433 Fixed
2017-11-08 15:35:43 +01:00
Pavel V. Talanov 9e061d3bbb Fix light class exception on empty multifile facade
Fix generating multifile facade with all members private (in bytecode)
leading to delegate not being generated for corresponding light class

 #KT-20966 Fixed
2017-11-03 16:44:53 +03:00
Alexander Udalov 56a51c1d22 Do not treat annotation classes as interfaces in bridges codegen
From Kotlin's point of view, everything in annotation classes is
non-abstract. A class inheriting from an annotation has a non-abstract
fake override for each property of the annotation class constructor. But
because members of annotation classes themselves were considered as
abstract in the bridge-generating code (see
DescriptorBasedFunctionHandle.isAbstract), there was a situation where a
concrete fake override has only one declaration among overridden
descriptors and it was abstract. This situation is invalid (a concrete
fake override must have exactly one concrete super-declaration),
therefore an exception was thrown.

The fix is to avoid considering annotation class members abstract for
the purposes of bridge generation. It's reasonably safe because no
bridges should be ever generated for annotation subclasses anyway,
because annotations can only have members with simple return types
(final and non-generic).

Note that in KT-19928, the problem is reproducible because of an
incorrect "inexact analysis" in light classes where "Target" is resolved
to an annotation class kotlin.annotation.Target. This behavior of the
analysis in light classes seems to do no harm otherwise, so it's not a
goal of this commit to change anything in that regard

 #KT-19928 Fixed
2017-11-02 14:02:09 +01:00
Ilmir Usmanov 817f79520a Implement coroutineContext intrinsic
This intrinsic allows coroutine to access its context without suspention
and, furthermore, disabling tail-call optimization.
KT-17609: Fixed
2017-11-02 12:45:24 +03:00
Dmitry Petrov cbef372e69 Recapture shared variables when calling local class constructor
When a local function or class A creates an instance of a local class B
capturing an outer variable 'x', it should use ref for 'x', but not the
value of 'x'.
2017-10-30 15:19:13 +03:00
Dmitry Petrov 7a156e4407 Give unique names to fields for captured local functions
When a local function is captured, corresponding field accesses are
later transformed by the inliner. It doesn't have enough information to
restore the original semantics completely, so it has to rely on field
names. Local functions can be overloaded or can have names matching
local variable names, in both cases we generated fields with the same
name for captured values.

Now, we use the same '$<local-class-number>' suffix for field names for
local functions as it is present in the corresponding local class name.
This allows to distinguish captured local functions from captured local
variables and between different overloads of a function with the same
name.

 #KT-19827 Fixed
 #KT-18639 Fixed
2017-10-30 15:19:13 +03:00
Alexander Udalov 2c4e023cba Minor, use extracted variable in LateinitIntrinsics.kt 2017-10-27 18:06:43 +02:00
Dmitry Petrov 28535a57d8 Fix issues with enum entry self-reference
Given a singleton class 'S' with possibly uninitialized static instance
(enum entry, interface companion object).
Such singleton can be referenced by name, or as an explicit or implicit
'this'.
For a given singleton class 'S' we
either use 'this@S' from context (local or captured),
or 'S' as a static instance.

Local or captured 'this@S' should be used if:
  - we are in the constructor for 'S',
    and corresponding instance is initialized
        by super or delegating constructor call;
  - we are in any other member of 'S' or any of its inner classes.

Otherwise, a static instance should be used.
2017-10-26 16:11:58 +03:00
Dmitry Petrov 2b924f44d8 Generate assertions for expressions with enhanced nullability
If an expression with type annotated with @EnhancedNullability is used
as a function expression body, or property initializer, or variable
initializer, and corresponding type can not contain null,
generate nullability assertions for this expression.
2017-10-25 12:30:32 +03:00
Dmitry Petrov f23dfdc0ac Mark operands of POP2 as don't touch in unused expression elimination
Fixes KT-20879.
2017-10-24 15:38:15 +03:00
Alexander Udalov bafc75ade4 Fix isInitialized receiver generation for empty LHS
#KT-20774 Fixed
2017-10-24 11:26:01 +02:00
Yan Zhulanow 43a1162b25 Evaluate: Fix for evaluating local variables captured by an inline function (KT-17514) 2017-10-16 21:25:44 +03:00
Alexander Udalov 8b0b334601 Extract shouldWritePreReleaseFlag(), use in JS as well as JVM
Fix the difference in behavior between JS and JVM
2017-10-16 15:09:36 +02:00
Alexander Udalov 0510c553c3 Mark class files as pre-release if language version > LATEST_STABLE
#KT-20547 Fixed
2017-10-16 15:09:36 +02:00
Alexander Udalov 5f775497e2 Add Kotlin package FQ name to kotlin.Metadata
It might differ from the JVM package FQ name if the JvmPackageName
annotation is used. This will be useful for faster indexing in the IDE
and for reflection
2017-10-13 16:23:07 +02:00
Dmitry Petrov 16b7bece46 Fix constant expression inlining logic
Constant expressions are inlined if they do not depend on non-inlineable
vals.
Java constants are always inlined.
Kotlin constants are inlined in LV 1.1+.
2017-10-13 17:01:42 +03:00
Yan Zhulanow 5acc992956 Disable uninitialized object copying checks for Parcelable writeToParcel() to createFromParcel() 2017-10-13 16:35:42 +03:00
Mikhael Bogdanov b73be50e5b Move object initialization from <init> to <clinit>
Codegen generates static backing fields for object properties.
  They are initialized in class constructor but some of them are final static
  and such access is prohibited in specification but it's allowed in
  java bytecode <= 1.8. Such access in 1.9 bytecode cause
  "IllegalAccessError: Update to static final field Object.INSTANCE
  attempted from a different method (<init>) than the initializer method <clinit>"

  Added additional hidden field in interface companion to pass out
  companion instance from <clinit>.

 #KT-15894 Fixed
2017-10-11 19:20:24 +03:00
Mikhael Bogdanov a79c2bf999 Write script descriptor type to ASM_TYPE slice
#KT-20707 Fixed
2017-10-10 17:01:23 +02:00
Dmitry Petrov 26136cd0fe Check constness of 'apiVersionIsAtLeast' arguments 2017-10-10 09:04:51 +03:00
Dmitry Petrov 23d8b4cefe Do not run CCE if there were no apiVersionIsAtLeast calls 2017-10-10 09:04:51 +03:00
Dmitry Petrov fd16035bbd API version calls preprocessing, 1st passing test 2017-10-10 09:04:51 +03:00
Dmitry Petrov 4e7c4c3976 Minor: inline single use of 'analyzeMethodNodeBeforeInline' 2017-10-10 09:04:51 +03:00
Dmitry Petrov a89f978597 Provide configurable constructor call normalization
Three modes:

- 'disable' (default): normalize constructor calls in coroutines only
  (required because uninitialized objects can't be stored in fields),
  don't insert additional code for forced class initialization;

- 'enable': normalize constructor calls,
  don't insert additional code for forced class initialization;

- 'preserve-class-initialization': normalize constructor calls,
  insert additional code for forced class initialization.
2017-10-10 08:49:19 +03:00
Dmitry Petrov e71090ae4c Spill stack for inline functions only if it's required
Stack should be spilled before inline function call and restored after
call only if one of the following conditions is met:
- inline function is a suspend function
- inline function has try-catch blocks
- inline function has loops (backward jumps)

Note that there're quite some "simple" inline functions in Kotlin stdlib
besides run/let/with/apply. For example, many string operations are
implemented as inline wrappers over Java method calls.
2017-10-10 08:49:19 +03:00
Dmitry Petrov 82a9c35194 Fix self-reference to singleton in initializer
Singleton instance is "initialized" by delegating constructor call,
which is superclass constructor call in case of singletons (because
singletons can't have more than one constructor).

Singleton constructor is effectively split into two stages:
- before a super constructor call;
- after a super constructor call.

Before super constructor call, singleton instance can't be used directly
(see KT-20662), because neither 'this' nor static instance is
initialized yet. However, it can be used in closures, in which case a
static instance should be used (escaping uninitialized this is
prohibited by JVM). Actually using this static instance before it is
initialized (e.g., invoking a method that uses this singleton) will
cause a correct ExceptionInInitializerError.

After a super constructor call, static instance of a singleton may be
not initialized yet (in case of enum entries and interface companion
objects). However, we already have an initialized 'this', which we
should use for singleton references.

 #KT-20651 Fixed
2017-10-09 16:27:34 +03:00
Dmitry Petrov a4918748a5 Specialize not-null values using information from current analysis pass
Instead of a separate analysis pass to determine variable types at the
point of null checks, use current data flow information and transform
possibly nullable values to definitely non-null values using a special
intrinsic.

This allows to perform a single data flow analysis pass per RNCE
transformation pass (instead of two passes).
2017-10-09 12:20:40 +03:00
Dmitry Petrov d31efaa7ac Don't analyze method in RNCE if there're no optimizable instructions 2017-10-09 12:20:40 +03:00
Leonid Stashevsky 0348561cd2 Add annotation for default parameter value 2017-10-06 15:45:38 +03:00
Dmitry Petrov c3d74bdabb Support jump out of the constructor call in suspend functions
Jump out from expression (e.g., break or continue expression in call
arguments) requires stack normalization, which inserts POP instructions.
POPping an uninitialized value is similar to ASTORE, except that it
doesn't store a value to a local variable. Such POP instructions should
be removed during postprocessing of the uninitialized stores.
2017-10-04 13:39:48 +03:00
Dmitry Petrov da6841163b Maintain evaluation order for suspend calls in constructor arguments
Insert 'Class.forName(...)' in place of NEW instruction, so that the
corresponding class will be initialized if required.
2017-10-04 13:39:48 +03:00
Dmitry Petrov 533c1d2541 Reject bytecode manipulating with uninitialized values on stack
NB this will break parcel-related tests in android-extensions compiler
plugin
2017-10-04 13:39:48 +03:00
Dmitry Petrov f4f1ea91d9 Use accessible get/set arguments for collection element receiver
When generating collection element receiver (such as 'a[i]'), accessible
descriptor for get/set operator should be used.
Otherwise, if the corresponding get/set operator fun is called via an
accessor, its argument types may be different in case of generic fun
specialized with primitive types.

 #KT-20387 Fixed
2017-09-28 14:55:11 +03:00
Dmitry Petrov 3994034f46 Keep track of synthetic accessor parameter types
Accessor parameter types may be different from callee parameter types
in case of generic methods specialized by primitive types:

  open class Base<T> {
    protected fun foo(x: T) {}
  }

  // in different package
  class Derived : Base<Long> {
    inner class Inner {
      fun bar() { foo(42L) }
    }
  }

Synthetic accessor for 'Base.foo' in 'Derived' has signature '(J)V'
(not '(Ljava.lang.Object;)V' or '(Ljava.lang.Long;)V'),
and should box its parameter.

Note that in Java the corresponding synthetic accessor has signature
'(Ljava.lang.Long;)V' with auto-boxing at call site.

 #KT-20491 Fixed
2017-09-28 14:55:11 +03:00
Dmitry Petrov 73724bcdc7 Do not copy immediately created arrays in spread arguments
E.g., 'foo(x = *intArrayOf(42))'.

 #KT-20462 Fixed
2017-09-28 14:55:11 +03:00
Dmitry Petrov c0a83c3c8a KT-19251 Process uninitialized stores in mandatory bytecode pass
See
https://youtrack.jetbrains.com/issue/KT-19251
https://github.com/puniverse/quasar/issues/280
https://bugs.openjdk.java.net/browse/JDK-8046233

Inline function calls (as well as try/catch expressions) in constructor
arguments produce bytecode that spills stack, and stores uninitialized
objects (created by 'NEW C', but not initialized by 'C.<init>') to
local variables. Such bytecode is valid according to the JVM spec, but
confuses Quasar (and other bytecode postprocessing tools),
and fails to verify under some (buggy) versions of JDK 8.

In order to avoid that, we apply 'processUnitializedStores' already
implemented for coroutines. It moves 'NEW' instructions after the
constructor arguments evaluation, producing code like

<initialize class C using Class.forName>
<evaluate constructor arguments>
<store constructor arguments to variables>
NEW C
DUP
<load constructor arguments from variables>
INVOKESPECIAL C.<init>(...)

NB some other expressions, such as break/continue in the constructor
arguments, also can produce "weird" bytecode: object is created by a
'NEW C' instruction, but later (conditionally) POPped from stack and
left uninitialized. This, as we know, also can screw bytecode
postprocessing. However, it looks like we can get away with it ATM.
Otherwise it looks like we'd have to analyze constructor arguments, see
if the evaluation can "jump out", and perform argument linearization in
codegen.
2017-09-27 12:38:52 +03:00
Dmitry Petrov 8f9ea3e08b Fix const range bounds generation 2017-09-25 17:49:33 +03:00
Alexander Udalov 23d6690581 Fix codegen for multifile class parts with type aliases only
#KT-20337 Fixed
2017-09-25 11:58:20 +03:00
Alexander Udalov 09f36927a5 Do not try to generate 'expect' declarations in multifile classes
Similarly to PackageCodegenImpl#generateFile

 #KT-15754 Fixed
 #KT-17478 Fixed
2017-09-25 11:58:20 +03:00
Alexander Podkhalyuzin 3f8170d369 Clean idea files generated on the gradle import, add them to .gitignore 2017-09-19 23:58:27 +02:00