1#  Copyright (C) 2015 The Android Open Source Project
2#
3#  Licensed under the Apache License, Version 2.0 (the "License");
4#  you may not use this file except in compliance with the License.
5#  You may obtain a copy of the License at
6#
7#       http://www.apache.org/licenses/LICENSE-2.0
8#
9#  Unless required by applicable law or agreed to in writing, software
10#  distributed under the License is distributed on an "AS IS" BASIS,
11#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#  See the License for the specific language governing permissions and
13#  limitations under the License.
14#
15.class public LBoxUnbox;
16.super Ljava/lang/Object;
17
18.method public constructor <init>()V
19.registers 1
20    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
21    return-void
22.end method
23
24.method public static run()V
25    .registers 0
26
27    invoke-static {}, LBoxUnbox;->testBox()V
28    invoke-static {}, LBoxUnbox;->testBoxEquality()V
29    invoke-static {}, LBoxUnbox;->testFailures()V
30    invoke-static {}, LBoxUnbox;->testFailures2()V
31    invoke-static {}, LBoxUnbox;->testFailures3()V
32    invoke-static {}, LBoxUnbox;->forceGC()V
33
34    return-void
35.end method
36
37#TODO: should use a closure type instead of ArtMethod.
38.method public static doHelloWorld(J)V
39    .registers 4 # 1 wide parameters, 2 locals
40
41    const-string v0, "(BoxUnbox) Hello boxing world! (0-args, no closure)"
42
43    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
44    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
45
46    return-void
47.end method
48
49# Test boxing and unboxing; the same lambda should be invoked as if there was no box.
50.method private static testBox()V
51    .registers 3
52
53    create-lambda v0, LBoxUnbox;->doHelloWorld(J)V
54    box-lambda v2, v0 # v2 = box(v0)
55    unbox-lambda v0, v2, J # v0 = unbox(v2)
56    invoke-lambda v0, {}
57
58    return-void
59.end method
60
61# Test that boxing the same lambda twice yield the same object.
62.method private static testBoxEquality()V
63   .registers 6 # 0 parameters, 6 locals
64
65    create-lambda v0, LBoxUnbox;->doHelloWorld(J)V
66    box-lambda v2, v0 # v2 = box(v0)
67    box-lambda v3, v0 # v3 = box(v0)
68
69    # The objects should be not-null, and they should have the same reference
70    if-eqz v2, :is_zero
71    if-ne v2, v3, :is_not_equal
72
73    const-string v4, "(BoxUnbox) Boxing repeatedly yields referentially-equal objects"
74    goto :end
75
76:is_zero
77    const-string v4, "(BoxUnbox) Boxing repeatedly FAILED: boxing returned null"
78    goto :end
79
80:is_not_equal
81    const-string v4, "(BoxUnbox) Boxing repeatedly FAILED: objects were not same reference"
82    goto :end
83
84:end
85    sget-object v5, Ljava/lang/System;->out:Ljava/io/PrintStream;
86    invoke-virtual {v5, v4}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
87    return-void
88.end method
89
90# Test exceptions are thrown as expected when used opcodes incorrectly
91.method private static testFailures()V
92    .registers 4 # 0 parameters, 4 locals
93
94    const v0, 0  # v0 = null
95    const v1, 0  # v1 = null
96:start
97    unbox-lambda v2, v0, J
98    # attempting to unbox a null lambda will throw NPE
99:end
100    return-void
101
102:handler
103    const-string v2, "(BoxUnbox) Caught NPE for unbox-lambda"
104    sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream;
105    invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
106
107    return-void
108
109    .catch Ljava/lang/NullPointerException; {:start .. :end} :handler
110.end method
111
112# Test exceptions are thrown as expected when used opcodes incorrectly
113.method private static testFailures2()V
114    .registers 4 # 0 parameters, 4 locals
115
116    const v0, 0  # v0 = null
117    const v1, 0  # v1 = null
118:start
119    box-lambda v2, v0  # attempting to box a null lambda will throw NPE
120:end
121    return-void
122
123    # TODO: refactor testFailures using a goto
124
125:handler
126    const-string v2, "(BoxUnbox) Caught NPE for box-lambda"
127    sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream;
128    invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
129
130    return-void
131
132    .catch Ljava/lang/NullPointerException; {:start .. :end} :handler
133.end method
134
135# Test exceptions are thrown as expected when used opcodes incorrectly
136.method private static testFailures3()V
137    .registers 4 # 0 parameters, 4 locals
138
139    const-string v0, "This is not a boxed lambda"
140:start
141    # TODO: use \FunctionalType; here instead
142    unbox-lambda v2, v0, J
143    # can't use a string, expects a lambda object here. throws ClassCastException.
144:end
145    return-void
146
147    # TODO: refactor testFailures using a goto
148
149:handler
150    const-string v2, "(BoxUnbox) Caught ClassCastException for unbox-lambda"
151    sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream;
152    invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
153
154    return-void
155
156    .catch Ljava/lang/ClassCastException; {:start .. :end} :handler
157.end method
158
159
160# Force a GC. Used to ensure our weak reference table of boxed lambdas is getting swept.
161.method private static forceGC()V
162    .registers 1
163    invoke-static {}, Ljava/lang/Runtime;->getRuntime()Ljava/lang/Runtime;
164    move-result-object v0
165    invoke-virtual {v0}, Ljava/lang/Runtime;->gc()V
166
167    return-void
168.end method
169