diff options
Diffstat (limited to 'test')
198 files changed, 15159 insertions, 3497 deletions
diff --git a/test/051-thread/expected.txt b/test/051-thread/expected.txt index 3fc34929eb..c8af963723 100644 --- a/test/051-thread/expected.txt +++ b/test/051-thread/expected.txt @@ -12,4 +12,6 @@ testSetName running testSetName finished testThreadPriorities starting testThreadPriorities finished +Found current Thread in ThreadGroup +Found expected stack in getAllStackTraces() thread test done diff --git a/test/051-thread/src/Main.java b/test/051-thread/src/Main.java index 82fc0d471b..08cb5deeac 100644 --- a/test/051-thread/src/Main.java +++ b/test/051-thread/src/Main.java @@ -15,6 +15,9 @@ */ import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; /** * Test some basic thread stuff. @@ -28,6 +31,8 @@ public class Main { testSleepZero(); testSetName(); testThreadPriorities(); + testMainThreadGroup(); + testMainThreadAllStackTraces(); System.out.println("thread test done"); } @@ -159,6 +164,49 @@ public class Main { System.out.print("testThreadPriorities finished\n"); } + private static void testMainThreadGroup() { + Thread threads[] = new Thread[10]; + Thread current = Thread.currentThread(); + current.getThreadGroup().enumerate(threads); + + for (Thread t : threads) { + if (t == current) { + System.out.println("Found current Thread in ThreadGroup"); + return; + } + } + throw new RuntimeException("Did not find main thread: " + Arrays.toString(threads)); + } + + private static void testMainThreadAllStackTraces() { + StackTraceElement[] trace = Thread.getAllStackTraces().get(Thread.currentThread()); + if (trace == null) { + throw new RuntimeException("Did not find main thread: " + Thread.getAllStackTraces()); + } + List<StackTraceElement> list = Arrays.asList(trace); + Iterator<StackTraceElement> it = list.iterator(); + while (it.hasNext()) { + StackTraceElement ste = it.next(); + if (ste.getClassName().equals("Main")) { + if (!ste.getMethodName().equals("testMainThreadAllStackTraces")) { + throw new RuntimeException(list.toString()); + } + + StackTraceElement ste2 = it.next(); + if (!ste2.getClassName().equals("Main")) { + throw new RuntimeException(list.toString()); + } + if (!ste2.getMethodName().equals("main")) { + throw new RuntimeException(list.toString()); + } + + System.out.println("Found expected stack in getAllStackTraces()"); + return; + } + } + throw new RuntimeException(list.toString()); + } + private static native int getNativePriority(); private static native boolean supportsThreadPriorities(); diff --git a/test/160-read-barrier-stress/expected.txt b/test/160-read-barrier-stress/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/160-read-barrier-stress/expected.txt diff --git a/test/160-read-barrier-stress/info.txt b/test/160-read-barrier-stress/info.txt new file mode 100644 index 0000000000..505fe33338 --- /dev/null +++ b/test/160-read-barrier-stress/info.txt @@ -0,0 +1 @@ +Test stressing read barriers for CC GC. diff --git a/test/160-read-barrier-stress/run b/test/160-read-barrier-stress/run new file mode 100644 index 0000000000..ab82229e4e --- /dev/null +++ b/test/160-read-barrier-stress/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (C) 2017 The Android Open Source Project +# +# 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. + +# Limit the Java heap to 16MiB to force more GCs. +exec ${RUN} $@ --runtime-option -Xmx16m diff --git a/test/160-read-barrier-stress/src/Main.java b/test/160-read-barrier-stress/src/Main.java new file mode 100644 index 0000000000..7e130cef94 --- /dev/null +++ b/test/160-read-barrier-stress/src/Main.java @@ -0,0 +1,1111 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +public class Main { + public static void main(String[] args) { + // Initialize local variables for comparison. + Object f0000 = manyFields.testField0000; + Object f1024 = manyFields.testField1024; + Object f4444 = manyFields.testField4444; + Object f4999 = manyFields.testField4999; + // Initialize largeArray for comparison. + largeArray[0] = f0000; + largeArray[1024] = f1024; + largeArray[4444] = f4444; + largeArray[4999] = f4999; + // Read indexes, they cannot be considered constant because the variables are volatile. + int i0 = index0; + int i1024 = index1024; + int i4444 = index4444; + int i4999 = index4999; + // Initialize strings, hide this under a condition based on a volatile field. + String testString0 = null; + String testString1 = null; + String testString2 = null; + String testString3 = null; + if (index0 != 12345678) { + // By having this in the const-string instructions in an if-block, we avoid + // GVN eliminating identical const-string instructions in the loop below. + testString0 = "testString0"; + testString1 = "testString1"; + testString2 = "testString2"; + testString3 = "testString3"; + } + + // Continually check reads from `manyFields` and `largeArray` while allocating + // over 64MiB memory (with heap size limited to 16MiB), ensuring we run GC and + // stress the read barrier implementation if concurrent collector is enabled. + for (int i = 0; i != 64 * 1024; ++i) { + allocateAtLeast1KiB(); + ManyFields mf = manyFields; // Load the volatile `manyFields` once on each iteration. + Object[] la = largeArray; // Load the volatile `largeArray` once on each iteration. + // Test reference field access. + assertSameObject(f0000, mf.testField0000); + assertSameObject(f1024, mf.testField1024); + assertSameObject(f4444, mf.testField4444); + assertSameObject(f4999, mf.testField4999); + // Test array access with constant index. + assertSameObject(f0000, la[0]); + assertSameObject(f1024, la[1024]); + assertSameObject(f4444, la[4444]); + assertSameObject(f4999, la[4999]); + // Test array access with non-constant index. + assertSameObject(f0000, la[i0]); + assertSameObject(f1024, la[i1024]); + assertSameObject(f4444, la[i4444]); + assertSameObject(f4999, la[i4999]); + // Test GC roots. + if (index0 != 12345678) { + assertSameObject(testString0, "testString0"); + assertSameObject(testString1, "testString1"); + assertSameObject(testString2, "testString2"); + assertSameObject(testString3, "testString3"); + } + // TODO: Stress GC roots (const-string/const-class, kBssEntry/kReferrersClass). + } + } + + public static void assertSameObject(Object lhs, Object rhs) { + if (lhs != rhs) { + throw new Error("Different objects: " + lhs + " and " + rhs); + } + } + + public static void allocateAtLeast1KiB() { + // Give GC more work by allocating Object arrays. + memory[allocationIndex] = new Object[1024 / 4]; + ++allocationIndex; + if (allocationIndex == memory.length) { + allocationIndex = 0; + } + } + + // Make these volatile to avoid load elimination. + public static volatile ManyFields manyFields = new ManyFields(); + public static volatile Object[] largeArray = new Object[5000]; + public static volatile int index0 = 0; + public static volatile int index1024 = 1024; + public static volatile int index4444 = 4444; + public static volatile int index4999 = 4999; + + // We shall retain some allocated memory and release old allocations + // so that the GC has something to do. + public static Object[] memory = new Object[1024]; + public static int allocationIndex = 0; +} + +class ManyFields extends ManyFieldsBase3 { + public Object testField4000 = new Integer(4000); + public Object testField4001 = new Integer(4001); + public Object testField4002 = new Integer(4002); + public Object testField4003 = new Integer(4003); + public Object testField4004 = new Integer(4004); + public Object testField4005 = new Integer(4005); + public Object testField4006 = new Integer(4006); + public Object testField4007 = new Integer(4007); + public Object testField4008 = new Integer(4008); + public Object testField4009 = new Integer(4009); + public Object testField4010 = new Integer(4010); + public Object testField4011 = new Integer(4011); + public Object testField4012 = new Integer(4012); + public Object testField4013 = new Integer(4013); + public Object testField4014 = new Integer(4014); + public Object testField4015 = new Integer(4015); + public Object testField4016 = new Integer(4016); + public Object testField4017 = new Integer(4017); + public Object testField4018 = new Integer(4018); + public Object testField4019 = new Integer(4019); + public Object testField4020 = new Integer(4020); + public Object testField4021 = new Integer(4021); + public Object testField4022 = new Integer(4022); + public Object testField4023 = new Integer(4023); + public Object testField4024 = new Integer(4024); + public Object testField4025 = new Integer(4025); + public Object testField4026 = new Integer(4026); + public Object testField4027 = new Integer(4027); + public Object testField4028 = new Integer(4028); + public Object testField4029 = new Integer(4029); + public Object testField4030 = new Integer(4030); + public Object testField4031 = new Integer(4031); + public Object testField4032 = new Integer(4032); + public Object testField4033 = new Integer(4033); + public Object testField4034 = new Integer(4034); + public Object testField4035 = new Integer(4035); + public Object testField4036 = new Integer(4036); + public Object testField4037 = new Integer(4037); + public Object testField4038 = new Integer(4038); + public Object testField4039 = new Integer(4039); + public Object testField4040 = new Integer(4040); + public Object testField4041 = new Integer(4041); + public Object testField4042 = new Integer(4042); + public Object testField4043 = new Integer(4043); + public Object testField4044 = new Integer(4044); + public Object testField4045 = new Integer(4045); + public Object testField4046 = new Integer(4046); + public Object testField4047 = new Integer(4047); + public Object testField4048 = new Integer(4048); + public Object testField4049 = new Integer(4049); + public Object testField4050 = new Integer(4050); + public Object testField4051 = new Integer(4051); + public Object testField4052 = new Integer(4052); + public Object testField4053 = new Integer(4053); + public Object testField4054 = new Integer(4054); + public Object testField4055 = new Integer(4055); + public Object testField4056 = new Integer(4056); + public Object testField4057 = new Integer(4057); + public Object testField4058 = new Integer(4058); + public Object testField4059 = new Integer(4059); + public Object testField4060 = new Integer(4060); + public Object testField4061 = new Integer(4061); + public Object testField4062 = new Integer(4062); + public Object testField4063 = new Integer(4063); + public Object testField4064 = new Integer(4064); + public Object testField4065 = new Integer(4065); + public Object testField4066 = new Integer(4066); + public Object testField4067 = new Integer(4067); + public Object testField4068 = new Integer(4068); + public Object testField4069 = new Integer(4069); + public Object testField4070 = new Integer(4070); + public Object testField4071 = new Integer(4071); + public Object testField4072 = new Integer(4072); + public Object testField4073 = new Integer(4073); + public Object testField4074 = new Integer(4074); + public Object testField4075 = new Integer(4075); + public Object testField4076 = new Integer(4076); + public Object testField4077 = new Integer(4077); + public Object testField4078 = new Integer(4078); + public Object testField4079 = new Integer(4079); + public Object testField4080 = new Integer(4080); + public Object testField4081 = new Integer(4081); + public Object testField4082 = new Integer(4082); + public Object testField4083 = new Integer(4083); + public Object testField4084 = new Integer(4084); + public Object testField4085 = new Integer(4085); + public Object testField4086 = new Integer(4086); + public Object testField4087 = new Integer(4087); + public Object testField4088 = new Integer(4088); + public Object testField4089 = new Integer(4089); + public Object testField4090 = new Integer(4090); + public Object testField4091 = new Integer(4091); + public Object testField4092 = new Integer(4092); + public Object testField4093 = new Integer(4093); + public Object testField4094 = new Integer(4094); + public Object testField4095 = new Integer(4095); + public Object testField4096 = new Integer(4096); + public Object testField4097 = new Integer(4097); + public Object testField4098 = new Integer(4098); + public Object testField4099 = new Integer(4099); + public Object testField4100 = new Integer(4100); + public Object testField4101 = new Integer(4101); + public Object testField4102 = new Integer(4102); + public Object testField4103 = new Integer(4103); + public Object testField4104 = new Integer(4104); + public Object testField4105 = new Integer(4105); + public Object testField4106 = new Integer(4106); + public Object testField4107 = new Integer(4107); + public Object testField4108 = new Integer(4108); + public Object testField4109 = new Integer(4109); + public Object testField4110 = new Integer(4110); + public Object testField4111 = new Integer(4111); + public Object testField4112 = new Integer(4112); + public Object testField4113 = new Integer(4113); + public Object testField4114 = new Integer(4114); + public Object testField4115 = new Integer(4115); + public Object testField4116 = new Integer(4116); + public Object testField4117 = new Integer(4117); + public Object testField4118 = new Integer(4118); + public Object testField4119 = new Integer(4119); + public Object testField4120 = new Integer(4120); + public Object testField4121 = new Integer(4121); + public Object testField4122 = new Integer(4122); + public Object testField4123 = new Integer(4123); + public Object testField4124 = new Integer(4124); + public Object testField4125 = new Integer(4125); + public Object testField4126 = new Integer(4126); + public Object testField4127 = new Integer(4127); + public Object testField4128 = new Integer(4128); + public Object testField4129 = new Integer(4129); + public Object testField4130 = new Integer(4130); + public Object testField4131 = new Integer(4131); + public Object testField4132 = new Integer(4132); + public Object testField4133 = new Integer(4133); + public Object testField4134 = new Integer(4134); + public Object testField4135 = new Integer(4135); + public Object testField4136 = new Integer(4136); + public Object testField4137 = new Integer(4137); + public Object testField4138 = new Integer(4138); + public Object testField4139 = new Integer(4139); + public Object testField4140 = new Integer(4140); + public Object testField4141 = new Integer(4141); + public Object testField4142 = new Integer(4142); + public Object testField4143 = new Integer(4143); + public Object testField4144 = new Integer(4144); + public Object testField4145 = new Integer(4145); + public Object testField4146 = new Integer(4146); + public Object testField4147 = new Integer(4147); + public Object testField4148 = new Integer(4148); + public Object testField4149 = new Integer(4149); + public Object testField4150 = new Integer(4150); + public Object testField4151 = new Integer(4151); + public Object testField4152 = new Integer(4152); + public Object testField4153 = new Integer(4153); + public Object testField4154 = new Integer(4154); + public Object testField4155 = new Integer(4155); + public Object testField4156 = new Integer(4156); + public Object testField4157 = new Integer(4157); + public Object testField4158 = new Integer(4158); + public Object testField4159 = new Integer(4159); + public Object testField4160 = new Integer(4160); + public Object testField4161 = new Integer(4161); + public Object testField4162 = new Integer(4162); + public Object testField4163 = new Integer(4163); + public Object testField4164 = new Integer(4164); + public Object testField4165 = new Integer(4165); + public Object testField4166 = new Integer(4166); + public Object testField4167 = new Integer(4167); + public Object testField4168 = new Integer(4168); + public Object testField4169 = new Integer(4169); + public Object testField4170 = new Integer(4170); + public Object testField4171 = new Integer(4171); + public Object testField4172 = new Integer(4172); + public Object testField4173 = new Integer(4173); + public Object testField4174 = new Integer(4174); + public Object testField4175 = new Integer(4175); + public Object testField4176 = new Integer(4176); + public Object testField4177 = new Integer(4177); + public Object testField4178 = new Integer(4178); + public Object testField4179 = new Integer(4179); + public Object testField4180 = new Integer(4180); + public Object testField4181 = new Integer(4181); + public Object testField4182 = new Integer(4182); + public Object testField4183 = new Integer(4183); + public Object testField4184 = new Integer(4184); + public Object testField4185 = new Integer(4185); + public Object testField4186 = new Integer(4186); + public Object testField4187 = new Integer(4187); + public Object testField4188 = new Integer(4188); + public Object testField4189 = new Integer(4189); + public Object testField4190 = new Integer(4190); + public Object testField4191 = new Integer(4191); + public Object testField4192 = new Integer(4192); + public Object testField4193 = new Integer(4193); + public Object testField4194 = new Integer(4194); + public Object testField4195 = new Integer(4195); + public Object testField4196 = new Integer(4196); + public Object testField4197 = new Integer(4197); + public Object testField4198 = new Integer(4198); + public Object testField4199 = new Integer(4199); + public Object testField4200 = new Integer(4200); + public Object testField4201 = new Integer(4201); + public Object testField4202 = new Integer(4202); + public Object testField4203 = new Integer(4203); + public Object testField4204 = new Integer(4204); + public Object testField4205 = new Integer(4205); + public Object testField4206 = new Integer(4206); + public Object testField4207 = new Integer(4207); + public Object testField4208 = new Integer(4208); + public Object testField4209 = new Integer(4209); + public Object testField4210 = new Integer(4210); + public Object testField4211 = new Integer(4211); + public Object testField4212 = new Integer(4212); + public Object testField4213 = new Integer(4213); + public Object testField4214 = new Integer(4214); + public Object testField4215 = new Integer(4215); + public Object testField4216 = new Integer(4216); + public Object testField4217 = new Integer(4217); + public Object testField4218 = new Integer(4218); + public Object testField4219 = new Integer(4219); + public Object testField4220 = new Integer(4220); + public Object testField4221 = new Integer(4221); + public Object testField4222 = new Integer(4222); + public Object testField4223 = new Integer(4223); + public Object testField4224 = new Integer(4224); + public Object testField4225 = new Integer(4225); + public Object testField4226 = new Integer(4226); + public Object testField4227 = new Integer(4227); + public Object testField4228 = new Integer(4228); + public Object testField4229 = new Integer(4229); + public Object testField4230 = new Integer(4230); + public Object testField4231 = new Integer(4231); + public Object testField4232 = new Integer(4232); + public Object testField4233 = new Integer(4233); + public Object testField4234 = new Integer(4234); + public Object testField4235 = new Integer(4235); + public Object testField4236 = new Integer(4236); + public Object testField4237 = new Integer(4237); + public Object testField4238 = new Integer(4238); + public Object testField4239 = new Integer(4239); + public Object testField4240 = new Integer(4240); + public Object testField4241 = new Integer(4241); + public Object testField4242 = new Integer(4242); + public Object testField4243 = new Integer(4243); + public Object testField4244 = new Integer(4244); + public Object testField4245 = new Integer(4245); + public Object testField4246 = new Integer(4246); + public Object testField4247 = new Integer(4247); + public Object testField4248 = new Integer(4248); + public Object testField4249 = new Integer(4249); + public Object testField4250 = new Integer(4250); + public Object testField4251 = new Integer(4251); + public Object testField4252 = new Integer(4252); + public Object testField4253 = new Integer(4253); + public Object testField4254 = new Integer(4254); + public Object testField4255 = new Integer(4255); + public Object testField4256 = new Integer(4256); + public Object testField4257 = new Integer(4257); + public Object testField4258 = new Integer(4258); + public Object testField4259 = new Integer(4259); + public Object testField4260 = new Integer(4260); + public Object testField4261 = new Integer(4261); + public Object testField4262 = new Integer(4262); + public Object testField4263 = new Integer(4263); + public Object testField4264 = new Integer(4264); + public Object testField4265 = new Integer(4265); + public Object testField4266 = new Integer(4266); + public Object testField4267 = new Integer(4267); + public Object testField4268 = new Integer(4268); + public Object testField4269 = new Integer(4269); + public Object testField4270 = new Integer(4270); + public Object testField4271 = new Integer(4271); + public Object testField4272 = new Integer(4272); + public Object testField4273 = new Integer(4273); + public Object testField4274 = new Integer(4274); + public Object testField4275 = new Integer(4275); + public Object testField4276 = new Integer(4276); + public Object testField4277 = new Integer(4277); + public Object testField4278 = new Integer(4278); + public Object testField4279 = new Integer(4279); + public Object testField4280 = new Integer(4280); + public Object testField4281 = new Integer(4281); + public Object testField4282 = new Integer(4282); + public Object testField4283 = new Integer(4283); + public Object testField4284 = new Integer(4284); + public Object testField4285 = new Integer(4285); + public Object testField4286 = new Integer(4286); + public Object testField4287 = new Integer(4287); + public Object testField4288 = new Integer(4288); + public Object testField4289 = new Integer(4289); + public Object testField4290 = new Integer(4290); + public Object testField4291 = new Integer(4291); + public Object testField4292 = new Integer(4292); + public Object testField4293 = new Integer(4293); + public Object testField4294 = new Integer(4294); + public Object testField4295 = new Integer(4295); + public Object testField4296 = new Integer(4296); + public Object testField4297 = new Integer(4297); + public Object testField4298 = new Integer(4298); + public Object testField4299 = new Integer(4299); + public Object testField4300 = new Integer(4300); + public Object testField4301 = new Integer(4301); + public Object testField4302 = new Integer(4302); + public Object testField4303 = new Integer(4303); + public Object testField4304 = new Integer(4304); + public Object testField4305 = new Integer(4305); + public Object testField4306 = new Integer(4306); + public Object testField4307 = new Integer(4307); + public Object testField4308 = new Integer(4308); + public Object testField4309 = new Integer(4309); + public Object testField4310 = new Integer(4310); + public Object testField4311 = new Integer(4311); + public Object testField4312 = new Integer(4312); + public Object testField4313 = new Integer(4313); + public Object testField4314 = new Integer(4314); + public Object testField4315 = new Integer(4315); + public Object testField4316 = new Integer(4316); + public Object testField4317 = new Integer(4317); + public Object testField4318 = new Integer(4318); + public Object testField4319 = new Integer(4319); + public Object testField4320 = new Integer(4320); + public Object testField4321 = new Integer(4321); + public Object testField4322 = new Integer(4322); + public Object testField4323 = new Integer(4323); + public Object testField4324 = new Integer(4324); + public Object testField4325 = new Integer(4325); + public Object testField4326 = new Integer(4326); + public Object testField4327 = new Integer(4327); + public Object testField4328 = new Integer(4328); + public Object testField4329 = new Integer(4329); + public Object testField4330 = new Integer(4330); + public Object testField4331 = new Integer(4331); + public Object testField4332 = new Integer(4332); + public Object testField4333 = new Integer(4333); + public Object testField4334 = new Integer(4334); + public Object testField4335 = new Integer(4335); + public Object testField4336 = new Integer(4336); + public Object testField4337 = new Integer(4337); + public Object testField4338 = new Integer(4338); + public Object testField4339 = new Integer(4339); + public Object testField4340 = new Integer(4340); + public Object testField4341 = new Integer(4341); + public Object testField4342 = new Integer(4342); + public Object testField4343 = new Integer(4343); + public Object testField4344 = new Integer(4344); + public Object testField4345 = new Integer(4345); + public Object testField4346 = new Integer(4346); + public Object testField4347 = new Integer(4347); + public Object testField4348 = new Integer(4348); + public Object testField4349 = new Integer(4349); + public Object testField4350 = new Integer(4350); + public Object testField4351 = new Integer(4351); + public Object testField4352 = new Integer(4352); + public Object testField4353 = new Integer(4353); + public Object testField4354 = new Integer(4354); + public Object testField4355 = new Integer(4355); + public Object testField4356 = new Integer(4356); + public Object testField4357 = new Integer(4357); + public Object testField4358 = new Integer(4358); + public Object testField4359 = new Integer(4359); + public Object testField4360 = new Integer(4360); + public Object testField4361 = new Integer(4361); + public Object testField4362 = new Integer(4362); + public Object testField4363 = new Integer(4363); + public Object testField4364 = new Integer(4364); + public Object testField4365 = new Integer(4365); + public Object testField4366 = new Integer(4366); + public Object testField4367 = new Integer(4367); + public Object testField4368 = new Integer(4368); + public Object testField4369 = new Integer(4369); + public Object testField4370 = new Integer(4370); + public Object testField4371 = new Integer(4371); + public Object testField4372 = new Integer(4372); + public Object testField4373 = new Integer(4373); + public Object testField4374 = new Integer(4374); + public Object testField4375 = new Integer(4375); + public Object testField4376 = new Integer(4376); + public Object testField4377 = new Integer(4377); + public Object testField4378 = new Integer(4378); + public Object testField4379 = new Integer(4379); + public Object testField4380 = new Integer(4380); + public Object testField4381 = new Integer(4381); + public Object testField4382 = new Integer(4382); + public Object testField4383 = new Integer(4383); + public Object testField4384 = new Integer(4384); + public Object testField4385 = new Integer(4385); + public Object testField4386 = new Integer(4386); + public Object testField4387 = new Integer(4387); + public Object testField4388 = new Integer(4388); + public Object testField4389 = new Integer(4389); + public Object testField4390 = new Integer(4390); + public Object testField4391 = new Integer(4391); + public Object testField4392 = new Integer(4392); + public Object testField4393 = new Integer(4393); + public Object testField4394 = new Integer(4394); + public Object testField4395 = new Integer(4395); + public Object testField4396 = new Integer(4396); + public Object testField4397 = new Integer(4397); + public Object testField4398 = new Integer(4398); + public Object testField4399 = new Integer(4399); + public Object testField4400 = new Integer(4400); + public Object testField4401 = new Integer(4401); + public Object testField4402 = new Integer(4402); + public Object testField4403 = new Integer(4403); + public Object testField4404 = new Integer(4404); + public Object testField4405 = new Integer(4405); + public Object testField4406 = new Integer(4406); + public Object testField4407 = new Integer(4407); + public Object testField4408 = new Integer(4408); + public Object testField4409 = new Integer(4409); + public Object testField4410 = new Integer(4410); + public Object testField4411 = new Integer(4411); + public Object testField4412 = new Integer(4412); + public Object testField4413 = new Integer(4413); + public Object testField4414 = new Integer(4414); + public Object testField4415 = new Integer(4415); + public Object testField4416 = new Integer(4416); + public Object testField4417 = new Integer(4417); + public Object testField4418 = new Integer(4418); + public Object testField4419 = new Integer(4419); + public Object testField4420 = new Integer(4420); + public Object testField4421 = new Integer(4421); + public Object testField4422 = new Integer(4422); + public Object testField4423 = new Integer(4423); + public Object testField4424 = new Integer(4424); + public Object testField4425 = new Integer(4425); + public Object testField4426 = new Integer(4426); + public Object testField4427 = new Integer(4427); + public Object testField4428 = new Integer(4428); + public Object testField4429 = new Integer(4429); + public Object testField4430 = new Integer(4430); + public Object testField4431 = new Integer(4431); + public Object testField4432 = new Integer(4432); + public Object testField4433 = new Integer(4433); + public Object testField4434 = new Integer(4434); + public Object testField4435 = new Integer(4435); + public Object testField4436 = new Integer(4436); + public Object testField4437 = new Integer(4437); + public Object testField4438 = new Integer(4438); + public Object testField4439 = new Integer(4439); + public Object testField4440 = new Integer(4440); + public Object testField4441 = new Integer(4441); + public Object testField4442 = new Integer(4442); + public Object testField4443 = new Integer(4443); + public Object testField4444 = new Integer(4444); + public Object testField4445 = new Integer(4445); + public Object testField4446 = new Integer(4446); + public Object testField4447 = new Integer(4447); + public Object testField4448 = new Integer(4448); + public Object testField4449 = new Integer(4449); + public Object testField4450 = new Integer(4450); + public Object testField4451 = new Integer(4451); + public Object testField4452 = new Integer(4452); + public Object testField4453 = new Integer(4453); + public Object testField4454 = new Integer(4454); + public Object testField4455 = new Integer(4455); + public Object testField4456 = new Integer(4456); + public Object testField4457 = new Integer(4457); + public Object testField4458 = new Integer(4458); + public Object testField4459 = new Integer(4459); + public Object testField4460 = new Integer(4460); + public Object testField4461 = new Integer(4461); + public Object testField4462 = new Integer(4462); + public Object testField4463 = new Integer(4463); + public Object testField4464 = new Integer(4464); + public Object testField4465 = new Integer(4465); + public Object testField4466 = new Integer(4466); + public Object testField4467 = new Integer(4467); + public Object testField4468 = new Integer(4468); + public Object testField4469 = new Integer(4469); + public Object testField4470 = new Integer(4470); + public Object testField4471 = new Integer(4471); + public Object testField4472 = new Integer(4472); + public Object testField4473 = new Integer(4473); + public Object testField4474 = new Integer(4474); + public Object testField4475 = new Integer(4475); + public Object testField4476 = new Integer(4476); + public Object testField4477 = new Integer(4477); + public Object testField4478 = new Integer(4478); + public Object testField4479 = new Integer(4479); + public Object testField4480 = new Integer(4480); + public Object testField4481 = new Integer(4481); + public Object testField4482 = new Integer(4482); + public Object testField4483 = new Integer(4483); + public Object testField4484 = new Integer(4484); + public Object testField4485 = new Integer(4485); + public Object testField4486 = new Integer(4486); + public Object testField4487 = new Integer(4487); + public Object testField4488 = new Integer(4488); + public Object testField4489 = new Integer(4489); + public Object testField4490 = new Integer(4490); + public Object testField4491 = new Integer(4491); + public Object testField4492 = new Integer(4492); + public Object testField4493 = new Integer(4493); + public Object testField4494 = new Integer(4494); + public Object testField4495 = new Integer(4495); + public Object testField4496 = new Integer(4496); + public Object testField4497 = new Integer(4497); + public Object testField4498 = new Integer(4498); + public Object testField4499 = new Integer(4499); + public Object testField4500 = new Integer(4500); + public Object testField4501 = new Integer(4501); + public Object testField4502 = new Integer(4502); + public Object testField4503 = new Integer(4503); + public Object testField4504 = new Integer(4504); + public Object testField4505 = new Integer(4505); + public Object testField4506 = new Integer(4506); + public Object testField4507 = new Integer(4507); + public Object testField4508 = new Integer(4508); + public Object testField4509 = new Integer(4509); + public Object testField4510 = new Integer(4510); + public Object testField4511 = new Integer(4511); + public Object testField4512 = new Integer(4512); + public Object testField4513 = new Integer(4513); + public Object testField4514 = new Integer(4514); + public Object testField4515 = new Integer(4515); + public Object testField4516 = new Integer(4516); + public Object testField4517 = new Integer(4517); + public Object testField4518 = new Integer(4518); + public Object testField4519 = new Integer(4519); + public Object testField4520 = new Integer(4520); + public Object testField4521 = new Integer(4521); + public Object testField4522 = new Integer(4522); + public Object testField4523 = new Integer(4523); + public Object testField4524 = new Integer(4524); + public Object testField4525 = new Integer(4525); + public Object testField4526 = new Integer(4526); + public Object testField4527 = new Integer(4527); + public Object testField4528 = new Integer(4528); + public Object testField4529 = new Integer(4529); + public Object testField4530 = new Integer(4530); + public Object testField4531 = new Integer(4531); + public Object testField4532 = new Integer(4532); + public Object testField4533 = new Integer(4533); + public Object testField4534 = new Integer(4534); + public Object testField4535 = new Integer(4535); + public Object testField4536 = new Integer(4536); + public Object testField4537 = new Integer(4537); + public Object testField4538 = new Integer(4538); + public Object testField4539 = new Integer(4539); + public Object testField4540 = new Integer(4540); + public Object testField4541 = new Integer(4541); + public Object testField4542 = new Integer(4542); + public Object testField4543 = new Integer(4543); + public Object testField4544 = new Integer(4544); + public Object testField4545 = new Integer(4545); + public Object testField4546 = new Integer(4546); + public Object testField4547 = new Integer(4547); + public Object testField4548 = new Integer(4548); + public Object testField4549 = new Integer(4549); + public Object testField4550 = new Integer(4550); + public Object testField4551 = new Integer(4551); + public Object testField4552 = new Integer(4552); + public Object testField4553 = new Integer(4553); + public Object testField4554 = new Integer(4554); + public Object testField4555 = new Integer(4555); + public Object testField4556 = new Integer(4556); + public Object testField4557 = new Integer(4557); + public Object testField4558 = new Integer(4558); + public Object testField4559 = new Integer(4559); + public Object testField4560 = new Integer(4560); + public Object testField4561 = new Integer(4561); + public Object testField4562 = new Integer(4562); + public Object testField4563 = new Integer(4563); + public Object testField4564 = new Integer(4564); + public Object testField4565 = new Integer(4565); + public Object testField4566 = new Integer(4566); + public Object testField4567 = new Integer(4567); + public Object testField4568 = new Integer(4568); + public Object testField4569 = new Integer(4569); + public Object testField4570 = new Integer(4570); + public Object testField4571 = new Integer(4571); + public Object testField4572 = new Integer(4572); + public Object testField4573 = new Integer(4573); + public Object testField4574 = new Integer(4574); + public Object testField4575 = new Integer(4575); + public Object testField4576 = new Integer(4576); + public Object testField4577 = new Integer(4577); + public Object testField4578 = new Integer(4578); + public Object testField4579 = new Integer(4579); + public Object testField4580 = new Integer(4580); + public Object testField4581 = new Integer(4581); + public Object testField4582 = new Integer(4582); + public Object testField4583 = new Integer(4583); + public Object testField4584 = new Integer(4584); + public Object testField4585 = new Integer(4585); + public Object testField4586 = new Integer(4586); + public Object testField4587 = new Integer(4587); + public Object testField4588 = new Integer(4588); + public Object testField4589 = new Integer(4589); + public Object testField4590 = new Integer(4590); + public Object testField4591 = new Integer(4591); + public Object testField4592 = new Integer(4592); + public Object testField4593 = new Integer(4593); + public Object testField4594 = new Integer(4594); + public Object testField4595 = new Integer(4595); + public Object testField4596 = new Integer(4596); + public Object testField4597 = new Integer(4597); + public Object testField4598 = new Integer(4598); + public Object testField4599 = new Integer(4599); + public Object testField4600 = new Integer(4600); + public Object testField4601 = new Integer(4601); + public Object testField4602 = new Integer(4602); + public Object testField4603 = new Integer(4603); + public Object testField4604 = new Integer(4604); + public Object testField4605 = new Integer(4605); + public Object testField4606 = new Integer(4606); + public Object testField4607 = new Integer(4607); + public Object testField4608 = new Integer(4608); + public Object testField4609 = new Integer(4609); + public Object testField4610 = new Integer(4610); + public Object testField4611 = new Integer(4611); + public Object testField4612 = new Integer(4612); + public Object testField4613 = new Integer(4613); + public Object testField4614 = new Integer(4614); + public Object testField4615 = new Integer(4615); + public Object testField4616 = new Integer(4616); + public Object testField4617 = new Integer(4617); + public Object testField4618 = new Integer(4618); + public Object testField4619 = new Integer(4619); + public Object testField4620 = new Integer(4620); + public Object testField4621 = new Integer(4621); + public Object testField4622 = new Integer(4622); + public Object testField4623 = new Integer(4623); + public Object testField4624 = new Integer(4624); + public Object testField4625 = new Integer(4625); + public Object testField4626 = new Integer(4626); + public Object testField4627 = new Integer(4627); + public Object testField4628 = new Integer(4628); + public Object testField4629 = new Integer(4629); + public Object testField4630 = new Integer(4630); + public Object testField4631 = new Integer(4631); + public Object testField4632 = new Integer(4632); + public Object testField4633 = new Integer(4633); + public Object testField4634 = new Integer(4634); + public Object testField4635 = new Integer(4635); + public Object testField4636 = new Integer(4636); + public Object testField4637 = new Integer(4637); + public Object testField4638 = new Integer(4638); + public Object testField4639 = new Integer(4639); + public Object testField4640 = new Integer(4640); + public Object testField4641 = new Integer(4641); + public Object testField4642 = new Integer(4642); + public Object testField4643 = new Integer(4643); + public Object testField4644 = new Integer(4644); + public Object testField4645 = new Integer(4645); + public Object testField4646 = new Integer(4646); + public Object testField4647 = new Integer(4647); + public Object testField4648 = new Integer(4648); + public Object testField4649 = new Integer(4649); + public Object testField4650 = new Integer(4650); + public Object testField4651 = new Integer(4651); + public Object testField4652 = new Integer(4652); + public Object testField4653 = new Integer(4653); + public Object testField4654 = new Integer(4654); + public Object testField4655 = new Integer(4655); + public Object testField4656 = new Integer(4656); + public Object testField4657 = new Integer(4657); + public Object testField4658 = new Integer(4658); + public Object testField4659 = new Integer(4659); + public Object testField4660 = new Integer(4660); + public Object testField4661 = new Integer(4661); + public Object testField4662 = new Integer(4662); + public Object testField4663 = new Integer(4663); + public Object testField4664 = new Integer(4664); + public Object testField4665 = new Integer(4665); + public Object testField4666 = new Integer(4666); + public Object testField4667 = new Integer(4667); + public Object testField4668 = new Integer(4668); + public Object testField4669 = new Integer(4669); + public Object testField4670 = new Integer(4670); + public Object testField4671 = new Integer(4671); + public Object testField4672 = new Integer(4672); + public Object testField4673 = new Integer(4673); + public Object testField4674 = new Integer(4674); + public Object testField4675 = new Integer(4675); + public Object testField4676 = new Integer(4676); + public Object testField4677 = new Integer(4677); + public Object testField4678 = new Integer(4678); + public Object testField4679 = new Integer(4679); + public Object testField4680 = new Integer(4680); + public Object testField4681 = new Integer(4681); + public Object testField4682 = new Integer(4682); + public Object testField4683 = new Integer(4683); + public Object testField4684 = new Integer(4684); + public Object testField4685 = new Integer(4685); + public Object testField4686 = new Integer(4686); + public Object testField4687 = new Integer(4687); + public Object testField4688 = new Integer(4688); + public Object testField4689 = new Integer(4689); + public Object testField4690 = new Integer(4690); + public Object testField4691 = new Integer(4691); + public Object testField4692 = new Integer(4692); + public Object testField4693 = new Integer(4693); + public Object testField4694 = new Integer(4694); + public Object testField4695 = new Integer(4695); + public Object testField4696 = new Integer(4696); + public Object testField4697 = new Integer(4697); + public Object testField4698 = new Integer(4698); + public Object testField4699 = new Integer(4699); + public Object testField4700 = new Integer(4700); + public Object testField4701 = new Integer(4701); + public Object testField4702 = new Integer(4702); + public Object testField4703 = new Integer(4703); + public Object testField4704 = new Integer(4704); + public Object testField4705 = new Integer(4705); + public Object testField4706 = new Integer(4706); + public Object testField4707 = new Integer(4707); + public Object testField4708 = new Integer(4708); + public Object testField4709 = new Integer(4709); + public Object testField4710 = new Integer(4710); + public Object testField4711 = new Integer(4711); + public Object testField4712 = new Integer(4712); + public Object testField4713 = new Integer(4713); + public Object testField4714 = new Integer(4714); + public Object testField4715 = new Integer(4715); + public Object testField4716 = new Integer(4716); + public Object testField4717 = new Integer(4717); + public Object testField4718 = new Integer(4718); + public Object testField4719 = new Integer(4719); + public Object testField4720 = new Integer(4720); + public Object testField4721 = new Integer(4721); + public Object testField4722 = new Integer(4722); + public Object testField4723 = new Integer(4723); + public Object testField4724 = new Integer(4724); + public Object testField4725 = new Integer(4725); + public Object testField4726 = new Integer(4726); + public Object testField4727 = new Integer(4727); + public Object testField4728 = new Integer(4728); + public Object testField4729 = new Integer(4729); + public Object testField4730 = new Integer(4730); + public Object testField4731 = new Integer(4731); + public Object testField4732 = new Integer(4732); + public Object testField4733 = new Integer(4733); + public Object testField4734 = new Integer(4734); + public Object testField4735 = new Integer(4735); + public Object testField4736 = new Integer(4736); + public Object testField4737 = new Integer(4737); + public Object testField4738 = new Integer(4738); + public Object testField4739 = new Integer(4739); + public Object testField4740 = new Integer(4740); + public Object testField4741 = new Integer(4741); + public Object testField4742 = new Integer(4742); + public Object testField4743 = new Integer(4743); + public Object testField4744 = new Integer(4744); + public Object testField4745 = new Integer(4745); + public Object testField4746 = new Integer(4746); + public Object testField4747 = new Integer(4747); + public Object testField4748 = new Integer(4748); + public Object testField4749 = new Integer(4749); + public Object testField4750 = new Integer(4750); + public Object testField4751 = new Integer(4751); + public Object testField4752 = new Integer(4752); + public Object testField4753 = new Integer(4753); + public Object testField4754 = new Integer(4754); + public Object testField4755 = new Integer(4755); + public Object testField4756 = new Integer(4756); + public Object testField4757 = new Integer(4757); + public Object testField4758 = new Integer(4758); + public Object testField4759 = new Integer(4759); + public Object testField4760 = new Integer(4760); + public Object testField4761 = new Integer(4761); + public Object testField4762 = new Integer(4762); + public Object testField4763 = new Integer(4763); + public Object testField4764 = new Integer(4764); + public Object testField4765 = new Integer(4765); + public Object testField4766 = new Integer(4766); + public Object testField4767 = new Integer(4767); + public Object testField4768 = new Integer(4768); + public Object testField4769 = new Integer(4769); + public Object testField4770 = new Integer(4770); + public Object testField4771 = new Integer(4771); + public Object testField4772 = new Integer(4772); + public Object testField4773 = new Integer(4773); + public Object testField4774 = new Integer(4774); + public Object testField4775 = new Integer(4775); + public Object testField4776 = new Integer(4776); + public Object testField4777 = new Integer(4777); + public Object testField4778 = new Integer(4778); + public Object testField4779 = new Integer(4779); + public Object testField4780 = new Integer(4780); + public Object testField4781 = new Integer(4781); + public Object testField4782 = new Integer(4782); + public Object testField4783 = new Integer(4783); + public Object testField4784 = new Integer(4784); + public Object testField4785 = new Integer(4785); + public Object testField4786 = new Integer(4786); + public Object testField4787 = new Integer(4787); + public Object testField4788 = new Integer(4788); + public Object testField4789 = new Integer(4789); + public Object testField4790 = new Integer(4790); + public Object testField4791 = new Integer(4791); + public Object testField4792 = new Integer(4792); + public Object testField4793 = new Integer(4793); + public Object testField4794 = new Integer(4794); + public Object testField4795 = new Integer(4795); + public Object testField4796 = new Integer(4796); + public Object testField4797 = new Integer(4797); + public Object testField4798 = new Integer(4798); + public Object testField4799 = new Integer(4799); + public Object testField4800 = new Integer(4800); + public Object testField4801 = new Integer(4801); + public Object testField4802 = new Integer(4802); + public Object testField4803 = new Integer(4803); + public Object testField4804 = new Integer(4804); + public Object testField4805 = new Integer(4805); + public Object testField4806 = new Integer(4806); + public Object testField4807 = new Integer(4807); + public Object testField4808 = new Integer(4808); + public Object testField4809 = new Integer(4809); + public Object testField4810 = new Integer(4810); + public Object testField4811 = new Integer(4811); + public Object testField4812 = new Integer(4812); + public Object testField4813 = new Integer(4813); + public Object testField4814 = new Integer(4814); + public Object testField4815 = new Integer(4815); + public Object testField4816 = new Integer(4816); + public Object testField4817 = new Integer(4817); + public Object testField4818 = new Integer(4818); + public Object testField4819 = new Integer(4819); + public Object testField4820 = new Integer(4820); + public Object testField4821 = new Integer(4821); + public Object testField4822 = new Integer(4822); + public Object testField4823 = new Integer(4823); + public Object testField4824 = new Integer(4824); + public Object testField4825 = new Integer(4825); + public Object testField4826 = new Integer(4826); + public Object testField4827 = new Integer(4827); + public Object testField4828 = new Integer(4828); + public Object testField4829 = new Integer(4829); + public Object testField4830 = new Integer(4830); + public Object testField4831 = new Integer(4831); + public Object testField4832 = new Integer(4832); + public Object testField4833 = new Integer(4833); + public Object testField4834 = new Integer(4834); + public Object testField4835 = new Integer(4835); + public Object testField4836 = new Integer(4836); + public Object testField4837 = new Integer(4837); + public Object testField4838 = new Integer(4838); + public Object testField4839 = new Integer(4839); + public Object testField4840 = new Integer(4840); + public Object testField4841 = new Integer(4841); + public Object testField4842 = new Integer(4842); + public Object testField4843 = new Integer(4843); + public Object testField4844 = new Integer(4844); + public Object testField4845 = new Integer(4845); + public Object testField4846 = new Integer(4846); + public Object testField4847 = new Integer(4847); + public Object testField4848 = new Integer(4848); + public Object testField4849 = new Integer(4849); + public Object testField4850 = new Integer(4850); + public Object testField4851 = new Integer(4851); + public Object testField4852 = new Integer(4852); + public Object testField4853 = new Integer(4853); + public Object testField4854 = new Integer(4854); + public Object testField4855 = new Integer(4855); + public Object testField4856 = new Integer(4856); + public Object testField4857 = new Integer(4857); + public Object testField4858 = new Integer(4858); + public Object testField4859 = new Integer(4859); + public Object testField4860 = new Integer(4860); + public Object testField4861 = new Integer(4861); + public Object testField4862 = new Integer(4862); + public Object testField4863 = new Integer(4863); + public Object testField4864 = new Integer(4864); + public Object testField4865 = new Integer(4865); + public Object testField4866 = new Integer(4866); + public Object testField4867 = new Integer(4867); + public Object testField4868 = new Integer(4868); + public Object testField4869 = new Integer(4869); + public Object testField4870 = new Integer(4870); + public Object testField4871 = new Integer(4871); + public Object testField4872 = new Integer(4872); + public Object testField4873 = new Integer(4873); + public Object testField4874 = new Integer(4874); + public Object testField4875 = new Integer(4875); + public Object testField4876 = new Integer(4876); + public Object testField4877 = new Integer(4877); + public Object testField4878 = new Integer(4878); + public Object testField4879 = new Integer(4879); + public Object testField4880 = new Integer(4880); + public Object testField4881 = new Integer(4881); + public Object testField4882 = new Integer(4882); + public Object testField4883 = new Integer(4883); + public Object testField4884 = new Integer(4884); + public Object testField4885 = new Integer(4885); + public Object testField4886 = new Integer(4886); + public Object testField4887 = new Integer(4887); + public Object testField4888 = new Integer(4888); + public Object testField4889 = new Integer(4889); + public Object testField4890 = new Integer(4890); + public Object testField4891 = new Integer(4891); + public Object testField4892 = new Integer(4892); + public Object testField4893 = new Integer(4893); + public Object testField4894 = new Integer(4894); + public Object testField4895 = new Integer(4895); + public Object testField4896 = new Integer(4896); + public Object testField4897 = new Integer(4897); + public Object testField4898 = new Integer(4898); + public Object testField4899 = new Integer(4899); + public Object testField4900 = new Integer(4900); + public Object testField4901 = new Integer(4901); + public Object testField4902 = new Integer(4902); + public Object testField4903 = new Integer(4903); + public Object testField4904 = new Integer(4904); + public Object testField4905 = new Integer(4905); + public Object testField4906 = new Integer(4906); + public Object testField4907 = new Integer(4907); + public Object testField4908 = new Integer(4908); + public Object testField4909 = new Integer(4909); + public Object testField4910 = new Integer(4910); + public Object testField4911 = new Integer(4911); + public Object testField4912 = new Integer(4912); + public Object testField4913 = new Integer(4913); + public Object testField4914 = new Integer(4914); + public Object testField4915 = new Integer(4915); + public Object testField4916 = new Integer(4916); + public Object testField4917 = new Integer(4917); + public Object testField4918 = new Integer(4918); + public Object testField4919 = new Integer(4919); + public Object testField4920 = new Integer(4920); + public Object testField4921 = new Integer(4921); + public Object testField4922 = new Integer(4922); + public Object testField4923 = new Integer(4923); + public Object testField4924 = new Integer(4924); + public Object testField4925 = new Integer(4925); + public Object testField4926 = new Integer(4926); + public Object testField4927 = new Integer(4927); + public Object testField4928 = new Integer(4928); + public Object testField4929 = new Integer(4929); + public Object testField4930 = new Integer(4930); + public Object testField4931 = new Integer(4931); + public Object testField4932 = new Integer(4932); + public Object testField4933 = new Integer(4933); + public Object testField4934 = new Integer(4934); + public Object testField4935 = new Integer(4935); + public Object testField4936 = new Integer(4936); + public Object testField4937 = new Integer(4937); + public Object testField4938 = new Integer(4938); + public Object testField4939 = new Integer(4939); + public Object testField4940 = new Integer(4940); + public Object testField4941 = new Integer(4941); + public Object testField4942 = new Integer(4942); + public Object testField4943 = new Integer(4943); + public Object testField4944 = new Integer(4944); + public Object testField4945 = new Integer(4945); + public Object testField4946 = new Integer(4946); + public Object testField4947 = new Integer(4947); + public Object testField4948 = new Integer(4948); + public Object testField4949 = new Integer(4949); + public Object testField4950 = new Integer(4950); + public Object testField4951 = new Integer(4951); + public Object testField4952 = new Integer(4952); + public Object testField4953 = new Integer(4953); + public Object testField4954 = new Integer(4954); + public Object testField4955 = new Integer(4955); + public Object testField4956 = new Integer(4956); + public Object testField4957 = new Integer(4957); + public Object testField4958 = new Integer(4958); + public Object testField4959 = new Integer(4959); + public Object testField4960 = new Integer(4960); + public Object testField4961 = new Integer(4961); + public Object testField4962 = new Integer(4962); + public Object testField4963 = new Integer(4963); + public Object testField4964 = new Integer(4964); + public Object testField4965 = new Integer(4965); + public Object testField4966 = new Integer(4966); + public Object testField4967 = new Integer(4967); + public Object testField4968 = new Integer(4968); + public Object testField4969 = new Integer(4969); + public Object testField4970 = new Integer(4970); + public Object testField4971 = new Integer(4971); + public Object testField4972 = new Integer(4972); + public Object testField4973 = new Integer(4973); + public Object testField4974 = new Integer(4974); + public Object testField4975 = new Integer(4975); + public Object testField4976 = new Integer(4976); + public Object testField4977 = new Integer(4977); + public Object testField4978 = new Integer(4978); + public Object testField4979 = new Integer(4979); + public Object testField4980 = new Integer(4980); + public Object testField4981 = new Integer(4981); + public Object testField4982 = new Integer(4982); + public Object testField4983 = new Integer(4983); + public Object testField4984 = new Integer(4984); + public Object testField4985 = new Integer(4985); + public Object testField4986 = new Integer(4986); + public Object testField4987 = new Integer(4987); + public Object testField4988 = new Integer(4988); + public Object testField4989 = new Integer(4989); + public Object testField4990 = new Integer(4990); + public Object testField4991 = new Integer(4991); + public Object testField4992 = new Integer(4992); + public Object testField4993 = new Integer(4993); + public Object testField4994 = new Integer(4994); + public Object testField4995 = new Integer(4995); + public Object testField4996 = new Integer(4996); + public Object testField4997 = new Integer(4997); + public Object testField4998 = new Integer(4998); + public Object testField4999 = new Integer(4999); +} diff --git a/test/160-read-barrier-stress/src/ManyFieldsBase0.java b/test/160-read-barrier-stress/src/ManyFieldsBase0.java new file mode 100644 index 0000000000..1b6c2a608b --- /dev/null +++ b/test/160-read-barrier-stress/src/ManyFieldsBase0.java @@ -0,0 +1,1018 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +class ManyFieldsBase0 { + public Object testField0000 = new Integer(0); + public Object testField0001 = new Integer(1); + public Object testField0002 = new Integer(2); + public Object testField0003 = new Integer(3); + public Object testField0004 = new Integer(4); + public Object testField0005 = new Integer(5); + public Object testField0006 = new Integer(6); + public Object testField0007 = new Integer(7); + public Object testField0008 = new Integer(8); + public Object testField0009 = new Integer(9); + public Object testField0010 = new Integer(10); + public Object testField0011 = new Integer(11); + public Object testField0012 = new Integer(12); + public Object testField0013 = new Integer(13); + public Object testField0014 = new Integer(14); + public Object testField0015 = new Integer(15); + public Object testField0016 = new Integer(16); + public Object testField0017 = new Integer(17); + public Object testField0018 = new Integer(18); + public Object testField0019 = new Integer(19); + public Object testField0020 = new Integer(20); + public Object testField0021 = new Integer(21); + public Object testField0022 = new Integer(22); + public Object testField0023 = new Integer(23); + public Object testField0024 = new Integer(24); + public Object testField0025 = new Integer(25); + public Object testField0026 = new Integer(26); + public Object testField0027 = new Integer(27); + public Object testField0028 = new Integer(28); + public Object testField0029 = new Integer(29); + public Object testField0030 = new Integer(30); + public Object testField0031 = new Integer(31); + public Object testField0032 = new Integer(32); + public Object testField0033 = new Integer(33); + public Object testField0034 = new Integer(34); + public Object testField0035 = new Integer(35); + public Object testField0036 = new Integer(36); + public Object testField0037 = new Integer(37); + public Object testField0038 = new Integer(38); + public Object testField0039 = new Integer(39); + public Object testField0040 = new Integer(40); + public Object testField0041 = new Integer(41); + public Object testField0042 = new Integer(42); + public Object testField0043 = new Integer(43); + public Object testField0044 = new Integer(44); + public Object testField0045 = new Integer(45); + public Object testField0046 = new Integer(46); + public Object testField0047 = new Integer(47); + public Object testField0048 = new Integer(48); + public Object testField0049 = new Integer(49); + public Object testField0050 = new Integer(50); + public Object testField0051 = new Integer(51); + public Object testField0052 = new Integer(52); + public Object testField0053 = new Integer(53); + public Object testField0054 = new Integer(54); + public Object testField0055 = new Integer(55); + public Object testField0056 = new Integer(56); + public Object testField0057 = new Integer(57); + public Object testField0058 = new Integer(58); + public Object testField0059 = new Integer(59); + public Object testField0060 = new Integer(60); + public Object testField0061 = new Integer(61); + public Object testField0062 = new Integer(62); + public Object testField0063 = new Integer(63); + public Object testField0064 = new Integer(64); + public Object testField0065 = new Integer(65); + public Object testField0066 = new Integer(66); + public Object testField0067 = new Integer(67); + public Object testField0068 = new Integer(68); + public Object testField0069 = new Integer(69); + public Object testField0070 = new Integer(70); + public Object testField0071 = new Integer(71); + public Object testField0072 = new Integer(72); + public Object testField0073 = new Integer(73); + public Object testField0074 = new Integer(74); + public Object testField0075 = new Integer(75); + public Object testField0076 = new Integer(76); + public Object testField0077 = new Integer(77); + public Object testField0078 = new Integer(78); + public Object testField0079 = new Integer(79); + public Object testField0080 = new Integer(80); + public Object testField0081 = new Integer(81); + public Object testField0082 = new Integer(82); + public Object testField0083 = new Integer(83); + public Object testField0084 = new Integer(84); + public Object testField0085 = new Integer(85); + public Object testField0086 = new Integer(86); + public Object testField0087 = new Integer(87); + public Object testField0088 = new Integer(88); + public Object testField0089 = new Integer(89); + public Object testField0090 = new Integer(90); + public Object testField0091 = new Integer(91); + public Object testField0092 = new Integer(92); + public Object testField0093 = new Integer(93); + public Object testField0094 = new Integer(94); + public Object testField0095 = new Integer(95); + public Object testField0096 = new Integer(96); + public Object testField0097 = new Integer(97); + public Object testField0098 = new Integer(98); + public Object testField0099 = new Integer(99); + public Object testField0100 = new Integer(100); + public Object testField0101 = new Integer(101); + public Object testField0102 = new Integer(102); + public Object testField0103 = new Integer(103); + public Object testField0104 = new Integer(104); + public Object testField0105 = new Integer(105); + public Object testField0106 = new Integer(106); + public Object testField0107 = new Integer(107); + public Object testField0108 = new Integer(108); + public Object testField0109 = new Integer(109); + public Object testField0110 = new Integer(110); + public Object testField0111 = new Integer(111); + public Object testField0112 = new Integer(112); + public Object testField0113 = new Integer(113); + public Object testField0114 = new Integer(114); + public Object testField0115 = new Integer(115); + public Object testField0116 = new Integer(116); + public Object testField0117 = new Integer(117); + public Object testField0118 = new Integer(118); + public Object testField0119 = new Integer(119); + public Object testField0120 = new Integer(120); + public Object testField0121 = new Integer(121); + public Object testField0122 = new Integer(122); + public Object testField0123 = new Integer(123); + public Object testField0124 = new Integer(124); + public Object testField0125 = new Integer(125); + public Object testField0126 = new Integer(126); + public Object testField0127 = new Integer(127); + public Object testField0128 = new Integer(128); + public Object testField0129 = new Integer(129); + public Object testField0130 = new Integer(130); + public Object testField0131 = new Integer(131); + public Object testField0132 = new Integer(132); + public Object testField0133 = new Integer(133); + public Object testField0134 = new Integer(134); + public Object testField0135 = new Integer(135); + public Object testField0136 = new Integer(136); + public Object testField0137 = new Integer(137); + public Object testField0138 = new Integer(138); + public Object testField0139 = new Integer(139); + public Object testField0140 = new Integer(140); + public Object testField0141 = new Integer(141); + public Object testField0142 = new Integer(142); + public Object testField0143 = new Integer(143); + public Object testField0144 = new Integer(144); + public Object testField0145 = new Integer(145); + public Object testField0146 = new Integer(146); + public Object testField0147 = new Integer(147); + public Object testField0148 = new Integer(148); + public Object testField0149 = new Integer(149); + public Object testField0150 = new Integer(150); + public Object testField0151 = new Integer(151); + public Object testField0152 = new Integer(152); + public Object testField0153 = new Integer(153); + public Object testField0154 = new Integer(154); + public Object testField0155 = new Integer(155); + public Object testField0156 = new Integer(156); + public Object testField0157 = new Integer(157); + public Object testField0158 = new Integer(158); + public Object testField0159 = new Integer(159); + public Object testField0160 = new Integer(160); + public Object testField0161 = new Integer(161); + public Object testField0162 = new Integer(162); + public Object testField0163 = new Integer(163); + public Object testField0164 = new Integer(164); + public Object testField0165 = new Integer(165); + public Object testField0166 = new Integer(166); + public Object testField0167 = new Integer(167); + public Object testField0168 = new Integer(168); + public Object testField0169 = new Integer(169); + public Object testField0170 = new Integer(170); + public Object testField0171 = new Integer(171); + public Object testField0172 = new Integer(172); + public Object testField0173 = new Integer(173); + public Object testField0174 = new Integer(174); + public Object testField0175 = new Integer(175); + public Object testField0176 = new Integer(176); + public Object testField0177 = new Integer(177); + public Object testField0178 = new Integer(178); + public Object testField0179 = new Integer(179); + public Object testField0180 = new Integer(180); + public Object testField0181 = new Integer(181); + public Object testField0182 = new Integer(182); + public Object testField0183 = new Integer(183); + public Object testField0184 = new Integer(184); + public Object testField0185 = new Integer(185); + public Object testField0186 = new Integer(186); + public Object testField0187 = new Integer(187); + public Object testField0188 = new Integer(188); + public Object testField0189 = new Integer(189); + public Object testField0190 = new Integer(190); + public Object testField0191 = new Integer(191); + public Object testField0192 = new Integer(192); + public Object testField0193 = new Integer(193); + public Object testField0194 = new Integer(194); + public Object testField0195 = new Integer(195); + public Object testField0196 = new Integer(196); + public Object testField0197 = new Integer(197); + public Object testField0198 = new Integer(198); + public Object testField0199 = new Integer(199); + public Object testField0200 = new Integer(200); + public Object testField0201 = new Integer(201); + public Object testField0202 = new Integer(202); + public Object testField0203 = new Integer(203); + public Object testField0204 = new Integer(204); + public Object testField0205 = new Integer(205); + public Object testField0206 = new Integer(206); + public Object testField0207 = new Integer(207); + public Object testField0208 = new Integer(208); + public Object testField0209 = new Integer(209); + public Object testField0210 = new Integer(210); + public Object testField0211 = new Integer(211); + public Object testField0212 = new Integer(212); + public Object testField0213 = new Integer(213); + public Object testField0214 = new Integer(214); + public Object testField0215 = new Integer(215); + public Object testField0216 = new Integer(216); + public Object testField0217 = new Integer(217); + public Object testField0218 = new Integer(218); + public Object testField0219 = new Integer(219); + public Object testField0220 = new Integer(220); + public Object testField0221 = new Integer(221); + public Object testField0222 = new Integer(222); + public Object testField0223 = new Integer(223); + public Object testField0224 = new Integer(224); + public Object testField0225 = new Integer(225); + public Object testField0226 = new Integer(226); + public Object testField0227 = new Integer(227); + public Object testField0228 = new Integer(228); + public Object testField0229 = new Integer(229); + public Object testField0230 = new Integer(230); + public Object testField0231 = new Integer(231); + public Object testField0232 = new Integer(232); + public Object testField0233 = new Integer(233); + public Object testField0234 = new Integer(234); + public Object testField0235 = new Integer(235); + public Object testField0236 = new Integer(236); + public Object testField0237 = new Integer(237); + public Object testField0238 = new Integer(238); + public Object testField0239 = new Integer(239); + public Object testField0240 = new Integer(240); + public Object testField0241 = new Integer(241); + public Object testField0242 = new Integer(242); + public Object testField0243 = new Integer(243); + public Object testField0244 = new Integer(244); + public Object testField0245 = new Integer(245); + public Object testField0246 = new Integer(246); + public Object testField0247 = new Integer(247); + public Object testField0248 = new Integer(248); + public Object testField0249 = new Integer(249); + public Object testField0250 = new Integer(250); + public Object testField0251 = new Integer(251); + public Object testField0252 = new Integer(252); + public Object testField0253 = new Integer(253); + public Object testField0254 = new Integer(254); + public Object testField0255 = new Integer(255); + public Object testField0256 = new Integer(256); + public Object testField0257 = new Integer(257); + public Object testField0258 = new Integer(258); + public Object testField0259 = new Integer(259); + public Object testField0260 = new Integer(260); + public Object testField0261 = new Integer(261); + public Object testField0262 = new Integer(262); + public Object testField0263 = new Integer(263); + public Object testField0264 = new Integer(264); + public Object testField0265 = new Integer(265); + public Object testField0266 = new Integer(266); + public Object testField0267 = new Integer(267); + public Object testField0268 = new Integer(268); + public Object testField0269 = new Integer(269); + public Object testField0270 = new Integer(270); + public Object testField0271 = new Integer(271); + public Object testField0272 = new Integer(272); + public Object testField0273 = new Integer(273); + public Object testField0274 = new Integer(274); + public Object testField0275 = new Integer(275); + public Object testField0276 = new Integer(276); + public Object testField0277 = new Integer(277); + public Object testField0278 = new Integer(278); + public Object testField0279 = new Integer(279); + public Object testField0280 = new Integer(280); + public Object testField0281 = new Integer(281); + public Object testField0282 = new Integer(282); + public Object testField0283 = new Integer(283); + public Object testField0284 = new Integer(284); + public Object testField0285 = new Integer(285); + public Object testField0286 = new Integer(286); + public Object testField0287 = new Integer(287); + public Object testField0288 = new Integer(288); + public Object testField0289 = new Integer(289); + public Object testField0290 = new Integer(290); + public Object testField0291 = new Integer(291); + public Object testField0292 = new Integer(292); + public Object testField0293 = new Integer(293); + public Object testField0294 = new Integer(294); + public Object testField0295 = new Integer(295); + public Object testField0296 = new Integer(296); + public Object testField0297 = new Integer(297); + public Object testField0298 = new Integer(298); + public Object testField0299 = new Integer(299); + public Object testField0300 = new Integer(300); + public Object testField0301 = new Integer(301); + public Object testField0302 = new Integer(302); + public Object testField0303 = new Integer(303); + public Object testField0304 = new Integer(304); + public Object testField0305 = new Integer(305); + public Object testField0306 = new Integer(306); + public Object testField0307 = new Integer(307); + public Object testField0308 = new Integer(308); + public Object testField0309 = new Integer(309); + public Object testField0310 = new Integer(310); + public Object testField0311 = new Integer(311); + public Object testField0312 = new Integer(312); + public Object testField0313 = new Integer(313); + public Object testField0314 = new Integer(314); + public Object testField0315 = new Integer(315); + public Object testField0316 = new Integer(316); + public Object testField0317 = new Integer(317); + public Object testField0318 = new Integer(318); + public Object testField0319 = new Integer(319); + public Object testField0320 = new Integer(320); + public Object testField0321 = new Integer(321); + public Object testField0322 = new Integer(322); + public Object testField0323 = new Integer(323); + public Object testField0324 = new Integer(324); + public Object testField0325 = new Integer(325); + public Object testField0326 = new Integer(326); + public Object testField0327 = new Integer(327); + public Object testField0328 = new Integer(328); + public Object testField0329 = new Integer(329); + public Object testField0330 = new Integer(330); + public Object testField0331 = new Integer(331); + public Object testField0332 = new Integer(332); + public Object testField0333 = new Integer(333); + public Object testField0334 = new Integer(334); + public Object testField0335 = new Integer(335); + public Object testField0336 = new Integer(336); + public Object testField0337 = new Integer(337); + public Object testField0338 = new Integer(338); + public Object testField0339 = new Integer(339); + public Object testField0340 = new Integer(340); + public Object testField0341 = new Integer(341); + public Object testField0342 = new Integer(342); + public Object testField0343 = new Integer(343); + public Object testField0344 = new Integer(344); + public Object testField0345 = new Integer(345); + public Object testField0346 = new Integer(346); + public Object testField0347 = new Integer(347); + public Object testField0348 = new Integer(348); + public Object testField0349 = new Integer(349); + public Object testField0350 = new Integer(350); + public Object testField0351 = new Integer(351); + public Object testField0352 = new Integer(352); + public Object testField0353 = new Integer(353); + public Object testField0354 = new Integer(354); + public Object testField0355 = new Integer(355); + public Object testField0356 = new Integer(356); + public Object testField0357 = new Integer(357); + public Object testField0358 = new Integer(358); + public Object testField0359 = new Integer(359); + public Object testField0360 = new Integer(360); + public Object testField0361 = new Integer(361); + public Object testField0362 = new Integer(362); + public Object testField0363 = new Integer(363); + public Object testField0364 = new Integer(364); + public Object testField0365 = new Integer(365); + public Object testField0366 = new Integer(366); + public Object testField0367 = new Integer(367); + public Object testField0368 = new Integer(368); + public Object testField0369 = new Integer(369); + public Object testField0370 = new Integer(370); + public Object testField0371 = new Integer(371); + public Object testField0372 = new Integer(372); + public Object testField0373 = new Integer(373); + public Object testField0374 = new Integer(374); + public Object testField0375 = new Integer(375); + public Object testField0376 = new Integer(376); + public Object testField0377 = new Integer(377); + public Object testField0378 = new Integer(378); + public Object testField0379 = new Integer(379); + public Object testField0380 = new Integer(380); + public Object testField0381 = new Integer(381); + public Object testField0382 = new Integer(382); + public Object testField0383 = new Integer(383); + public Object testField0384 = new Integer(384); + public Object testField0385 = new Integer(385); + public Object testField0386 = new Integer(386); + public Object testField0387 = new Integer(387); + public Object testField0388 = new Integer(388); + public Object testField0389 = new Integer(389); + public Object testField0390 = new Integer(390); + public Object testField0391 = new Integer(391); + public Object testField0392 = new Integer(392); + public Object testField0393 = new Integer(393); + public Object testField0394 = new Integer(394); + public Object testField0395 = new Integer(395); + public Object testField0396 = new Integer(396); + public Object testField0397 = new Integer(397); + public Object testField0398 = new Integer(398); + public Object testField0399 = new Integer(399); + public Object testField0400 = new Integer(400); + public Object testField0401 = new Integer(401); + public Object testField0402 = new Integer(402); + public Object testField0403 = new Integer(403); + public Object testField0404 = new Integer(404); + public Object testField0405 = new Integer(405); + public Object testField0406 = new Integer(406); + public Object testField0407 = new Integer(407); + public Object testField0408 = new Integer(408); + public Object testField0409 = new Integer(409); + public Object testField0410 = new Integer(410); + public Object testField0411 = new Integer(411); + public Object testField0412 = new Integer(412); + public Object testField0413 = new Integer(413); + public Object testField0414 = new Integer(414); + public Object testField0415 = new Integer(415); + public Object testField0416 = new Integer(416); + public Object testField0417 = new Integer(417); + public Object testField0418 = new Integer(418); + public Object testField0419 = new Integer(419); + public Object testField0420 = new Integer(420); + public Object testField0421 = new Integer(421); + public Object testField0422 = new Integer(422); + public Object testField0423 = new Integer(423); + public Object testField0424 = new Integer(424); + public Object testField0425 = new Integer(425); + public Object testField0426 = new Integer(426); + public Object testField0427 = new Integer(427); + public Object testField0428 = new Integer(428); + public Object testField0429 = new Integer(429); + public Object testField0430 = new Integer(430); + public Object testField0431 = new Integer(431); + public Object testField0432 = new Integer(432); + public Object testField0433 = new Integer(433); + public Object testField0434 = new Integer(434); + public Object testField0435 = new Integer(435); + public Object testField0436 = new Integer(436); + public Object testField0437 = new Integer(437); + public Object testField0438 = new Integer(438); + public Object testField0439 = new Integer(439); + public Object testField0440 = new Integer(440); + public Object testField0441 = new Integer(441); + public Object testField0442 = new Integer(442); + public Object testField0443 = new Integer(443); + public Object testField0444 = new Integer(444); + public Object testField0445 = new Integer(445); + public Object testField0446 = new Integer(446); + public Object testField0447 = new Integer(447); + public Object testField0448 = new Integer(448); + public Object testField0449 = new Integer(449); + public Object testField0450 = new Integer(450); + public Object testField0451 = new Integer(451); + public Object testField0452 = new Integer(452); + public Object testField0453 = new Integer(453); + public Object testField0454 = new Integer(454); + public Object testField0455 = new Integer(455); + public Object testField0456 = new Integer(456); + public Object testField0457 = new Integer(457); + public Object testField0458 = new Integer(458); + public Object testField0459 = new Integer(459); + public Object testField0460 = new Integer(460); + public Object testField0461 = new Integer(461); + public Object testField0462 = new Integer(462); + public Object testField0463 = new Integer(463); + public Object testField0464 = new Integer(464); + public Object testField0465 = new Integer(465); + public Object testField0466 = new Integer(466); + public Object testField0467 = new Integer(467); + public Object testField0468 = new Integer(468); + public Object testField0469 = new Integer(469); + public Object testField0470 = new Integer(470); + public Object testField0471 = new Integer(471); + public Object testField0472 = new Integer(472); + public Object testField0473 = new Integer(473); + public Object testField0474 = new Integer(474); + public Object testField0475 = new Integer(475); + public Object testField0476 = new Integer(476); + public Object testField0477 = new Integer(477); + public Object testField0478 = new Integer(478); + public Object testField0479 = new Integer(479); + public Object testField0480 = new Integer(480); + public Object testField0481 = new Integer(481); + public Object testField0482 = new Integer(482); + public Object testField0483 = new Integer(483); + public Object testField0484 = new Integer(484); + public Object testField0485 = new Integer(485); + public Object testField0486 = new Integer(486); + public Object testField0487 = new Integer(487); + public Object testField0488 = new Integer(488); + public Object testField0489 = new Integer(489); + public Object testField0490 = new Integer(490); + public Object testField0491 = new Integer(491); + public Object testField0492 = new Integer(492); + public Object testField0493 = new Integer(493); + public Object testField0494 = new Integer(494); + public Object testField0495 = new Integer(495); + public Object testField0496 = new Integer(496); + public Object testField0497 = new Integer(497); + public Object testField0498 = new Integer(498); + public Object testField0499 = new Integer(499); + public Object testField0500 = new Integer(500); + public Object testField0501 = new Integer(501); + public Object testField0502 = new Integer(502); + public Object testField0503 = new Integer(503); + public Object testField0504 = new Integer(504); + public Object testField0505 = new Integer(505); + public Object testField0506 = new Integer(506); + public Object testField0507 = new Integer(507); + public Object testField0508 = new Integer(508); + public Object testField0509 = new Integer(509); + public Object testField0510 = new Integer(510); + public Object testField0511 = new Integer(511); + public Object testField0512 = new Integer(512); + public Object testField0513 = new Integer(513); + public Object testField0514 = new Integer(514); + public Object testField0515 = new Integer(515); + public Object testField0516 = new Integer(516); + public Object testField0517 = new Integer(517); + public Object testField0518 = new Integer(518); + public Object testField0519 = new Integer(519); + public Object testField0520 = new Integer(520); + public Object testField0521 = new Integer(521); + public Object testField0522 = new Integer(522); + public Object testField0523 = new Integer(523); + public Object testField0524 = new Integer(524); + public Object testField0525 = new Integer(525); + public Object testField0526 = new Integer(526); + public Object testField0527 = new Integer(527); + public Object testField0528 = new Integer(528); + public Object testField0529 = new Integer(529); + public Object testField0530 = new Integer(530); + public Object testField0531 = new Integer(531); + public Object testField0532 = new Integer(532); + public Object testField0533 = new Integer(533); + public Object testField0534 = new Integer(534); + public Object testField0535 = new Integer(535); + public Object testField0536 = new Integer(536); + public Object testField0537 = new Integer(537); + public Object testField0538 = new Integer(538); + public Object testField0539 = new Integer(539); + public Object testField0540 = new Integer(540); + public Object testField0541 = new Integer(541); + public Object testField0542 = new Integer(542); + public Object testField0543 = new Integer(543); + public Object testField0544 = new Integer(544); + public Object testField0545 = new Integer(545); + public Object testField0546 = new Integer(546); + public Object testField0547 = new Integer(547); + public Object testField0548 = new Integer(548); + public Object testField0549 = new Integer(549); + public Object testField0550 = new Integer(550); + public Object testField0551 = new Integer(551); + public Object testField0552 = new Integer(552); + public Object testField0553 = new Integer(553); + public Object testField0554 = new Integer(554); + public Object testField0555 = new Integer(555); + public Object testField0556 = new Integer(556); + public Object testField0557 = new Integer(557); + public Object testField0558 = new Integer(558); + public Object testField0559 = new Integer(559); + public Object testField0560 = new Integer(560); + public Object testField0561 = new Integer(561); + public Object testField0562 = new Integer(562); + public Object testField0563 = new Integer(563); + public Object testField0564 = new Integer(564); + public Object testField0565 = new Integer(565); + public Object testField0566 = new Integer(566); + public Object testField0567 = new Integer(567); + public Object testField0568 = new Integer(568); + public Object testField0569 = new Integer(569); + public Object testField0570 = new Integer(570); + public Object testField0571 = new Integer(571); + public Object testField0572 = new Integer(572); + public Object testField0573 = new Integer(573); + public Object testField0574 = new Integer(574); + public Object testField0575 = new Integer(575); + public Object testField0576 = new Integer(576); + public Object testField0577 = new Integer(577); + public Object testField0578 = new Integer(578); + public Object testField0579 = new Integer(579); + public Object testField0580 = new Integer(580); + public Object testField0581 = new Integer(581); + public Object testField0582 = new Integer(582); + public Object testField0583 = new Integer(583); + public Object testField0584 = new Integer(584); + public Object testField0585 = new Integer(585); + public Object testField0586 = new Integer(586); + public Object testField0587 = new Integer(587); + public Object testField0588 = new Integer(588); + public Object testField0589 = new Integer(589); + public Object testField0590 = new Integer(590); + public Object testField0591 = new Integer(591); + public Object testField0592 = new Integer(592); + public Object testField0593 = new Integer(593); + public Object testField0594 = new Integer(594); + public Object testField0595 = new Integer(595); + public Object testField0596 = new Integer(596); + public Object testField0597 = new Integer(597); + public Object testField0598 = new Integer(598); + public Object testField0599 = new Integer(599); + public Object testField0600 = new Integer(600); + public Object testField0601 = new Integer(601); + public Object testField0602 = new Integer(602); + public Object testField0603 = new Integer(603); + public Object testField0604 = new Integer(604); + public Object testField0605 = new Integer(605); + public Object testField0606 = new Integer(606); + public Object testField0607 = new Integer(607); + public Object testField0608 = new Integer(608); + public Object testField0609 = new Integer(609); + public Object testField0610 = new Integer(610); + public Object testField0611 = new Integer(611); + public Object testField0612 = new Integer(612); + public Object testField0613 = new Integer(613); + public Object testField0614 = new Integer(614); + public Object testField0615 = new Integer(615); + public Object testField0616 = new Integer(616); + public Object testField0617 = new Integer(617); + public Object testField0618 = new Integer(618); + public Object testField0619 = new Integer(619); + public Object testField0620 = new Integer(620); + public Object testField0621 = new Integer(621); + public Object testField0622 = new Integer(622); + public Object testField0623 = new Integer(623); + public Object testField0624 = new Integer(624); + public Object testField0625 = new Integer(625); + public Object testField0626 = new Integer(626); + public Object testField0627 = new Integer(627); + public Object testField0628 = new Integer(628); + public Object testField0629 = new Integer(629); + public Object testField0630 = new Integer(630); + public Object testField0631 = new Integer(631); + public Object testField0632 = new Integer(632); + public Object testField0633 = new Integer(633); + public Object testField0634 = new Integer(634); + public Object testField0635 = new Integer(635); + public Object testField0636 = new Integer(636); + public Object testField0637 = new Integer(637); + public Object testField0638 = new Integer(638); + public Object testField0639 = new Integer(639); + public Object testField0640 = new Integer(640); + public Object testField0641 = new Integer(641); + public Object testField0642 = new Integer(642); + public Object testField0643 = new Integer(643); + public Object testField0644 = new Integer(644); + public Object testField0645 = new Integer(645); + public Object testField0646 = new Integer(646); + public Object testField0647 = new Integer(647); + public Object testField0648 = new Integer(648); + public Object testField0649 = new Integer(649); + public Object testField0650 = new Integer(650); + public Object testField0651 = new Integer(651); + public Object testField0652 = new Integer(652); + public Object testField0653 = new Integer(653); + public Object testField0654 = new Integer(654); + public Object testField0655 = new Integer(655); + public Object testField0656 = new Integer(656); + public Object testField0657 = new Integer(657); + public Object testField0658 = new Integer(658); + public Object testField0659 = new Integer(659); + public Object testField0660 = new Integer(660); + public Object testField0661 = new Integer(661); + public Object testField0662 = new Integer(662); + public Object testField0663 = new Integer(663); + public Object testField0664 = new Integer(664); + public Object testField0665 = new Integer(665); + public Object testField0666 = new Integer(666); + public Object testField0667 = new Integer(667); + public Object testField0668 = new Integer(668); + public Object testField0669 = new Integer(669); + public Object testField0670 = new Integer(670); + public Object testField0671 = new Integer(671); + public Object testField0672 = new Integer(672); + public Object testField0673 = new Integer(673); + public Object testField0674 = new Integer(674); + public Object testField0675 = new Integer(675); + public Object testField0676 = new Integer(676); + public Object testField0677 = new Integer(677); + public Object testField0678 = new Integer(678); + public Object testField0679 = new Integer(679); + public Object testField0680 = new Integer(680); + public Object testField0681 = new Integer(681); + public Object testField0682 = new Integer(682); + public Object testField0683 = new Integer(683); + public Object testField0684 = new Integer(684); + public Object testField0685 = new Integer(685); + public Object testField0686 = new Integer(686); + public Object testField0687 = new Integer(687); + public Object testField0688 = new Integer(688); + public Object testField0689 = new Integer(689); + public Object testField0690 = new Integer(690); + public Object testField0691 = new Integer(691); + public Object testField0692 = new Integer(692); + public Object testField0693 = new Integer(693); + public Object testField0694 = new Integer(694); + public Object testField0695 = new Integer(695); + public Object testField0696 = new Integer(696); + public Object testField0697 = new Integer(697); + public Object testField0698 = new Integer(698); + public Object testField0699 = new Integer(699); + public Object testField0700 = new Integer(700); + public Object testField0701 = new Integer(701); + public Object testField0702 = new Integer(702); + public Object testField0703 = new Integer(703); + public Object testField0704 = new Integer(704); + public Object testField0705 = new Integer(705); + public Object testField0706 = new Integer(706); + public Object testField0707 = new Integer(707); + public Object testField0708 = new Integer(708); + public Object testField0709 = new Integer(709); + public Object testField0710 = new Integer(710); + public Object testField0711 = new Integer(711); + public Object testField0712 = new Integer(712); + public Object testField0713 = new Integer(713); + public Object testField0714 = new Integer(714); + public Object testField0715 = new Integer(715); + public Object testField0716 = new Integer(716); + public Object testField0717 = new Integer(717); + public Object testField0718 = new Integer(718); + public Object testField0719 = new Integer(719); + public Object testField0720 = new Integer(720); + public Object testField0721 = new Integer(721); + public Object testField0722 = new Integer(722); + public Object testField0723 = new Integer(723); + public Object testField0724 = new Integer(724); + public Object testField0725 = new Integer(725); + public Object testField0726 = new Integer(726); + public Object testField0727 = new Integer(727); + public Object testField0728 = new Integer(728); + public Object testField0729 = new Integer(729); + public Object testField0730 = new Integer(730); + public Object testField0731 = new Integer(731); + public Object testField0732 = new Integer(732); + public Object testField0733 = new Integer(733); + public Object testField0734 = new Integer(734); + public Object testField0735 = new Integer(735); + public Object testField0736 = new Integer(736); + public Object testField0737 = new Integer(737); + public Object testField0738 = new Integer(738); + public Object testField0739 = new Integer(739); + public Object testField0740 = new Integer(740); + public Object testField0741 = new Integer(741); + public Object testField0742 = new Integer(742); + public Object testField0743 = new Integer(743); + public Object testField0744 = new Integer(744); + public Object testField0745 = new Integer(745); + public Object testField0746 = new Integer(746); + public Object testField0747 = new Integer(747); + public Object testField0748 = new Integer(748); + public Object testField0749 = new Integer(749); + public Object testField0750 = new Integer(750); + public Object testField0751 = new Integer(751); + public Object testField0752 = new Integer(752); + public Object testField0753 = new Integer(753); + public Object testField0754 = new Integer(754); + public Object testField0755 = new Integer(755); + public Object testField0756 = new Integer(756); + public Object testField0757 = new Integer(757); + public Object testField0758 = new Integer(758); + public Object testField0759 = new Integer(759); + public Object testField0760 = new Integer(760); + public Object testField0761 = new Integer(761); + public Object testField0762 = new Integer(762); + public Object testField0763 = new Integer(763); + public Object testField0764 = new Integer(764); + public Object testField0765 = new Integer(765); + public Object testField0766 = new Integer(766); + public Object testField0767 = new Integer(767); + public Object testField0768 = new Integer(768); + public Object testField0769 = new Integer(769); + public Object testField0770 = new Integer(770); + public Object testField0771 = new Integer(771); + public Object testField0772 = new Integer(772); + public Object testField0773 = new Integer(773); + public Object testField0774 = new Integer(774); + public Object testField0775 = new Integer(775); + public Object testField0776 = new Integer(776); + public Object testField0777 = new Integer(777); + public Object testField0778 = new Integer(778); + public Object testField0779 = new Integer(779); + public Object testField0780 = new Integer(780); + public Object testField0781 = new Integer(781); + public Object testField0782 = new Integer(782); + public Object testField0783 = new Integer(783); + public Object testField0784 = new Integer(784); + public Object testField0785 = new Integer(785); + public Object testField0786 = new Integer(786); + public Object testField0787 = new Integer(787); + public Object testField0788 = new Integer(788); + public Object testField0789 = new Integer(789); + public Object testField0790 = new Integer(790); + public Object testField0791 = new Integer(791); + public Object testField0792 = new Integer(792); + public Object testField0793 = new Integer(793); + public Object testField0794 = new Integer(794); + public Object testField0795 = new Integer(795); + public Object testField0796 = new Integer(796); + public Object testField0797 = new Integer(797); + public Object testField0798 = new Integer(798); + public Object testField0799 = new Integer(799); + public Object testField0800 = new Integer(800); + public Object testField0801 = new Integer(801); + public Object testField0802 = new Integer(802); + public Object testField0803 = new Integer(803); + public Object testField0804 = new Integer(804); + public Object testField0805 = new Integer(805); + public Object testField0806 = new Integer(806); + public Object testField0807 = new Integer(807); + public Object testField0808 = new Integer(808); + public Object testField0809 = new Integer(809); + public Object testField0810 = new Integer(810); + public Object testField0811 = new Integer(811); + public Object testField0812 = new Integer(812); + public Object testField0813 = new Integer(813); + public Object testField0814 = new Integer(814); + public Object testField0815 = new Integer(815); + public Object testField0816 = new Integer(816); + public Object testField0817 = new Integer(817); + public Object testField0818 = new Integer(818); + public Object testField0819 = new Integer(819); + public Object testField0820 = new Integer(820); + public Object testField0821 = new Integer(821); + public Object testField0822 = new Integer(822); + public Object testField0823 = new Integer(823); + public Object testField0824 = new Integer(824); + public Object testField0825 = new Integer(825); + public Object testField0826 = new Integer(826); + public Object testField0827 = new Integer(827); + public Object testField0828 = new Integer(828); + public Object testField0829 = new Integer(829); + public Object testField0830 = new Integer(830); + public Object testField0831 = new Integer(831); + public Object testField0832 = new Integer(832); + public Object testField0833 = new Integer(833); + public Object testField0834 = new Integer(834); + public Object testField0835 = new Integer(835); + public Object testField0836 = new Integer(836); + public Object testField0837 = new Integer(837); + public Object testField0838 = new Integer(838); + public Object testField0839 = new Integer(839); + public Object testField0840 = new Integer(840); + public Object testField0841 = new Integer(841); + public Object testField0842 = new Integer(842); + public Object testField0843 = new Integer(843); + public Object testField0844 = new Integer(844); + public Object testField0845 = new Integer(845); + public Object testField0846 = new Integer(846); + public Object testField0847 = new Integer(847); + public Object testField0848 = new Integer(848); + public Object testField0849 = new Integer(849); + public Object testField0850 = new Integer(850); + public Object testField0851 = new Integer(851); + public Object testField0852 = new Integer(852); + public Object testField0853 = new Integer(853); + public Object testField0854 = new Integer(854); + public Object testField0855 = new Integer(855); + public Object testField0856 = new Integer(856); + public Object testField0857 = new Integer(857); + public Object testField0858 = new Integer(858); + public Object testField0859 = new Integer(859); + public Object testField0860 = new Integer(860); + public Object testField0861 = new Integer(861); + public Object testField0862 = new Integer(862); + public Object testField0863 = new Integer(863); + public Object testField0864 = new Integer(864); + public Object testField0865 = new Integer(865); + public Object testField0866 = new Integer(866); + public Object testField0867 = new Integer(867); + public Object testField0868 = new Integer(868); + public Object testField0869 = new Integer(869); + public Object testField0870 = new Integer(870); + public Object testField0871 = new Integer(871); + public Object testField0872 = new Integer(872); + public Object testField0873 = new Integer(873); + public Object testField0874 = new Integer(874); + public Object testField0875 = new Integer(875); + public Object testField0876 = new Integer(876); + public Object testField0877 = new Integer(877); + public Object testField0878 = new Integer(878); + public Object testField0879 = new Integer(879); + public Object testField0880 = new Integer(880); + public Object testField0881 = new Integer(881); + public Object testField0882 = new Integer(882); + public Object testField0883 = new Integer(883); + public Object testField0884 = new Integer(884); + public Object testField0885 = new Integer(885); + public Object testField0886 = new Integer(886); + public Object testField0887 = new Integer(887); + public Object testField0888 = new Integer(888); + public Object testField0889 = new Integer(889); + public Object testField0890 = new Integer(890); + public Object testField0891 = new Integer(891); + public Object testField0892 = new Integer(892); + public Object testField0893 = new Integer(893); + public Object testField0894 = new Integer(894); + public Object testField0895 = new Integer(895); + public Object testField0896 = new Integer(896); + public Object testField0897 = new Integer(897); + public Object testField0898 = new Integer(898); + public Object testField0899 = new Integer(899); + public Object testField0900 = new Integer(900); + public Object testField0901 = new Integer(901); + public Object testField0902 = new Integer(902); + public Object testField0903 = new Integer(903); + public Object testField0904 = new Integer(904); + public Object testField0905 = new Integer(905); + public Object testField0906 = new Integer(906); + public Object testField0907 = new Integer(907); + public Object testField0908 = new Integer(908); + public Object testField0909 = new Integer(909); + public Object testField0910 = new Integer(910); + public Object testField0911 = new Integer(911); + public Object testField0912 = new Integer(912); + public Object testField0913 = new Integer(913); + public Object testField0914 = new Integer(914); + public Object testField0915 = new Integer(915); + public Object testField0916 = new Integer(916); + public Object testField0917 = new Integer(917); + public Object testField0918 = new Integer(918); + public Object testField0919 = new Integer(919); + public Object testField0920 = new Integer(920); + public Object testField0921 = new Integer(921); + public Object testField0922 = new Integer(922); + public Object testField0923 = new Integer(923); + public Object testField0924 = new Integer(924); + public Object testField0925 = new Integer(925); + public Object testField0926 = new Integer(926); + public Object testField0927 = new Integer(927); + public Object testField0928 = new Integer(928); + public Object testField0929 = new Integer(929); + public Object testField0930 = new Integer(930); + public Object testField0931 = new Integer(931); + public Object testField0932 = new Integer(932); + public Object testField0933 = new Integer(933); + public Object testField0934 = new Integer(934); + public Object testField0935 = new Integer(935); + public Object testField0936 = new Integer(936); + public Object testField0937 = new Integer(937); + public Object testField0938 = new Integer(938); + public Object testField0939 = new Integer(939); + public Object testField0940 = new Integer(940); + public Object testField0941 = new Integer(941); + public Object testField0942 = new Integer(942); + public Object testField0943 = new Integer(943); + public Object testField0944 = new Integer(944); + public Object testField0945 = new Integer(945); + public Object testField0946 = new Integer(946); + public Object testField0947 = new Integer(947); + public Object testField0948 = new Integer(948); + public Object testField0949 = new Integer(949); + public Object testField0950 = new Integer(950); + public Object testField0951 = new Integer(951); + public Object testField0952 = new Integer(952); + public Object testField0953 = new Integer(953); + public Object testField0954 = new Integer(954); + public Object testField0955 = new Integer(955); + public Object testField0956 = new Integer(956); + public Object testField0957 = new Integer(957); + public Object testField0958 = new Integer(958); + public Object testField0959 = new Integer(959); + public Object testField0960 = new Integer(960); + public Object testField0961 = new Integer(961); + public Object testField0962 = new Integer(962); + public Object testField0963 = new Integer(963); + public Object testField0964 = new Integer(964); + public Object testField0965 = new Integer(965); + public Object testField0966 = new Integer(966); + public Object testField0967 = new Integer(967); + public Object testField0968 = new Integer(968); + public Object testField0969 = new Integer(969); + public Object testField0970 = new Integer(970); + public Object testField0971 = new Integer(971); + public Object testField0972 = new Integer(972); + public Object testField0973 = new Integer(973); + public Object testField0974 = new Integer(974); + public Object testField0975 = new Integer(975); + public Object testField0976 = new Integer(976); + public Object testField0977 = new Integer(977); + public Object testField0978 = new Integer(978); + public Object testField0979 = new Integer(979); + public Object testField0980 = new Integer(980); + public Object testField0981 = new Integer(981); + public Object testField0982 = new Integer(982); + public Object testField0983 = new Integer(983); + public Object testField0984 = new Integer(984); + public Object testField0985 = new Integer(985); + public Object testField0986 = new Integer(986); + public Object testField0987 = new Integer(987); + public Object testField0988 = new Integer(988); + public Object testField0989 = new Integer(989); + public Object testField0990 = new Integer(990); + public Object testField0991 = new Integer(991); + public Object testField0992 = new Integer(992); + public Object testField0993 = new Integer(993); + public Object testField0994 = new Integer(994); + public Object testField0995 = new Integer(995); + public Object testField0996 = new Integer(996); + public Object testField0997 = new Integer(997); + public Object testField0998 = new Integer(998); + public Object testField0999 = new Integer(999); +} diff --git a/test/160-read-barrier-stress/src/ManyFieldsBase1.java b/test/160-read-barrier-stress/src/ManyFieldsBase1.java new file mode 100644 index 0000000000..8680c6bb03 --- /dev/null +++ b/test/160-read-barrier-stress/src/ManyFieldsBase1.java @@ -0,0 +1,1018 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +class ManyFieldsBase1 extends ManyFieldsBase0 { + public Object testField1000 = new Integer(1000); + public Object testField1001 = new Integer(1001); + public Object testField1002 = new Integer(1002); + public Object testField1003 = new Integer(1003); + public Object testField1004 = new Integer(1004); + public Object testField1005 = new Integer(1005); + public Object testField1006 = new Integer(1006); + public Object testField1007 = new Integer(1007); + public Object testField1008 = new Integer(1008); + public Object testField1009 = new Integer(1009); + public Object testField1010 = new Integer(1010); + public Object testField1011 = new Integer(1011); + public Object testField1012 = new Integer(1012); + public Object testField1013 = new Integer(1013); + public Object testField1014 = new Integer(1014); + public Object testField1015 = new Integer(1015); + public Object testField1016 = new Integer(1016); + public Object testField1017 = new Integer(1017); + public Object testField1018 = new Integer(1018); + public Object testField1019 = new Integer(1019); + public Object testField1020 = new Integer(1020); + public Object testField1021 = new Integer(1021); + public Object testField1022 = new Integer(1022); + public Object testField1023 = new Integer(1023); + public Object testField1024 = new Integer(1024); + public Object testField1025 = new Integer(1025); + public Object testField1026 = new Integer(1026); + public Object testField1027 = new Integer(1027); + public Object testField1028 = new Integer(1028); + public Object testField1029 = new Integer(1029); + public Object testField1030 = new Integer(1030); + public Object testField1031 = new Integer(1031); + public Object testField1032 = new Integer(1032); + public Object testField1033 = new Integer(1033); + public Object testField1034 = new Integer(1034); + public Object testField1035 = new Integer(1035); + public Object testField1036 = new Integer(1036); + public Object testField1037 = new Integer(1037); + public Object testField1038 = new Integer(1038); + public Object testField1039 = new Integer(1039); + public Object testField1040 = new Integer(1040); + public Object testField1041 = new Integer(1041); + public Object testField1042 = new Integer(1042); + public Object testField1043 = new Integer(1043); + public Object testField1044 = new Integer(1044); + public Object testField1045 = new Integer(1045); + public Object testField1046 = new Integer(1046); + public Object testField1047 = new Integer(1047); + public Object testField1048 = new Integer(1048); + public Object testField1049 = new Integer(1049); + public Object testField1050 = new Integer(1050); + public Object testField1051 = new Integer(1051); + public Object testField1052 = new Integer(1052); + public Object testField1053 = new Integer(1053); + public Object testField1054 = new Integer(1054); + public Object testField1055 = new Integer(1055); + public Object testField1056 = new Integer(1056); + public Object testField1057 = new Integer(1057); + public Object testField1058 = new Integer(1058); + public Object testField1059 = new Integer(1059); + public Object testField1060 = new Integer(1060); + public Object testField1061 = new Integer(1061); + public Object testField1062 = new Integer(1062); + public Object testField1063 = new Integer(1063); + public Object testField1064 = new Integer(1064); + public Object testField1065 = new Integer(1065); + public Object testField1066 = new Integer(1066); + public Object testField1067 = new Integer(1067); + public Object testField1068 = new Integer(1068); + public Object testField1069 = new Integer(1069); + public Object testField1070 = new Integer(1070); + public Object testField1071 = new Integer(1071); + public Object testField1072 = new Integer(1072); + public Object testField1073 = new Integer(1073); + public Object testField1074 = new Integer(1074); + public Object testField1075 = new Integer(1075); + public Object testField1076 = new Integer(1076); + public Object testField1077 = new Integer(1077); + public Object testField1078 = new Integer(1078); + public Object testField1079 = new Integer(1079); + public Object testField1080 = new Integer(1080); + public Object testField1081 = new Integer(1081); + public Object testField1082 = new Integer(1082); + public Object testField1083 = new Integer(1083); + public Object testField1084 = new Integer(1084); + public Object testField1085 = new Integer(1085); + public Object testField1086 = new Integer(1086); + public Object testField1087 = new Integer(1087); + public Object testField1088 = new Integer(1088); + public Object testField1089 = new Integer(1089); + public Object testField1090 = new Integer(1090); + public Object testField1091 = new Integer(1091); + public Object testField1092 = new Integer(1092); + public Object testField1093 = new Integer(1093); + public Object testField1094 = new Integer(1094); + public Object testField1095 = new Integer(1095); + public Object testField1096 = new Integer(1096); + public Object testField1097 = new Integer(1097); + public Object testField1098 = new Integer(1098); + public Object testField1099 = new Integer(1099); + public Object testField1100 = new Integer(1100); + public Object testField1101 = new Integer(1101); + public Object testField1102 = new Integer(1102); + public Object testField1103 = new Integer(1103); + public Object testField1104 = new Integer(1104); + public Object testField1105 = new Integer(1105); + public Object testField1106 = new Integer(1106); + public Object testField1107 = new Integer(1107); + public Object testField1108 = new Integer(1108); + public Object testField1109 = new Integer(1109); + public Object testField1110 = new Integer(1110); + public Object testField1111 = new Integer(1111); + public Object testField1112 = new Integer(1112); + public Object testField1113 = new Integer(1113); + public Object testField1114 = new Integer(1114); + public Object testField1115 = new Integer(1115); + public Object testField1116 = new Integer(1116); + public Object testField1117 = new Integer(1117); + public Object testField1118 = new Integer(1118); + public Object testField1119 = new Integer(1119); + public Object testField1120 = new Integer(1120); + public Object testField1121 = new Integer(1121); + public Object testField1122 = new Integer(1122); + public Object testField1123 = new Integer(1123); + public Object testField1124 = new Integer(1124); + public Object testField1125 = new Integer(1125); + public Object testField1126 = new Integer(1126); + public Object testField1127 = new Integer(1127); + public Object testField1128 = new Integer(1128); + public Object testField1129 = new Integer(1129); + public Object testField1130 = new Integer(1130); + public Object testField1131 = new Integer(1131); + public Object testField1132 = new Integer(1132); + public Object testField1133 = new Integer(1133); + public Object testField1134 = new Integer(1134); + public Object testField1135 = new Integer(1135); + public Object testField1136 = new Integer(1136); + public Object testField1137 = new Integer(1137); + public Object testField1138 = new Integer(1138); + public Object testField1139 = new Integer(1139); + public Object testField1140 = new Integer(1140); + public Object testField1141 = new Integer(1141); + public Object testField1142 = new Integer(1142); + public Object testField1143 = new Integer(1143); + public Object testField1144 = new Integer(1144); + public Object testField1145 = new Integer(1145); + public Object testField1146 = new Integer(1146); + public Object testField1147 = new Integer(1147); + public Object testField1148 = new Integer(1148); + public Object testField1149 = new Integer(1149); + public Object testField1150 = new Integer(1150); + public Object testField1151 = new Integer(1151); + public Object testField1152 = new Integer(1152); + public Object testField1153 = new Integer(1153); + public Object testField1154 = new Integer(1154); + public Object testField1155 = new Integer(1155); + public Object testField1156 = new Integer(1156); + public Object testField1157 = new Integer(1157); + public Object testField1158 = new Integer(1158); + public Object testField1159 = new Integer(1159); + public Object testField1160 = new Integer(1160); + public Object testField1161 = new Integer(1161); + public Object testField1162 = new Integer(1162); + public Object testField1163 = new Integer(1163); + public Object testField1164 = new Integer(1164); + public Object testField1165 = new Integer(1165); + public Object testField1166 = new Integer(1166); + public Object testField1167 = new Integer(1167); + public Object testField1168 = new Integer(1168); + public Object testField1169 = new Integer(1169); + public Object testField1170 = new Integer(1170); + public Object testField1171 = new Integer(1171); + public Object testField1172 = new Integer(1172); + public Object testField1173 = new Integer(1173); + public Object testField1174 = new Integer(1174); + public Object testField1175 = new Integer(1175); + public Object testField1176 = new Integer(1176); + public Object testField1177 = new Integer(1177); + public Object testField1178 = new Integer(1178); + public Object testField1179 = new Integer(1179); + public Object testField1180 = new Integer(1180); + public Object testField1181 = new Integer(1181); + public Object testField1182 = new Integer(1182); + public Object testField1183 = new Integer(1183); + public Object testField1184 = new Integer(1184); + public Object testField1185 = new Integer(1185); + public Object testField1186 = new Integer(1186); + public Object testField1187 = new Integer(1187); + public Object testField1188 = new Integer(1188); + public Object testField1189 = new Integer(1189); + public Object testField1190 = new Integer(1190); + public Object testField1191 = new Integer(1191); + public Object testField1192 = new Integer(1192); + public Object testField1193 = new Integer(1193); + public Object testField1194 = new Integer(1194); + public Object testField1195 = new Integer(1195); + public Object testField1196 = new Integer(1196); + public Object testField1197 = new Integer(1197); + public Object testField1198 = new Integer(1198); + public Object testField1199 = new Integer(1199); + public Object testField1200 = new Integer(1200); + public Object testField1201 = new Integer(1201); + public Object testField1202 = new Integer(1202); + public Object testField1203 = new Integer(1203); + public Object testField1204 = new Integer(1204); + public Object testField1205 = new Integer(1205); + public Object testField1206 = new Integer(1206); + public Object testField1207 = new Integer(1207); + public Object testField1208 = new Integer(1208); + public Object testField1209 = new Integer(1209); + public Object testField1210 = new Integer(1210); + public Object testField1211 = new Integer(1211); + public Object testField1212 = new Integer(1212); + public Object testField1213 = new Integer(1213); + public Object testField1214 = new Integer(1214); + public Object testField1215 = new Integer(1215); + public Object testField1216 = new Integer(1216); + public Object testField1217 = new Integer(1217); + public Object testField1218 = new Integer(1218); + public Object testField1219 = new Integer(1219); + public Object testField1220 = new Integer(1220); + public Object testField1221 = new Integer(1221); + public Object testField1222 = new Integer(1222); + public Object testField1223 = new Integer(1223); + public Object testField1224 = new Integer(1224); + public Object testField1225 = new Integer(1225); + public Object testField1226 = new Integer(1226); + public Object testField1227 = new Integer(1227); + public Object testField1228 = new Integer(1228); + public Object testField1229 = new Integer(1229); + public Object testField1230 = new Integer(1230); + public Object testField1231 = new Integer(1231); + public Object testField1232 = new Integer(1232); + public Object testField1233 = new Integer(1233); + public Object testField1234 = new Integer(1234); + public Object testField1235 = new Integer(1235); + public Object testField1236 = new Integer(1236); + public Object testField1237 = new Integer(1237); + public Object testField1238 = new Integer(1238); + public Object testField1239 = new Integer(1239); + public Object testField1240 = new Integer(1240); + public Object testField1241 = new Integer(1241); + public Object testField1242 = new Integer(1242); + public Object testField1243 = new Integer(1243); + public Object testField1244 = new Integer(1244); + public Object testField1245 = new Integer(1245); + public Object testField1246 = new Integer(1246); + public Object testField1247 = new Integer(1247); + public Object testField1248 = new Integer(1248); + public Object testField1249 = new Integer(1249); + public Object testField1250 = new Integer(1250); + public Object testField1251 = new Integer(1251); + public Object testField1252 = new Integer(1252); + public Object testField1253 = new Integer(1253); + public Object testField1254 = new Integer(1254); + public Object testField1255 = new Integer(1255); + public Object testField1256 = new Integer(1256); + public Object testField1257 = new Integer(1257); + public Object testField1258 = new Integer(1258); + public Object testField1259 = new Integer(1259); + public Object testField1260 = new Integer(1260); + public Object testField1261 = new Integer(1261); + public Object testField1262 = new Integer(1262); + public Object testField1263 = new Integer(1263); + public Object testField1264 = new Integer(1264); + public Object testField1265 = new Integer(1265); + public Object testField1266 = new Integer(1266); + public Object testField1267 = new Integer(1267); + public Object testField1268 = new Integer(1268); + public Object testField1269 = new Integer(1269); + public Object testField1270 = new Integer(1270); + public Object testField1271 = new Integer(1271); + public Object testField1272 = new Integer(1272); + public Object testField1273 = new Integer(1273); + public Object testField1274 = new Integer(1274); + public Object testField1275 = new Integer(1275); + public Object testField1276 = new Integer(1276); + public Object testField1277 = new Integer(1277); + public Object testField1278 = new Integer(1278); + public Object testField1279 = new Integer(1279); + public Object testField1280 = new Integer(1280); + public Object testField1281 = new Integer(1281); + public Object testField1282 = new Integer(1282); + public Object testField1283 = new Integer(1283); + public Object testField1284 = new Integer(1284); + public Object testField1285 = new Integer(1285); + public Object testField1286 = new Integer(1286); + public Object testField1287 = new Integer(1287); + public Object testField1288 = new Integer(1288); + public Object testField1289 = new Integer(1289); + public Object testField1290 = new Integer(1290); + public Object testField1291 = new Integer(1291); + public Object testField1292 = new Integer(1292); + public Object testField1293 = new Integer(1293); + public Object testField1294 = new Integer(1294); + public Object testField1295 = new Integer(1295); + public Object testField1296 = new Integer(1296); + public Object testField1297 = new Integer(1297); + public Object testField1298 = new Integer(1298); + public Object testField1299 = new Integer(1299); + public Object testField1300 = new Integer(1300); + public Object testField1301 = new Integer(1301); + public Object testField1302 = new Integer(1302); + public Object testField1303 = new Integer(1303); + public Object testField1304 = new Integer(1304); + public Object testField1305 = new Integer(1305); + public Object testField1306 = new Integer(1306); + public Object testField1307 = new Integer(1307); + public Object testField1308 = new Integer(1308); + public Object testField1309 = new Integer(1309); + public Object testField1310 = new Integer(1310); + public Object testField1311 = new Integer(1311); + public Object testField1312 = new Integer(1312); + public Object testField1313 = new Integer(1313); + public Object testField1314 = new Integer(1314); + public Object testField1315 = new Integer(1315); + public Object testField1316 = new Integer(1316); + public Object testField1317 = new Integer(1317); + public Object testField1318 = new Integer(1318); + public Object testField1319 = new Integer(1319); + public Object testField1320 = new Integer(1320); + public Object testField1321 = new Integer(1321); + public Object testField1322 = new Integer(1322); + public Object testField1323 = new Integer(1323); + public Object testField1324 = new Integer(1324); + public Object testField1325 = new Integer(1325); + public Object testField1326 = new Integer(1326); + public Object testField1327 = new Integer(1327); + public Object testField1328 = new Integer(1328); + public Object testField1329 = new Integer(1329); + public Object testField1330 = new Integer(1330); + public Object testField1331 = new Integer(1331); + public Object testField1332 = new Integer(1332); + public Object testField1333 = new Integer(1333); + public Object testField1334 = new Integer(1334); + public Object testField1335 = new Integer(1335); + public Object testField1336 = new Integer(1336); + public Object testField1337 = new Integer(1337); + public Object testField1338 = new Integer(1338); + public Object testField1339 = new Integer(1339); + public Object testField1340 = new Integer(1340); + public Object testField1341 = new Integer(1341); + public Object testField1342 = new Integer(1342); + public Object testField1343 = new Integer(1343); + public Object testField1344 = new Integer(1344); + public Object testField1345 = new Integer(1345); + public Object testField1346 = new Integer(1346); + public Object testField1347 = new Integer(1347); + public Object testField1348 = new Integer(1348); + public Object testField1349 = new Integer(1349); + public Object testField1350 = new Integer(1350); + public Object testField1351 = new Integer(1351); + public Object testField1352 = new Integer(1352); + public Object testField1353 = new Integer(1353); + public Object testField1354 = new Integer(1354); + public Object testField1355 = new Integer(1355); + public Object testField1356 = new Integer(1356); + public Object testField1357 = new Integer(1357); + public Object testField1358 = new Integer(1358); + public Object testField1359 = new Integer(1359); + public Object testField1360 = new Integer(1360); + public Object testField1361 = new Integer(1361); + public Object testField1362 = new Integer(1362); + public Object testField1363 = new Integer(1363); + public Object testField1364 = new Integer(1364); + public Object testField1365 = new Integer(1365); + public Object testField1366 = new Integer(1366); + public Object testField1367 = new Integer(1367); + public Object testField1368 = new Integer(1368); + public Object testField1369 = new Integer(1369); + public Object testField1370 = new Integer(1370); + public Object testField1371 = new Integer(1371); + public Object testField1372 = new Integer(1372); + public Object testField1373 = new Integer(1373); + public Object testField1374 = new Integer(1374); + public Object testField1375 = new Integer(1375); + public Object testField1376 = new Integer(1376); + public Object testField1377 = new Integer(1377); + public Object testField1378 = new Integer(1378); + public Object testField1379 = new Integer(1379); + public Object testField1380 = new Integer(1380); + public Object testField1381 = new Integer(1381); + public Object testField1382 = new Integer(1382); + public Object testField1383 = new Integer(1383); + public Object testField1384 = new Integer(1384); + public Object testField1385 = new Integer(1385); + public Object testField1386 = new Integer(1386); + public Object testField1387 = new Integer(1387); + public Object testField1388 = new Integer(1388); + public Object testField1389 = new Integer(1389); + public Object testField1390 = new Integer(1390); + public Object testField1391 = new Integer(1391); + public Object testField1392 = new Integer(1392); + public Object testField1393 = new Integer(1393); + public Object testField1394 = new Integer(1394); + public Object testField1395 = new Integer(1395); + public Object testField1396 = new Integer(1396); + public Object testField1397 = new Integer(1397); + public Object testField1398 = new Integer(1398); + public Object testField1399 = new Integer(1399); + public Object testField1400 = new Integer(1400); + public Object testField1401 = new Integer(1401); + public Object testField1402 = new Integer(1402); + public Object testField1403 = new Integer(1403); + public Object testField1404 = new Integer(1404); + public Object testField1405 = new Integer(1405); + public Object testField1406 = new Integer(1406); + public Object testField1407 = new Integer(1407); + public Object testField1408 = new Integer(1408); + public Object testField1409 = new Integer(1409); + public Object testField1410 = new Integer(1410); + public Object testField1411 = new Integer(1411); + public Object testField1412 = new Integer(1412); + public Object testField1413 = new Integer(1413); + public Object testField1414 = new Integer(1414); + public Object testField1415 = new Integer(1415); + public Object testField1416 = new Integer(1416); + public Object testField1417 = new Integer(1417); + public Object testField1418 = new Integer(1418); + public Object testField1419 = new Integer(1419); + public Object testField1420 = new Integer(1420); + public Object testField1421 = new Integer(1421); + public Object testField1422 = new Integer(1422); + public Object testField1423 = new Integer(1423); + public Object testField1424 = new Integer(1424); + public Object testField1425 = new Integer(1425); + public Object testField1426 = new Integer(1426); + public Object testField1427 = new Integer(1427); + public Object testField1428 = new Integer(1428); + public Object testField1429 = new Integer(1429); + public Object testField1430 = new Integer(1430); + public Object testField1431 = new Integer(1431); + public Object testField1432 = new Integer(1432); + public Object testField1433 = new Integer(1433); + public Object testField1434 = new Integer(1434); + public Object testField1435 = new Integer(1435); + public Object testField1436 = new Integer(1436); + public Object testField1437 = new Integer(1437); + public Object testField1438 = new Integer(1438); + public Object testField1439 = new Integer(1439); + public Object testField1440 = new Integer(1440); + public Object testField1441 = new Integer(1441); + public Object testField1442 = new Integer(1442); + public Object testField1443 = new Integer(1443); + public Object testField1444 = new Integer(1444); + public Object testField1445 = new Integer(1445); + public Object testField1446 = new Integer(1446); + public Object testField1447 = new Integer(1447); + public Object testField1448 = new Integer(1448); + public Object testField1449 = new Integer(1449); + public Object testField1450 = new Integer(1450); + public Object testField1451 = new Integer(1451); + public Object testField1452 = new Integer(1452); + public Object testField1453 = new Integer(1453); + public Object testField1454 = new Integer(1454); + public Object testField1455 = new Integer(1455); + public Object testField1456 = new Integer(1456); + public Object testField1457 = new Integer(1457); + public Object testField1458 = new Integer(1458); + public Object testField1459 = new Integer(1459); + public Object testField1460 = new Integer(1460); + public Object testField1461 = new Integer(1461); + public Object testField1462 = new Integer(1462); + public Object testField1463 = new Integer(1463); + public Object testField1464 = new Integer(1464); + public Object testField1465 = new Integer(1465); + public Object testField1466 = new Integer(1466); + public Object testField1467 = new Integer(1467); + public Object testField1468 = new Integer(1468); + public Object testField1469 = new Integer(1469); + public Object testField1470 = new Integer(1470); + public Object testField1471 = new Integer(1471); + public Object testField1472 = new Integer(1472); + public Object testField1473 = new Integer(1473); + public Object testField1474 = new Integer(1474); + public Object testField1475 = new Integer(1475); + public Object testField1476 = new Integer(1476); + public Object testField1477 = new Integer(1477); + public Object testField1478 = new Integer(1478); + public Object testField1479 = new Integer(1479); + public Object testField1480 = new Integer(1480); + public Object testField1481 = new Integer(1481); + public Object testField1482 = new Integer(1482); + public Object testField1483 = new Integer(1483); + public Object testField1484 = new Integer(1484); + public Object testField1485 = new Integer(1485); + public Object testField1486 = new Integer(1486); + public Object testField1487 = new Integer(1487); + public Object testField1488 = new Integer(1488); + public Object testField1489 = new Integer(1489); + public Object testField1490 = new Integer(1490); + public Object testField1491 = new Integer(1491); + public Object testField1492 = new Integer(1492); + public Object testField1493 = new Integer(1493); + public Object testField1494 = new Integer(1494); + public Object testField1495 = new Integer(1495); + public Object testField1496 = new Integer(1496); + public Object testField1497 = new Integer(1497); + public Object testField1498 = new Integer(1498); + public Object testField1499 = new Integer(1499); + public Object testField1500 = new Integer(1500); + public Object testField1501 = new Integer(1501); + public Object testField1502 = new Integer(1502); + public Object testField1503 = new Integer(1503); + public Object testField1504 = new Integer(1504); + public Object testField1505 = new Integer(1505); + public Object testField1506 = new Integer(1506); + public Object testField1507 = new Integer(1507); + public Object testField1508 = new Integer(1508); + public Object testField1509 = new Integer(1509); + public Object testField1510 = new Integer(1510); + public Object testField1511 = new Integer(1511); + public Object testField1512 = new Integer(1512); + public Object testField1513 = new Integer(1513); + public Object testField1514 = new Integer(1514); + public Object testField1515 = new Integer(1515); + public Object testField1516 = new Integer(1516); + public Object testField1517 = new Integer(1517); + public Object testField1518 = new Integer(1518); + public Object testField1519 = new Integer(1519); + public Object testField1520 = new Integer(1520); + public Object testField1521 = new Integer(1521); + public Object testField1522 = new Integer(1522); + public Object testField1523 = new Integer(1523); + public Object testField1524 = new Integer(1524); + public Object testField1525 = new Integer(1525); + public Object testField1526 = new Integer(1526); + public Object testField1527 = new Integer(1527); + public Object testField1528 = new Integer(1528); + public Object testField1529 = new Integer(1529); + public Object testField1530 = new Integer(1530); + public Object testField1531 = new Integer(1531); + public Object testField1532 = new Integer(1532); + public Object testField1533 = new Integer(1533); + public Object testField1534 = new Integer(1534); + public Object testField1535 = new Integer(1535); + public Object testField1536 = new Integer(1536); + public Object testField1537 = new Integer(1537); + public Object testField1538 = new Integer(1538); + public Object testField1539 = new Integer(1539); + public Object testField1540 = new Integer(1540); + public Object testField1541 = new Integer(1541); + public Object testField1542 = new Integer(1542); + public Object testField1543 = new Integer(1543); + public Object testField1544 = new Integer(1544); + public Object testField1545 = new Integer(1545); + public Object testField1546 = new Integer(1546); + public Object testField1547 = new Integer(1547); + public Object testField1548 = new Integer(1548); + public Object testField1549 = new Integer(1549); + public Object testField1550 = new Integer(1550); + public Object testField1551 = new Integer(1551); + public Object testField1552 = new Integer(1552); + public Object testField1553 = new Integer(1553); + public Object testField1554 = new Integer(1554); + public Object testField1555 = new Integer(1555); + public Object testField1556 = new Integer(1556); + public Object testField1557 = new Integer(1557); + public Object testField1558 = new Integer(1558); + public Object testField1559 = new Integer(1559); + public Object testField1560 = new Integer(1560); + public Object testField1561 = new Integer(1561); + public Object testField1562 = new Integer(1562); + public Object testField1563 = new Integer(1563); + public Object testField1564 = new Integer(1564); + public Object testField1565 = new Integer(1565); + public Object testField1566 = new Integer(1566); + public Object testField1567 = new Integer(1567); + public Object testField1568 = new Integer(1568); + public Object testField1569 = new Integer(1569); + public Object testField1570 = new Integer(1570); + public Object testField1571 = new Integer(1571); + public Object testField1572 = new Integer(1572); + public Object testField1573 = new Integer(1573); + public Object testField1574 = new Integer(1574); + public Object testField1575 = new Integer(1575); + public Object testField1576 = new Integer(1576); + public Object testField1577 = new Integer(1577); + public Object testField1578 = new Integer(1578); + public Object testField1579 = new Integer(1579); + public Object testField1580 = new Integer(1580); + public Object testField1581 = new Integer(1581); + public Object testField1582 = new Integer(1582); + public Object testField1583 = new Integer(1583); + public Object testField1584 = new Integer(1584); + public Object testField1585 = new Integer(1585); + public Object testField1586 = new Integer(1586); + public Object testField1587 = new Integer(1587); + public Object testField1588 = new Integer(1588); + public Object testField1589 = new Integer(1589); + public Object testField1590 = new Integer(1590); + public Object testField1591 = new Integer(1591); + public Object testField1592 = new Integer(1592); + public Object testField1593 = new Integer(1593); + public Object testField1594 = new Integer(1594); + public Object testField1595 = new Integer(1595); + public Object testField1596 = new Integer(1596); + public Object testField1597 = new Integer(1597); + public Object testField1598 = new Integer(1598); + public Object testField1599 = new Integer(1599); + public Object testField1600 = new Integer(1600); + public Object testField1601 = new Integer(1601); + public Object testField1602 = new Integer(1602); + public Object testField1603 = new Integer(1603); + public Object testField1604 = new Integer(1604); + public Object testField1605 = new Integer(1605); + public Object testField1606 = new Integer(1606); + public Object testField1607 = new Integer(1607); + public Object testField1608 = new Integer(1608); + public Object testField1609 = new Integer(1609); + public Object testField1610 = new Integer(1610); + public Object testField1611 = new Integer(1611); + public Object testField1612 = new Integer(1612); + public Object testField1613 = new Integer(1613); + public Object testField1614 = new Integer(1614); + public Object testField1615 = new Integer(1615); + public Object testField1616 = new Integer(1616); + public Object testField1617 = new Integer(1617); + public Object testField1618 = new Integer(1618); + public Object testField1619 = new Integer(1619); + public Object testField1620 = new Integer(1620); + public Object testField1621 = new Integer(1621); + public Object testField1622 = new Integer(1622); + public Object testField1623 = new Integer(1623); + public Object testField1624 = new Integer(1624); + public Object testField1625 = new Integer(1625); + public Object testField1626 = new Integer(1626); + public Object testField1627 = new Integer(1627); + public Object testField1628 = new Integer(1628); + public Object testField1629 = new Integer(1629); + public Object testField1630 = new Integer(1630); + public Object testField1631 = new Integer(1631); + public Object testField1632 = new Integer(1632); + public Object testField1633 = new Integer(1633); + public Object testField1634 = new Integer(1634); + public Object testField1635 = new Integer(1635); + public Object testField1636 = new Integer(1636); + public Object testField1637 = new Integer(1637); + public Object testField1638 = new Integer(1638); + public Object testField1639 = new Integer(1639); + public Object testField1640 = new Integer(1640); + public Object testField1641 = new Integer(1641); + public Object testField1642 = new Integer(1642); + public Object testField1643 = new Integer(1643); + public Object testField1644 = new Integer(1644); + public Object testField1645 = new Integer(1645); + public Object testField1646 = new Integer(1646); + public Object testField1647 = new Integer(1647); + public Object testField1648 = new Integer(1648); + public Object testField1649 = new Integer(1649); + public Object testField1650 = new Integer(1650); + public Object testField1651 = new Integer(1651); + public Object testField1652 = new Integer(1652); + public Object testField1653 = new Integer(1653); + public Object testField1654 = new Integer(1654); + public Object testField1655 = new Integer(1655); + public Object testField1656 = new Integer(1656); + public Object testField1657 = new Integer(1657); + public Object testField1658 = new Integer(1658); + public Object testField1659 = new Integer(1659); + public Object testField1660 = new Integer(1660); + public Object testField1661 = new Integer(1661); + public Object testField1662 = new Integer(1662); + public Object testField1663 = new Integer(1663); + public Object testField1664 = new Integer(1664); + public Object testField1665 = new Integer(1665); + public Object testField1666 = new Integer(1666); + public Object testField1667 = new Integer(1667); + public Object testField1668 = new Integer(1668); + public Object testField1669 = new Integer(1669); + public Object testField1670 = new Integer(1670); + public Object testField1671 = new Integer(1671); + public Object testField1672 = new Integer(1672); + public Object testField1673 = new Integer(1673); + public Object testField1674 = new Integer(1674); + public Object testField1675 = new Integer(1675); + public Object testField1676 = new Integer(1676); + public Object testField1677 = new Integer(1677); + public Object testField1678 = new Integer(1678); + public Object testField1679 = new Integer(1679); + public Object testField1680 = new Integer(1680); + public Object testField1681 = new Integer(1681); + public Object testField1682 = new Integer(1682); + public Object testField1683 = new Integer(1683); + public Object testField1684 = new Integer(1684); + public Object testField1685 = new Integer(1685); + public Object testField1686 = new Integer(1686); + public Object testField1687 = new Integer(1687); + public Object testField1688 = new Integer(1688); + public Object testField1689 = new Integer(1689); + public Object testField1690 = new Integer(1690); + public Object testField1691 = new Integer(1691); + public Object testField1692 = new Integer(1692); + public Object testField1693 = new Integer(1693); + public Object testField1694 = new Integer(1694); + public Object testField1695 = new Integer(1695); + public Object testField1696 = new Integer(1696); + public Object testField1697 = new Integer(1697); + public Object testField1698 = new Integer(1698); + public Object testField1699 = new Integer(1699); + public Object testField1700 = new Integer(1700); + public Object testField1701 = new Integer(1701); + public Object testField1702 = new Integer(1702); + public Object testField1703 = new Integer(1703); + public Object testField1704 = new Integer(1704); + public Object testField1705 = new Integer(1705); + public Object testField1706 = new Integer(1706); + public Object testField1707 = new Integer(1707); + public Object testField1708 = new Integer(1708); + public Object testField1709 = new Integer(1709); + public Object testField1710 = new Integer(1710); + public Object testField1711 = new Integer(1711); + public Object testField1712 = new Integer(1712); + public Object testField1713 = new Integer(1713); + public Object testField1714 = new Integer(1714); + public Object testField1715 = new Integer(1715); + public Object testField1716 = new Integer(1716); + public Object testField1717 = new Integer(1717); + public Object testField1718 = new Integer(1718); + public Object testField1719 = new Integer(1719); + public Object testField1720 = new Integer(1720); + public Object testField1721 = new Integer(1721); + public Object testField1722 = new Integer(1722); + public Object testField1723 = new Integer(1723); + public Object testField1724 = new Integer(1724); + public Object testField1725 = new Integer(1725); + public Object testField1726 = new Integer(1726); + public Object testField1727 = new Integer(1727); + public Object testField1728 = new Integer(1728); + public Object testField1729 = new Integer(1729); + public Object testField1730 = new Integer(1730); + public Object testField1731 = new Integer(1731); + public Object testField1732 = new Integer(1732); + public Object testField1733 = new Integer(1733); + public Object testField1734 = new Integer(1734); + public Object testField1735 = new Integer(1735); + public Object testField1736 = new Integer(1736); + public Object testField1737 = new Integer(1737); + public Object testField1738 = new Integer(1738); + public Object testField1739 = new Integer(1739); + public Object testField1740 = new Integer(1740); + public Object testField1741 = new Integer(1741); + public Object testField1742 = new Integer(1742); + public Object testField1743 = new Integer(1743); + public Object testField1744 = new Integer(1744); + public Object testField1745 = new Integer(1745); + public Object testField1746 = new Integer(1746); + public Object testField1747 = new Integer(1747); + public Object testField1748 = new Integer(1748); + public Object testField1749 = new Integer(1749); + public Object testField1750 = new Integer(1750); + public Object testField1751 = new Integer(1751); + public Object testField1752 = new Integer(1752); + public Object testField1753 = new Integer(1753); + public Object testField1754 = new Integer(1754); + public Object testField1755 = new Integer(1755); + public Object testField1756 = new Integer(1756); + public Object testField1757 = new Integer(1757); + public Object testField1758 = new Integer(1758); + public Object testField1759 = new Integer(1759); + public Object testField1760 = new Integer(1760); + public Object testField1761 = new Integer(1761); + public Object testField1762 = new Integer(1762); + public Object testField1763 = new Integer(1763); + public Object testField1764 = new Integer(1764); + public Object testField1765 = new Integer(1765); + public Object testField1766 = new Integer(1766); + public Object testField1767 = new Integer(1767); + public Object testField1768 = new Integer(1768); + public Object testField1769 = new Integer(1769); + public Object testField1770 = new Integer(1770); + public Object testField1771 = new Integer(1771); + public Object testField1772 = new Integer(1772); + public Object testField1773 = new Integer(1773); + public Object testField1774 = new Integer(1774); + public Object testField1775 = new Integer(1775); + public Object testField1776 = new Integer(1776); + public Object testField1777 = new Integer(1777); + public Object testField1778 = new Integer(1778); + public Object testField1779 = new Integer(1779); + public Object testField1780 = new Integer(1780); + public Object testField1781 = new Integer(1781); + public Object testField1782 = new Integer(1782); + public Object testField1783 = new Integer(1783); + public Object testField1784 = new Integer(1784); + public Object testField1785 = new Integer(1785); + public Object testField1786 = new Integer(1786); + public Object testField1787 = new Integer(1787); + public Object testField1788 = new Integer(1788); + public Object testField1789 = new Integer(1789); + public Object testField1790 = new Integer(1790); + public Object testField1791 = new Integer(1791); + public Object testField1792 = new Integer(1792); + public Object testField1793 = new Integer(1793); + public Object testField1794 = new Integer(1794); + public Object testField1795 = new Integer(1795); + public Object testField1796 = new Integer(1796); + public Object testField1797 = new Integer(1797); + public Object testField1798 = new Integer(1798); + public Object testField1799 = new Integer(1799); + public Object testField1800 = new Integer(1800); + public Object testField1801 = new Integer(1801); + public Object testField1802 = new Integer(1802); + public Object testField1803 = new Integer(1803); + public Object testField1804 = new Integer(1804); + public Object testField1805 = new Integer(1805); + public Object testField1806 = new Integer(1806); + public Object testField1807 = new Integer(1807); + public Object testField1808 = new Integer(1808); + public Object testField1809 = new Integer(1809); + public Object testField1810 = new Integer(1810); + public Object testField1811 = new Integer(1811); + public Object testField1812 = new Integer(1812); + public Object testField1813 = new Integer(1813); + public Object testField1814 = new Integer(1814); + public Object testField1815 = new Integer(1815); + public Object testField1816 = new Integer(1816); + public Object testField1817 = new Integer(1817); + public Object testField1818 = new Integer(1818); + public Object testField1819 = new Integer(1819); + public Object testField1820 = new Integer(1820); + public Object testField1821 = new Integer(1821); + public Object testField1822 = new Integer(1822); + public Object testField1823 = new Integer(1823); + public Object testField1824 = new Integer(1824); + public Object testField1825 = new Integer(1825); + public Object testField1826 = new Integer(1826); + public Object testField1827 = new Integer(1827); + public Object testField1828 = new Integer(1828); + public Object testField1829 = new Integer(1829); + public Object testField1830 = new Integer(1830); + public Object testField1831 = new Integer(1831); + public Object testField1832 = new Integer(1832); + public Object testField1833 = new Integer(1833); + public Object testField1834 = new Integer(1834); + public Object testField1835 = new Integer(1835); + public Object testField1836 = new Integer(1836); + public Object testField1837 = new Integer(1837); + public Object testField1838 = new Integer(1838); + public Object testField1839 = new Integer(1839); + public Object testField1840 = new Integer(1840); + public Object testField1841 = new Integer(1841); + public Object testField1842 = new Integer(1842); + public Object testField1843 = new Integer(1843); + public Object testField1844 = new Integer(1844); + public Object testField1845 = new Integer(1845); + public Object testField1846 = new Integer(1846); + public Object testField1847 = new Integer(1847); + public Object testField1848 = new Integer(1848); + public Object testField1849 = new Integer(1849); + public Object testField1850 = new Integer(1850); + public Object testField1851 = new Integer(1851); + public Object testField1852 = new Integer(1852); + public Object testField1853 = new Integer(1853); + public Object testField1854 = new Integer(1854); + public Object testField1855 = new Integer(1855); + public Object testField1856 = new Integer(1856); + public Object testField1857 = new Integer(1857); + public Object testField1858 = new Integer(1858); + public Object testField1859 = new Integer(1859); + public Object testField1860 = new Integer(1860); + public Object testField1861 = new Integer(1861); + public Object testField1862 = new Integer(1862); + public Object testField1863 = new Integer(1863); + public Object testField1864 = new Integer(1864); + public Object testField1865 = new Integer(1865); + public Object testField1866 = new Integer(1866); + public Object testField1867 = new Integer(1867); + public Object testField1868 = new Integer(1868); + public Object testField1869 = new Integer(1869); + public Object testField1870 = new Integer(1870); + public Object testField1871 = new Integer(1871); + public Object testField1872 = new Integer(1872); + public Object testField1873 = new Integer(1873); + public Object testField1874 = new Integer(1874); + public Object testField1875 = new Integer(1875); + public Object testField1876 = new Integer(1876); + public Object testField1877 = new Integer(1877); + public Object testField1878 = new Integer(1878); + public Object testField1879 = new Integer(1879); + public Object testField1880 = new Integer(1880); + public Object testField1881 = new Integer(1881); + public Object testField1882 = new Integer(1882); + public Object testField1883 = new Integer(1883); + public Object testField1884 = new Integer(1884); + public Object testField1885 = new Integer(1885); + public Object testField1886 = new Integer(1886); + public Object testField1887 = new Integer(1887); + public Object testField1888 = new Integer(1888); + public Object testField1889 = new Integer(1889); + public Object testField1890 = new Integer(1890); + public Object testField1891 = new Integer(1891); + public Object testField1892 = new Integer(1892); + public Object testField1893 = new Integer(1893); + public Object testField1894 = new Integer(1894); + public Object testField1895 = new Integer(1895); + public Object testField1896 = new Integer(1896); + public Object testField1897 = new Integer(1897); + public Object testField1898 = new Integer(1898); + public Object testField1899 = new Integer(1899); + public Object testField1900 = new Integer(1900); + public Object testField1901 = new Integer(1901); + public Object testField1902 = new Integer(1902); + public Object testField1903 = new Integer(1903); + public Object testField1904 = new Integer(1904); + public Object testField1905 = new Integer(1905); + public Object testField1906 = new Integer(1906); + public Object testField1907 = new Integer(1907); + public Object testField1908 = new Integer(1908); + public Object testField1909 = new Integer(1909); + public Object testField1910 = new Integer(1910); + public Object testField1911 = new Integer(1911); + public Object testField1912 = new Integer(1912); + public Object testField1913 = new Integer(1913); + public Object testField1914 = new Integer(1914); + public Object testField1915 = new Integer(1915); + public Object testField1916 = new Integer(1916); + public Object testField1917 = new Integer(1917); + public Object testField1918 = new Integer(1918); + public Object testField1919 = new Integer(1919); + public Object testField1920 = new Integer(1920); + public Object testField1921 = new Integer(1921); + public Object testField1922 = new Integer(1922); + public Object testField1923 = new Integer(1923); + public Object testField1924 = new Integer(1924); + public Object testField1925 = new Integer(1925); + public Object testField1926 = new Integer(1926); + public Object testField1927 = new Integer(1927); + public Object testField1928 = new Integer(1928); + public Object testField1929 = new Integer(1929); + public Object testField1930 = new Integer(1930); + public Object testField1931 = new Integer(1931); + public Object testField1932 = new Integer(1932); + public Object testField1933 = new Integer(1933); + public Object testField1934 = new Integer(1934); + public Object testField1935 = new Integer(1935); + public Object testField1936 = new Integer(1936); + public Object testField1937 = new Integer(1937); + public Object testField1938 = new Integer(1938); + public Object testField1939 = new Integer(1939); + public Object testField1940 = new Integer(1940); + public Object testField1941 = new Integer(1941); + public Object testField1942 = new Integer(1942); + public Object testField1943 = new Integer(1943); + public Object testField1944 = new Integer(1944); + public Object testField1945 = new Integer(1945); + public Object testField1946 = new Integer(1946); + public Object testField1947 = new Integer(1947); + public Object testField1948 = new Integer(1948); + public Object testField1949 = new Integer(1949); + public Object testField1950 = new Integer(1950); + public Object testField1951 = new Integer(1951); + public Object testField1952 = new Integer(1952); + public Object testField1953 = new Integer(1953); + public Object testField1954 = new Integer(1954); + public Object testField1955 = new Integer(1955); + public Object testField1956 = new Integer(1956); + public Object testField1957 = new Integer(1957); + public Object testField1958 = new Integer(1958); + public Object testField1959 = new Integer(1959); + public Object testField1960 = new Integer(1960); + public Object testField1961 = new Integer(1961); + public Object testField1962 = new Integer(1962); + public Object testField1963 = new Integer(1963); + public Object testField1964 = new Integer(1964); + public Object testField1965 = new Integer(1965); + public Object testField1966 = new Integer(1966); + public Object testField1967 = new Integer(1967); + public Object testField1968 = new Integer(1968); + public Object testField1969 = new Integer(1969); + public Object testField1970 = new Integer(1970); + public Object testField1971 = new Integer(1971); + public Object testField1972 = new Integer(1972); + public Object testField1973 = new Integer(1973); + public Object testField1974 = new Integer(1974); + public Object testField1975 = new Integer(1975); + public Object testField1976 = new Integer(1976); + public Object testField1977 = new Integer(1977); + public Object testField1978 = new Integer(1978); + public Object testField1979 = new Integer(1979); + public Object testField1980 = new Integer(1980); + public Object testField1981 = new Integer(1981); + public Object testField1982 = new Integer(1982); + public Object testField1983 = new Integer(1983); + public Object testField1984 = new Integer(1984); + public Object testField1985 = new Integer(1985); + public Object testField1986 = new Integer(1986); + public Object testField1987 = new Integer(1987); + public Object testField1988 = new Integer(1988); + public Object testField1989 = new Integer(1989); + public Object testField1990 = new Integer(1990); + public Object testField1991 = new Integer(1991); + public Object testField1992 = new Integer(1992); + public Object testField1993 = new Integer(1993); + public Object testField1994 = new Integer(1994); + public Object testField1995 = new Integer(1995); + public Object testField1996 = new Integer(1996); + public Object testField1997 = new Integer(1997); + public Object testField1998 = new Integer(1998); + public Object testField1999 = new Integer(1999); +} diff --git a/test/160-read-barrier-stress/src/ManyFieldsBase2.java b/test/160-read-barrier-stress/src/ManyFieldsBase2.java new file mode 100644 index 0000000000..54bbe99f73 --- /dev/null +++ b/test/160-read-barrier-stress/src/ManyFieldsBase2.java @@ -0,0 +1,1018 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +class ManyFieldsBase2 extends ManyFieldsBase1 { + public Object testField2000 = new Integer(2000); + public Object testField2001 = new Integer(2001); + public Object testField2002 = new Integer(2002); + public Object testField2003 = new Integer(2003); + public Object testField2004 = new Integer(2004); + public Object testField2005 = new Integer(2005); + public Object testField2006 = new Integer(2006); + public Object testField2007 = new Integer(2007); + public Object testField2008 = new Integer(2008); + public Object testField2009 = new Integer(2009); + public Object testField2010 = new Integer(2010); + public Object testField2011 = new Integer(2011); + public Object testField2012 = new Integer(2012); + public Object testField2013 = new Integer(2013); + public Object testField2014 = new Integer(2014); + public Object testField2015 = new Integer(2015); + public Object testField2016 = new Integer(2016); + public Object testField2017 = new Integer(2017); + public Object testField2018 = new Integer(2018); + public Object testField2019 = new Integer(2019); + public Object testField2020 = new Integer(2020); + public Object testField2021 = new Integer(2021); + public Object testField2022 = new Integer(2022); + public Object testField2023 = new Integer(2023); + public Object testField2024 = new Integer(2024); + public Object testField2025 = new Integer(2025); + public Object testField2026 = new Integer(2026); + public Object testField2027 = new Integer(2027); + public Object testField2028 = new Integer(2028); + public Object testField2029 = new Integer(2029); + public Object testField2030 = new Integer(2030); + public Object testField2031 = new Integer(2031); + public Object testField2032 = new Integer(2032); + public Object testField2033 = new Integer(2033); + public Object testField2034 = new Integer(2034); + public Object testField2035 = new Integer(2035); + public Object testField2036 = new Integer(2036); + public Object testField2037 = new Integer(2037); + public Object testField2038 = new Integer(2038); + public Object testField2039 = new Integer(2039); + public Object testField2040 = new Integer(2040); + public Object testField2041 = new Integer(2041); + public Object testField2042 = new Integer(2042); + public Object testField2043 = new Integer(2043); + public Object testField2044 = new Integer(2044); + public Object testField2045 = new Integer(2045); + public Object testField2046 = new Integer(2046); + public Object testField2047 = new Integer(2047); + public Object testField2048 = new Integer(2048); + public Object testField2049 = new Integer(2049); + public Object testField2050 = new Integer(2050); + public Object testField2051 = new Integer(2051); + public Object testField2052 = new Integer(2052); + public Object testField2053 = new Integer(2053); + public Object testField2054 = new Integer(2054); + public Object testField2055 = new Integer(2055); + public Object testField2056 = new Integer(2056); + public Object testField2057 = new Integer(2057); + public Object testField2058 = new Integer(2058); + public Object testField2059 = new Integer(2059); + public Object testField2060 = new Integer(2060); + public Object testField2061 = new Integer(2061); + public Object testField2062 = new Integer(2062); + public Object testField2063 = new Integer(2063); + public Object testField2064 = new Integer(2064); + public Object testField2065 = new Integer(2065); + public Object testField2066 = new Integer(2066); + public Object testField2067 = new Integer(2067); + public Object testField2068 = new Integer(2068); + public Object testField2069 = new Integer(2069); + public Object testField2070 = new Integer(2070); + public Object testField2071 = new Integer(2071); + public Object testField2072 = new Integer(2072); + public Object testField2073 = new Integer(2073); + public Object testField2074 = new Integer(2074); + public Object testField2075 = new Integer(2075); + public Object testField2076 = new Integer(2076); + public Object testField2077 = new Integer(2077); + public Object testField2078 = new Integer(2078); + public Object testField2079 = new Integer(2079); + public Object testField2080 = new Integer(2080); + public Object testField2081 = new Integer(2081); + public Object testField2082 = new Integer(2082); + public Object testField2083 = new Integer(2083); + public Object testField2084 = new Integer(2084); + public Object testField2085 = new Integer(2085); + public Object testField2086 = new Integer(2086); + public Object testField2087 = new Integer(2087); + public Object testField2088 = new Integer(2088); + public Object testField2089 = new Integer(2089); + public Object testField2090 = new Integer(2090); + public Object testField2091 = new Integer(2091); + public Object testField2092 = new Integer(2092); + public Object testField2093 = new Integer(2093); + public Object testField2094 = new Integer(2094); + public Object testField2095 = new Integer(2095); + public Object testField2096 = new Integer(2096); + public Object testField2097 = new Integer(2097); + public Object testField2098 = new Integer(2098); + public Object testField2099 = new Integer(2099); + public Object testField2100 = new Integer(2100); + public Object testField2101 = new Integer(2101); + public Object testField2102 = new Integer(2102); + public Object testField2103 = new Integer(2103); + public Object testField2104 = new Integer(2104); + public Object testField2105 = new Integer(2105); + public Object testField2106 = new Integer(2106); + public Object testField2107 = new Integer(2107); + public Object testField2108 = new Integer(2108); + public Object testField2109 = new Integer(2109); + public Object testField2110 = new Integer(2110); + public Object testField2111 = new Integer(2111); + public Object testField2112 = new Integer(2112); + public Object testField2113 = new Integer(2113); + public Object testField2114 = new Integer(2114); + public Object testField2115 = new Integer(2115); + public Object testField2116 = new Integer(2116); + public Object testField2117 = new Integer(2117); + public Object testField2118 = new Integer(2118); + public Object testField2119 = new Integer(2119); + public Object testField2120 = new Integer(2120); + public Object testField2121 = new Integer(2121); + public Object testField2122 = new Integer(2122); + public Object testField2123 = new Integer(2123); + public Object testField2124 = new Integer(2124); + public Object testField2125 = new Integer(2125); + public Object testField2126 = new Integer(2126); + public Object testField2127 = new Integer(2127); + public Object testField2128 = new Integer(2128); + public Object testField2129 = new Integer(2129); + public Object testField2130 = new Integer(2130); + public Object testField2131 = new Integer(2131); + public Object testField2132 = new Integer(2132); + public Object testField2133 = new Integer(2133); + public Object testField2134 = new Integer(2134); + public Object testField2135 = new Integer(2135); + public Object testField2136 = new Integer(2136); + public Object testField2137 = new Integer(2137); + public Object testField2138 = new Integer(2138); + public Object testField2139 = new Integer(2139); + public Object testField2140 = new Integer(2140); + public Object testField2141 = new Integer(2141); + public Object testField2142 = new Integer(2142); + public Object testField2143 = new Integer(2143); + public Object testField2144 = new Integer(2144); + public Object testField2145 = new Integer(2145); + public Object testField2146 = new Integer(2146); + public Object testField2147 = new Integer(2147); + public Object testField2148 = new Integer(2148); + public Object testField2149 = new Integer(2149); + public Object testField2150 = new Integer(2150); + public Object testField2151 = new Integer(2151); + public Object testField2152 = new Integer(2152); + public Object testField2153 = new Integer(2153); + public Object testField2154 = new Integer(2154); + public Object testField2155 = new Integer(2155); + public Object testField2156 = new Integer(2156); + public Object testField2157 = new Integer(2157); + public Object testField2158 = new Integer(2158); + public Object testField2159 = new Integer(2159); + public Object testField2160 = new Integer(2160); + public Object testField2161 = new Integer(2161); + public Object testField2162 = new Integer(2162); + public Object testField2163 = new Integer(2163); + public Object testField2164 = new Integer(2164); + public Object testField2165 = new Integer(2165); + public Object testField2166 = new Integer(2166); + public Object testField2167 = new Integer(2167); + public Object testField2168 = new Integer(2168); + public Object testField2169 = new Integer(2169); + public Object testField2170 = new Integer(2170); + public Object testField2171 = new Integer(2171); + public Object testField2172 = new Integer(2172); + public Object testField2173 = new Integer(2173); + public Object testField2174 = new Integer(2174); + public Object testField2175 = new Integer(2175); + public Object testField2176 = new Integer(2176); + public Object testField2177 = new Integer(2177); + public Object testField2178 = new Integer(2178); + public Object testField2179 = new Integer(2179); + public Object testField2180 = new Integer(2180); + public Object testField2181 = new Integer(2181); + public Object testField2182 = new Integer(2182); + public Object testField2183 = new Integer(2183); + public Object testField2184 = new Integer(2184); + public Object testField2185 = new Integer(2185); + public Object testField2186 = new Integer(2186); + public Object testField2187 = new Integer(2187); + public Object testField2188 = new Integer(2188); + public Object testField2189 = new Integer(2189); + public Object testField2190 = new Integer(2190); + public Object testField2191 = new Integer(2191); + public Object testField2192 = new Integer(2192); + public Object testField2193 = new Integer(2193); + public Object testField2194 = new Integer(2194); + public Object testField2195 = new Integer(2195); + public Object testField2196 = new Integer(2196); + public Object testField2197 = new Integer(2197); + public Object testField2198 = new Integer(2198); + public Object testField2199 = new Integer(2199); + public Object testField2200 = new Integer(2200); + public Object testField2201 = new Integer(2201); + public Object testField2202 = new Integer(2202); + public Object testField2203 = new Integer(2203); + public Object testField2204 = new Integer(2204); + public Object testField2205 = new Integer(2205); + public Object testField2206 = new Integer(2206); + public Object testField2207 = new Integer(2207); + public Object testField2208 = new Integer(2208); + public Object testField2209 = new Integer(2209); + public Object testField2210 = new Integer(2210); + public Object testField2211 = new Integer(2211); + public Object testField2212 = new Integer(2212); + public Object testField2213 = new Integer(2213); + public Object testField2214 = new Integer(2214); + public Object testField2215 = new Integer(2215); + public Object testField2216 = new Integer(2216); + public Object testField2217 = new Integer(2217); + public Object testField2218 = new Integer(2218); + public Object testField2219 = new Integer(2219); + public Object testField2220 = new Integer(2220); + public Object testField2221 = new Integer(2221); + public Object testField2222 = new Integer(2222); + public Object testField2223 = new Integer(2223); + public Object testField2224 = new Integer(2224); + public Object testField2225 = new Integer(2225); + public Object testField2226 = new Integer(2226); + public Object testField2227 = new Integer(2227); + public Object testField2228 = new Integer(2228); + public Object testField2229 = new Integer(2229); + public Object testField2230 = new Integer(2230); + public Object testField2231 = new Integer(2231); + public Object testField2232 = new Integer(2232); + public Object testField2233 = new Integer(2233); + public Object testField2234 = new Integer(2234); + public Object testField2235 = new Integer(2235); + public Object testField2236 = new Integer(2236); + public Object testField2237 = new Integer(2237); + public Object testField2238 = new Integer(2238); + public Object testField2239 = new Integer(2239); + public Object testField2240 = new Integer(2240); + public Object testField2241 = new Integer(2241); + public Object testField2242 = new Integer(2242); + public Object testField2243 = new Integer(2243); + public Object testField2244 = new Integer(2244); + public Object testField2245 = new Integer(2245); + public Object testField2246 = new Integer(2246); + public Object testField2247 = new Integer(2247); + public Object testField2248 = new Integer(2248); + public Object testField2249 = new Integer(2249); + public Object testField2250 = new Integer(2250); + public Object testField2251 = new Integer(2251); + public Object testField2252 = new Integer(2252); + public Object testField2253 = new Integer(2253); + public Object testField2254 = new Integer(2254); + public Object testField2255 = new Integer(2255); + public Object testField2256 = new Integer(2256); + public Object testField2257 = new Integer(2257); + public Object testField2258 = new Integer(2258); + public Object testField2259 = new Integer(2259); + public Object testField2260 = new Integer(2260); + public Object testField2261 = new Integer(2261); + public Object testField2262 = new Integer(2262); + public Object testField2263 = new Integer(2263); + public Object testField2264 = new Integer(2264); + public Object testField2265 = new Integer(2265); + public Object testField2266 = new Integer(2266); + public Object testField2267 = new Integer(2267); + public Object testField2268 = new Integer(2268); + public Object testField2269 = new Integer(2269); + public Object testField2270 = new Integer(2270); + public Object testField2271 = new Integer(2271); + public Object testField2272 = new Integer(2272); + public Object testField2273 = new Integer(2273); + public Object testField2274 = new Integer(2274); + public Object testField2275 = new Integer(2275); + public Object testField2276 = new Integer(2276); + public Object testField2277 = new Integer(2277); + public Object testField2278 = new Integer(2278); + public Object testField2279 = new Integer(2279); + public Object testField2280 = new Integer(2280); + public Object testField2281 = new Integer(2281); + public Object testField2282 = new Integer(2282); + public Object testField2283 = new Integer(2283); + public Object testField2284 = new Integer(2284); + public Object testField2285 = new Integer(2285); + public Object testField2286 = new Integer(2286); + public Object testField2287 = new Integer(2287); + public Object testField2288 = new Integer(2288); + public Object testField2289 = new Integer(2289); + public Object testField2290 = new Integer(2290); + public Object testField2291 = new Integer(2291); + public Object testField2292 = new Integer(2292); + public Object testField2293 = new Integer(2293); + public Object testField2294 = new Integer(2294); + public Object testField2295 = new Integer(2295); + public Object testField2296 = new Integer(2296); + public Object testField2297 = new Integer(2297); + public Object testField2298 = new Integer(2298); + public Object testField2299 = new Integer(2299); + public Object testField2300 = new Integer(2300); + public Object testField2301 = new Integer(2301); + public Object testField2302 = new Integer(2302); + public Object testField2303 = new Integer(2303); + public Object testField2304 = new Integer(2304); + public Object testField2305 = new Integer(2305); + public Object testField2306 = new Integer(2306); + public Object testField2307 = new Integer(2307); + public Object testField2308 = new Integer(2308); + public Object testField2309 = new Integer(2309); + public Object testField2310 = new Integer(2310); + public Object testField2311 = new Integer(2311); + public Object testField2312 = new Integer(2312); + public Object testField2313 = new Integer(2313); + public Object testField2314 = new Integer(2314); + public Object testField2315 = new Integer(2315); + public Object testField2316 = new Integer(2316); + public Object testField2317 = new Integer(2317); + public Object testField2318 = new Integer(2318); + public Object testField2319 = new Integer(2319); + public Object testField2320 = new Integer(2320); + public Object testField2321 = new Integer(2321); + public Object testField2322 = new Integer(2322); + public Object testField2323 = new Integer(2323); + public Object testField2324 = new Integer(2324); + public Object testField2325 = new Integer(2325); + public Object testField2326 = new Integer(2326); + public Object testField2327 = new Integer(2327); + public Object testField2328 = new Integer(2328); + public Object testField2329 = new Integer(2329); + public Object testField2330 = new Integer(2330); + public Object testField2331 = new Integer(2331); + public Object testField2332 = new Integer(2332); + public Object testField2333 = new Integer(2333); + public Object testField2334 = new Integer(2334); + public Object testField2335 = new Integer(2335); + public Object testField2336 = new Integer(2336); + public Object testField2337 = new Integer(2337); + public Object testField2338 = new Integer(2338); + public Object testField2339 = new Integer(2339); + public Object testField2340 = new Integer(2340); + public Object testField2341 = new Integer(2341); + public Object testField2342 = new Integer(2342); + public Object testField2343 = new Integer(2343); + public Object testField2344 = new Integer(2344); + public Object testField2345 = new Integer(2345); + public Object testField2346 = new Integer(2346); + public Object testField2347 = new Integer(2347); + public Object testField2348 = new Integer(2348); + public Object testField2349 = new Integer(2349); + public Object testField2350 = new Integer(2350); + public Object testField2351 = new Integer(2351); + public Object testField2352 = new Integer(2352); + public Object testField2353 = new Integer(2353); + public Object testField2354 = new Integer(2354); + public Object testField2355 = new Integer(2355); + public Object testField2356 = new Integer(2356); + public Object testField2357 = new Integer(2357); + public Object testField2358 = new Integer(2358); + public Object testField2359 = new Integer(2359); + public Object testField2360 = new Integer(2360); + public Object testField2361 = new Integer(2361); + public Object testField2362 = new Integer(2362); + public Object testField2363 = new Integer(2363); + public Object testField2364 = new Integer(2364); + public Object testField2365 = new Integer(2365); + public Object testField2366 = new Integer(2366); + public Object testField2367 = new Integer(2367); + public Object testField2368 = new Integer(2368); + public Object testField2369 = new Integer(2369); + public Object testField2370 = new Integer(2370); + public Object testField2371 = new Integer(2371); + public Object testField2372 = new Integer(2372); + public Object testField2373 = new Integer(2373); + public Object testField2374 = new Integer(2374); + public Object testField2375 = new Integer(2375); + public Object testField2376 = new Integer(2376); + public Object testField2377 = new Integer(2377); + public Object testField2378 = new Integer(2378); + public Object testField2379 = new Integer(2379); + public Object testField2380 = new Integer(2380); + public Object testField2381 = new Integer(2381); + public Object testField2382 = new Integer(2382); + public Object testField2383 = new Integer(2383); + public Object testField2384 = new Integer(2384); + public Object testField2385 = new Integer(2385); + public Object testField2386 = new Integer(2386); + public Object testField2387 = new Integer(2387); + public Object testField2388 = new Integer(2388); + public Object testField2389 = new Integer(2389); + public Object testField2390 = new Integer(2390); + public Object testField2391 = new Integer(2391); + public Object testField2392 = new Integer(2392); + public Object testField2393 = new Integer(2393); + public Object testField2394 = new Integer(2394); + public Object testField2395 = new Integer(2395); + public Object testField2396 = new Integer(2396); + public Object testField2397 = new Integer(2397); + public Object testField2398 = new Integer(2398); + public Object testField2399 = new Integer(2399); + public Object testField2400 = new Integer(2400); + public Object testField2401 = new Integer(2401); + public Object testField2402 = new Integer(2402); + public Object testField2403 = new Integer(2403); + public Object testField2404 = new Integer(2404); + public Object testField2405 = new Integer(2405); + public Object testField2406 = new Integer(2406); + public Object testField2407 = new Integer(2407); + public Object testField2408 = new Integer(2408); + public Object testField2409 = new Integer(2409); + public Object testField2410 = new Integer(2410); + public Object testField2411 = new Integer(2411); + public Object testField2412 = new Integer(2412); + public Object testField2413 = new Integer(2413); + public Object testField2414 = new Integer(2414); + public Object testField2415 = new Integer(2415); + public Object testField2416 = new Integer(2416); + public Object testField2417 = new Integer(2417); + public Object testField2418 = new Integer(2418); + public Object testField2419 = new Integer(2419); + public Object testField2420 = new Integer(2420); + public Object testField2421 = new Integer(2421); + public Object testField2422 = new Integer(2422); + public Object testField2423 = new Integer(2423); + public Object testField2424 = new Integer(2424); + public Object testField2425 = new Integer(2425); + public Object testField2426 = new Integer(2426); + public Object testField2427 = new Integer(2427); + public Object testField2428 = new Integer(2428); + public Object testField2429 = new Integer(2429); + public Object testField2430 = new Integer(2430); + public Object testField2431 = new Integer(2431); + public Object testField2432 = new Integer(2432); + public Object testField2433 = new Integer(2433); + public Object testField2434 = new Integer(2434); + public Object testField2435 = new Integer(2435); + public Object testField2436 = new Integer(2436); + public Object testField2437 = new Integer(2437); + public Object testField2438 = new Integer(2438); + public Object testField2439 = new Integer(2439); + public Object testField2440 = new Integer(2440); + public Object testField2441 = new Integer(2441); + public Object testField2442 = new Integer(2442); + public Object testField2443 = new Integer(2443); + public Object testField2444 = new Integer(2444); + public Object testField2445 = new Integer(2445); + public Object testField2446 = new Integer(2446); + public Object testField2447 = new Integer(2447); + public Object testField2448 = new Integer(2448); + public Object testField2449 = new Integer(2449); + public Object testField2450 = new Integer(2450); + public Object testField2451 = new Integer(2451); + public Object testField2452 = new Integer(2452); + public Object testField2453 = new Integer(2453); + public Object testField2454 = new Integer(2454); + public Object testField2455 = new Integer(2455); + public Object testField2456 = new Integer(2456); + public Object testField2457 = new Integer(2457); + public Object testField2458 = new Integer(2458); + public Object testField2459 = new Integer(2459); + public Object testField2460 = new Integer(2460); + public Object testField2461 = new Integer(2461); + public Object testField2462 = new Integer(2462); + public Object testField2463 = new Integer(2463); + public Object testField2464 = new Integer(2464); + public Object testField2465 = new Integer(2465); + public Object testField2466 = new Integer(2466); + public Object testField2467 = new Integer(2467); + public Object testField2468 = new Integer(2468); + public Object testField2469 = new Integer(2469); + public Object testField2470 = new Integer(2470); + public Object testField2471 = new Integer(2471); + public Object testField2472 = new Integer(2472); + public Object testField2473 = new Integer(2473); + public Object testField2474 = new Integer(2474); + public Object testField2475 = new Integer(2475); + public Object testField2476 = new Integer(2476); + public Object testField2477 = new Integer(2477); + public Object testField2478 = new Integer(2478); + public Object testField2479 = new Integer(2479); + public Object testField2480 = new Integer(2480); + public Object testField2481 = new Integer(2481); + public Object testField2482 = new Integer(2482); + public Object testField2483 = new Integer(2483); + public Object testField2484 = new Integer(2484); + public Object testField2485 = new Integer(2485); + public Object testField2486 = new Integer(2486); + public Object testField2487 = new Integer(2487); + public Object testField2488 = new Integer(2488); + public Object testField2489 = new Integer(2489); + public Object testField2490 = new Integer(2490); + public Object testField2491 = new Integer(2491); + public Object testField2492 = new Integer(2492); + public Object testField2493 = new Integer(2493); + public Object testField2494 = new Integer(2494); + public Object testField2495 = new Integer(2495); + public Object testField2496 = new Integer(2496); + public Object testField2497 = new Integer(2497); + public Object testField2498 = new Integer(2498); + public Object testField2499 = new Integer(2499); + public Object testField2500 = new Integer(2500); + public Object testField2501 = new Integer(2501); + public Object testField2502 = new Integer(2502); + public Object testField2503 = new Integer(2503); + public Object testField2504 = new Integer(2504); + public Object testField2505 = new Integer(2505); + public Object testField2506 = new Integer(2506); + public Object testField2507 = new Integer(2507); + public Object testField2508 = new Integer(2508); + public Object testField2509 = new Integer(2509); + public Object testField2510 = new Integer(2510); + public Object testField2511 = new Integer(2511); + public Object testField2512 = new Integer(2512); + public Object testField2513 = new Integer(2513); + public Object testField2514 = new Integer(2514); + public Object testField2515 = new Integer(2515); + public Object testField2516 = new Integer(2516); + public Object testField2517 = new Integer(2517); + public Object testField2518 = new Integer(2518); + public Object testField2519 = new Integer(2519); + public Object testField2520 = new Integer(2520); + public Object testField2521 = new Integer(2521); + public Object testField2522 = new Integer(2522); + public Object testField2523 = new Integer(2523); + public Object testField2524 = new Integer(2524); + public Object testField2525 = new Integer(2525); + public Object testField2526 = new Integer(2526); + public Object testField2527 = new Integer(2527); + public Object testField2528 = new Integer(2528); + public Object testField2529 = new Integer(2529); + public Object testField2530 = new Integer(2530); + public Object testField2531 = new Integer(2531); + public Object testField2532 = new Integer(2532); + public Object testField2533 = new Integer(2533); + public Object testField2534 = new Integer(2534); + public Object testField2535 = new Integer(2535); + public Object testField2536 = new Integer(2536); + public Object testField2537 = new Integer(2537); + public Object testField2538 = new Integer(2538); + public Object testField2539 = new Integer(2539); + public Object testField2540 = new Integer(2540); + public Object testField2541 = new Integer(2541); + public Object testField2542 = new Integer(2542); + public Object testField2543 = new Integer(2543); + public Object testField2544 = new Integer(2544); + public Object testField2545 = new Integer(2545); + public Object testField2546 = new Integer(2546); + public Object testField2547 = new Integer(2547); + public Object testField2548 = new Integer(2548); + public Object testField2549 = new Integer(2549); + public Object testField2550 = new Integer(2550); + public Object testField2551 = new Integer(2551); + public Object testField2552 = new Integer(2552); + public Object testField2553 = new Integer(2553); + public Object testField2554 = new Integer(2554); + public Object testField2555 = new Integer(2555); + public Object testField2556 = new Integer(2556); + public Object testField2557 = new Integer(2557); + public Object testField2558 = new Integer(2558); + public Object testField2559 = new Integer(2559); + public Object testField2560 = new Integer(2560); + public Object testField2561 = new Integer(2561); + public Object testField2562 = new Integer(2562); + public Object testField2563 = new Integer(2563); + public Object testField2564 = new Integer(2564); + public Object testField2565 = new Integer(2565); + public Object testField2566 = new Integer(2566); + public Object testField2567 = new Integer(2567); + public Object testField2568 = new Integer(2568); + public Object testField2569 = new Integer(2569); + public Object testField2570 = new Integer(2570); + public Object testField2571 = new Integer(2571); + public Object testField2572 = new Integer(2572); + public Object testField2573 = new Integer(2573); + public Object testField2574 = new Integer(2574); + public Object testField2575 = new Integer(2575); + public Object testField2576 = new Integer(2576); + public Object testField2577 = new Integer(2577); + public Object testField2578 = new Integer(2578); + public Object testField2579 = new Integer(2579); + public Object testField2580 = new Integer(2580); + public Object testField2581 = new Integer(2581); + public Object testField2582 = new Integer(2582); + public Object testField2583 = new Integer(2583); + public Object testField2584 = new Integer(2584); + public Object testField2585 = new Integer(2585); + public Object testField2586 = new Integer(2586); + public Object testField2587 = new Integer(2587); + public Object testField2588 = new Integer(2588); + public Object testField2589 = new Integer(2589); + public Object testField2590 = new Integer(2590); + public Object testField2591 = new Integer(2591); + public Object testField2592 = new Integer(2592); + public Object testField2593 = new Integer(2593); + public Object testField2594 = new Integer(2594); + public Object testField2595 = new Integer(2595); + public Object testField2596 = new Integer(2596); + public Object testField2597 = new Integer(2597); + public Object testField2598 = new Integer(2598); + public Object testField2599 = new Integer(2599); + public Object testField2600 = new Integer(2600); + public Object testField2601 = new Integer(2601); + public Object testField2602 = new Integer(2602); + public Object testField2603 = new Integer(2603); + public Object testField2604 = new Integer(2604); + public Object testField2605 = new Integer(2605); + public Object testField2606 = new Integer(2606); + public Object testField2607 = new Integer(2607); + public Object testField2608 = new Integer(2608); + public Object testField2609 = new Integer(2609); + public Object testField2610 = new Integer(2610); + public Object testField2611 = new Integer(2611); + public Object testField2612 = new Integer(2612); + public Object testField2613 = new Integer(2613); + public Object testField2614 = new Integer(2614); + public Object testField2615 = new Integer(2615); + public Object testField2616 = new Integer(2616); + public Object testField2617 = new Integer(2617); + public Object testField2618 = new Integer(2618); + public Object testField2619 = new Integer(2619); + public Object testField2620 = new Integer(2620); + public Object testField2621 = new Integer(2621); + public Object testField2622 = new Integer(2622); + public Object testField2623 = new Integer(2623); + public Object testField2624 = new Integer(2624); + public Object testField2625 = new Integer(2625); + public Object testField2626 = new Integer(2626); + public Object testField2627 = new Integer(2627); + public Object testField2628 = new Integer(2628); + public Object testField2629 = new Integer(2629); + public Object testField2630 = new Integer(2630); + public Object testField2631 = new Integer(2631); + public Object testField2632 = new Integer(2632); + public Object testField2633 = new Integer(2633); + public Object testField2634 = new Integer(2634); + public Object testField2635 = new Integer(2635); + public Object testField2636 = new Integer(2636); + public Object testField2637 = new Integer(2637); + public Object testField2638 = new Integer(2638); + public Object testField2639 = new Integer(2639); + public Object testField2640 = new Integer(2640); + public Object testField2641 = new Integer(2641); + public Object testField2642 = new Integer(2642); + public Object testField2643 = new Integer(2643); + public Object testField2644 = new Integer(2644); + public Object testField2645 = new Integer(2645); + public Object testField2646 = new Integer(2646); + public Object testField2647 = new Integer(2647); + public Object testField2648 = new Integer(2648); + public Object testField2649 = new Integer(2649); + public Object testField2650 = new Integer(2650); + public Object testField2651 = new Integer(2651); + public Object testField2652 = new Integer(2652); + public Object testField2653 = new Integer(2653); + public Object testField2654 = new Integer(2654); + public Object testField2655 = new Integer(2655); + public Object testField2656 = new Integer(2656); + public Object testField2657 = new Integer(2657); + public Object testField2658 = new Integer(2658); + public Object testField2659 = new Integer(2659); + public Object testField2660 = new Integer(2660); + public Object testField2661 = new Integer(2661); + public Object testField2662 = new Integer(2662); + public Object testField2663 = new Integer(2663); + public Object testField2664 = new Integer(2664); + public Object testField2665 = new Integer(2665); + public Object testField2666 = new Integer(2666); + public Object testField2667 = new Integer(2667); + public Object testField2668 = new Integer(2668); + public Object testField2669 = new Integer(2669); + public Object testField2670 = new Integer(2670); + public Object testField2671 = new Integer(2671); + public Object testField2672 = new Integer(2672); + public Object testField2673 = new Integer(2673); + public Object testField2674 = new Integer(2674); + public Object testField2675 = new Integer(2675); + public Object testField2676 = new Integer(2676); + public Object testField2677 = new Integer(2677); + public Object testField2678 = new Integer(2678); + public Object testField2679 = new Integer(2679); + public Object testField2680 = new Integer(2680); + public Object testField2681 = new Integer(2681); + public Object testField2682 = new Integer(2682); + public Object testField2683 = new Integer(2683); + public Object testField2684 = new Integer(2684); + public Object testField2685 = new Integer(2685); + public Object testField2686 = new Integer(2686); + public Object testField2687 = new Integer(2687); + public Object testField2688 = new Integer(2688); + public Object testField2689 = new Integer(2689); + public Object testField2690 = new Integer(2690); + public Object testField2691 = new Integer(2691); + public Object testField2692 = new Integer(2692); + public Object testField2693 = new Integer(2693); + public Object testField2694 = new Integer(2694); + public Object testField2695 = new Integer(2695); + public Object testField2696 = new Integer(2696); + public Object testField2697 = new Integer(2697); + public Object testField2698 = new Integer(2698); + public Object testField2699 = new Integer(2699); + public Object testField2700 = new Integer(2700); + public Object testField2701 = new Integer(2701); + public Object testField2702 = new Integer(2702); + public Object testField2703 = new Integer(2703); + public Object testField2704 = new Integer(2704); + public Object testField2705 = new Integer(2705); + public Object testField2706 = new Integer(2706); + public Object testField2707 = new Integer(2707); + public Object testField2708 = new Integer(2708); + public Object testField2709 = new Integer(2709); + public Object testField2710 = new Integer(2710); + public Object testField2711 = new Integer(2711); + public Object testField2712 = new Integer(2712); + public Object testField2713 = new Integer(2713); + public Object testField2714 = new Integer(2714); + public Object testField2715 = new Integer(2715); + public Object testField2716 = new Integer(2716); + public Object testField2717 = new Integer(2717); + public Object testField2718 = new Integer(2718); + public Object testField2719 = new Integer(2719); + public Object testField2720 = new Integer(2720); + public Object testField2721 = new Integer(2721); + public Object testField2722 = new Integer(2722); + public Object testField2723 = new Integer(2723); + public Object testField2724 = new Integer(2724); + public Object testField2725 = new Integer(2725); + public Object testField2726 = new Integer(2726); + public Object testField2727 = new Integer(2727); + public Object testField2728 = new Integer(2728); + public Object testField2729 = new Integer(2729); + public Object testField2730 = new Integer(2730); + public Object testField2731 = new Integer(2731); + public Object testField2732 = new Integer(2732); + public Object testField2733 = new Integer(2733); + public Object testField2734 = new Integer(2734); + public Object testField2735 = new Integer(2735); + public Object testField2736 = new Integer(2736); + public Object testField2737 = new Integer(2737); + public Object testField2738 = new Integer(2738); + public Object testField2739 = new Integer(2739); + public Object testField2740 = new Integer(2740); + public Object testField2741 = new Integer(2741); + public Object testField2742 = new Integer(2742); + public Object testField2743 = new Integer(2743); + public Object testField2744 = new Integer(2744); + public Object testField2745 = new Integer(2745); + public Object testField2746 = new Integer(2746); + public Object testField2747 = new Integer(2747); + public Object testField2748 = new Integer(2748); + public Object testField2749 = new Integer(2749); + public Object testField2750 = new Integer(2750); + public Object testField2751 = new Integer(2751); + public Object testField2752 = new Integer(2752); + public Object testField2753 = new Integer(2753); + public Object testField2754 = new Integer(2754); + public Object testField2755 = new Integer(2755); + public Object testField2756 = new Integer(2756); + public Object testField2757 = new Integer(2757); + public Object testField2758 = new Integer(2758); + public Object testField2759 = new Integer(2759); + public Object testField2760 = new Integer(2760); + public Object testField2761 = new Integer(2761); + public Object testField2762 = new Integer(2762); + public Object testField2763 = new Integer(2763); + public Object testField2764 = new Integer(2764); + public Object testField2765 = new Integer(2765); + public Object testField2766 = new Integer(2766); + public Object testField2767 = new Integer(2767); + public Object testField2768 = new Integer(2768); + public Object testField2769 = new Integer(2769); + public Object testField2770 = new Integer(2770); + public Object testField2771 = new Integer(2771); + public Object testField2772 = new Integer(2772); + public Object testField2773 = new Integer(2773); + public Object testField2774 = new Integer(2774); + public Object testField2775 = new Integer(2775); + public Object testField2776 = new Integer(2776); + public Object testField2777 = new Integer(2777); + public Object testField2778 = new Integer(2778); + public Object testField2779 = new Integer(2779); + public Object testField2780 = new Integer(2780); + public Object testField2781 = new Integer(2781); + public Object testField2782 = new Integer(2782); + public Object testField2783 = new Integer(2783); + public Object testField2784 = new Integer(2784); + public Object testField2785 = new Integer(2785); + public Object testField2786 = new Integer(2786); + public Object testField2787 = new Integer(2787); + public Object testField2788 = new Integer(2788); + public Object testField2789 = new Integer(2789); + public Object testField2790 = new Integer(2790); + public Object testField2791 = new Integer(2791); + public Object testField2792 = new Integer(2792); + public Object testField2793 = new Integer(2793); + public Object testField2794 = new Integer(2794); + public Object testField2795 = new Integer(2795); + public Object testField2796 = new Integer(2796); + public Object testField2797 = new Integer(2797); + public Object testField2798 = new Integer(2798); + public Object testField2799 = new Integer(2799); + public Object testField2800 = new Integer(2800); + public Object testField2801 = new Integer(2801); + public Object testField2802 = new Integer(2802); + public Object testField2803 = new Integer(2803); + public Object testField2804 = new Integer(2804); + public Object testField2805 = new Integer(2805); + public Object testField2806 = new Integer(2806); + public Object testField2807 = new Integer(2807); + public Object testField2808 = new Integer(2808); + public Object testField2809 = new Integer(2809); + public Object testField2810 = new Integer(2810); + public Object testField2811 = new Integer(2811); + public Object testField2812 = new Integer(2812); + public Object testField2813 = new Integer(2813); + public Object testField2814 = new Integer(2814); + public Object testField2815 = new Integer(2815); + public Object testField2816 = new Integer(2816); + public Object testField2817 = new Integer(2817); + public Object testField2818 = new Integer(2818); + public Object testField2819 = new Integer(2819); + public Object testField2820 = new Integer(2820); + public Object testField2821 = new Integer(2821); + public Object testField2822 = new Integer(2822); + public Object testField2823 = new Integer(2823); + public Object testField2824 = new Integer(2824); + public Object testField2825 = new Integer(2825); + public Object testField2826 = new Integer(2826); + public Object testField2827 = new Integer(2827); + public Object testField2828 = new Integer(2828); + public Object testField2829 = new Integer(2829); + public Object testField2830 = new Integer(2830); + public Object testField2831 = new Integer(2831); + public Object testField2832 = new Integer(2832); + public Object testField2833 = new Integer(2833); + public Object testField2834 = new Integer(2834); + public Object testField2835 = new Integer(2835); + public Object testField2836 = new Integer(2836); + public Object testField2837 = new Integer(2837); + public Object testField2838 = new Integer(2838); + public Object testField2839 = new Integer(2839); + public Object testField2840 = new Integer(2840); + public Object testField2841 = new Integer(2841); + public Object testField2842 = new Integer(2842); + public Object testField2843 = new Integer(2843); + public Object testField2844 = new Integer(2844); + public Object testField2845 = new Integer(2845); + public Object testField2846 = new Integer(2846); + public Object testField2847 = new Integer(2847); + public Object testField2848 = new Integer(2848); + public Object testField2849 = new Integer(2849); + public Object testField2850 = new Integer(2850); + public Object testField2851 = new Integer(2851); + public Object testField2852 = new Integer(2852); + public Object testField2853 = new Integer(2853); + public Object testField2854 = new Integer(2854); + public Object testField2855 = new Integer(2855); + public Object testField2856 = new Integer(2856); + public Object testField2857 = new Integer(2857); + public Object testField2858 = new Integer(2858); + public Object testField2859 = new Integer(2859); + public Object testField2860 = new Integer(2860); + public Object testField2861 = new Integer(2861); + public Object testField2862 = new Integer(2862); + public Object testField2863 = new Integer(2863); + public Object testField2864 = new Integer(2864); + public Object testField2865 = new Integer(2865); + public Object testField2866 = new Integer(2866); + public Object testField2867 = new Integer(2867); + public Object testField2868 = new Integer(2868); + public Object testField2869 = new Integer(2869); + public Object testField2870 = new Integer(2870); + public Object testField2871 = new Integer(2871); + public Object testField2872 = new Integer(2872); + public Object testField2873 = new Integer(2873); + public Object testField2874 = new Integer(2874); + public Object testField2875 = new Integer(2875); + public Object testField2876 = new Integer(2876); + public Object testField2877 = new Integer(2877); + public Object testField2878 = new Integer(2878); + public Object testField2879 = new Integer(2879); + public Object testField2880 = new Integer(2880); + public Object testField2881 = new Integer(2881); + public Object testField2882 = new Integer(2882); + public Object testField2883 = new Integer(2883); + public Object testField2884 = new Integer(2884); + public Object testField2885 = new Integer(2885); + public Object testField2886 = new Integer(2886); + public Object testField2887 = new Integer(2887); + public Object testField2888 = new Integer(2888); + public Object testField2889 = new Integer(2889); + public Object testField2890 = new Integer(2890); + public Object testField2891 = new Integer(2891); + public Object testField2892 = new Integer(2892); + public Object testField2893 = new Integer(2893); + public Object testField2894 = new Integer(2894); + public Object testField2895 = new Integer(2895); + public Object testField2896 = new Integer(2896); + public Object testField2897 = new Integer(2897); + public Object testField2898 = new Integer(2898); + public Object testField2899 = new Integer(2899); + public Object testField2900 = new Integer(2900); + public Object testField2901 = new Integer(2901); + public Object testField2902 = new Integer(2902); + public Object testField2903 = new Integer(2903); + public Object testField2904 = new Integer(2904); + public Object testField2905 = new Integer(2905); + public Object testField2906 = new Integer(2906); + public Object testField2907 = new Integer(2907); + public Object testField2908 = new Integer(2908); + public Object testField2909 = new Integer(2909); + public Object testField2910 = new Integer(2910); + public Object testField2911 = new Integer(2911); + public Object testField2912 = new Integer(2912); + public Object testField2913 = new Integer(2913); + public Object testField2914 = new Integer(2914); + public Object testField2915 = new Integer(2915); + public Object testField2916 = new Integer(2916); + public Object testField2917 = new Integer(2917); + public Object testField2918 = new Integer(2918); + public Object testField2919 = new Integer(2919); + public Object testField2920 = new Integer(2920); + public Object testField2921 = new Integer(2921); + public Object testField2922 = new Integer(2922); + public Object testField2923 = new Integer(2923); + public Object testField2924 = new Integer(2924); + public Object testField2925 = new Integer(2925); + public Object testField2926 = new Integer(2926); + public Object testField2927 = new Integer(2927); + public Object testField2928 = new Integer(2928); + public Object testField2929 = new Integer(2929); + public Object testField2930 = new Integer(2930); + public Object testField2931 = new Integer(2931); + public Object testField2932 = new Integer(2932); + public Object testField2933 = new Integer(2933); + public Object testField2934 = new Integer(2934); + public Object testField2935 = new Integer(2935); + public Object testField2936 = new Integer(2936); + public Object testField2937 = new Integer(2937); + public Object testField2938 = new Integer(2938); + public Object testField2939 = new Integer(2939); + public Object testField2940 = new Integer(2940); + public Object testField2941 = new Integer(2941); + public Object testField2942 = new Integer(2942); + public Object testField2943 = new Integer(2943); + public Object testField2944 = new Integer(2944); + public Object testField2945 = new Integer(2945); + public Object testField2946 = new Integer(2946); + public Object testField2947 = new Integer(2947); + public Object testField2948 = new Integer(2948); + public Object testField2949 = new Integer(2949); + public Object testField2950 = new Integer(2950); + public Object testField2951 = new Integer(2951); + public Object testField2952 = new Integer(2952); + public Object testField2953 = new Integer(2953); + public Object testField2954 = new Integer(2954); + public Object testField2955 = new Integer(2955); + public Object testField2956 = new Integer(2956); + public Object testField2957 = new Integer(2957); + public Object testField2958 = new Integer(2958); + public Object testField2959 = new Integer(2959); + public Object testField2960 = new Integer(2960); + public Object testField2961 = new Integer(2961); + public Object testField2962 = new Integer(2962); + public Object testField2963 = new Integer(2963); + public Object testField2964 = new Integer(2964); + public Object testField2965 = new Integer(2965); + public Object testField2966 = new Integer(2966); + public Object testField2967 = new Integer(2967); + public Object testField2968 = new Integer(2968); + public Object testField2969 = new Integer(2969); + public Object testField2970 = new Integer(2970); + public Object testField2971 = new Integer(2971); + public Object testField2972 = new Integer(2972); + public Object testField2973 = new Integer(2973); + public Object testField2974 = new Integer(2974); + public Object testField2975 = new Integer(2975); + public Object testField2976 = new Integer(2976); + public Object testField2977 = new Integer(2977); + public Object testField2978 = new Integer(2978); + public Object testField2979 = new Integer(2979); + public Object testField2980 = new Integer(2980); + public Object testField2981 = new Integer(2981); + public Object testField2982 = new Integer(2982); + public Object testField2983 = new Integer(2983); + public Object testField2984 = new Integer(2984); + public Object testField2985 = new Integer(2985); + public Object testField2986 = new Integer(2986); + public Object testField2987 = new Integer(2987); + public Object testField2988 = new Integer(2988); + public Object testField2989 = new Integer(2989); + public Object testField2990 = new Integer(2990); + public Object testField2991 = new Integer(2991); + public Object testField2992 = new Integer(2992); + public Object testField2993 = new Integer(2993); + public Object testField2994 = new Integer(2994); + public Object testField2995 = new Integer(2995); + public Object testField2996 = new Integer(2996); + public Object testField2997 = new Integer(2997); + public Object testField2998 = new Integer(2998); + public Object testField2999 = new Integer(2999); +} diff --git a/test/160-read-barrier-stress/src/ManyFieldsBase3.java b/test/160-read-barrier-stress/src/ManyFieldsBase3.java new file mode 100644 index 0000000000..e7cfaac4fe --- /dev/null +++ b/test/160-read-barrier-stress/src/ManyFieldsBase3.java @@ -0,0 +1,1018 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +class ManyFieldsBase3 extends ManyFieldsBase2 { + public Object testField3000 = new Integer(3000); + public Object testField3001 = new Integer(3001); + public Object testField3002 = new Integer(3002); + public Object testField3003 = new Integer(3003); + public Object testField3004 = new Integer(3004); + public Object testField3005 = new Integer(3005); + public Object testField3006 = new Integer(3006); + public Object testField3007 = new Integer(3007); + public Object testField3008 = new Integer(3008); + public Object testField3009 = new Integer(3009); + public Object testField3010 = new Integer(3010); + public Object testField3011 = new Integer(3011); + public Object testField3012 = new Integer(3012); + public Object testField3013 = new Integer(3013); + public Object testField3014 = new Integer(3014); + public Object testField3015 = new Integer(3015); + public Object testField3016 = new Integer(3016); + public Object testField3017 = new Integer(3017); + public Object testField3018 = new Integer(3018); + public Object testField3019 = new Integer(3019); + public Object testField3020 = new Integer(3020); + public Object testField3021 = new Integer(3021); + public Object testField3022 = new Integer(3022); + public Object testField3023 = new Integer(3023); + public Object testField3024 = new Integer(3024); + public Object testField3025 = new Integer(3025); + public Object testField3026 = new Integer(3026); + public Object testField3027 = new Integer(3027); + public Object testField3028 = new Integer(3028); + public Object testField3029 = new Integer(3029); + public Object testField3030 = new Integer(3030); + public Object testField3031 = new Integer(3031); + public Object testField3032 = new Integer(3032); + public Object testField3033 = new Integer(3033); + public Object testField3034 = new Integer(3034); + public Object testField3035 = new Integer(3035); + public Object testField3036 = new Integer(3036); + public Object testField3037 = new Integer(3037); + public Object testField3038 = new Integer(3038); + public Object testField3039 = new Integer(3039); + public Object testField3040 = new Integer(3040); + public Object testField3041 = new Integer(3041); + public Object testField3042 = new Integer(3042); + public Object testField3043 = new Integer(3043); + public Object testField3044 = new Integer(3044); + public Object testField3045 = new Integer(3045); + public Object testField3046 = new Integer(3046); + public Object testField3047 = new Integer(3047); + public Object testField3048 = new Integer(3048); + public Object testField3049 = new Integer(3049); + public Object testField3050 = new Integer(3050); + public Object testField3051 = new Integer(3051); + public Object testField3052 = new Integer(3052); + public Object testField3053 = new Integer(3053); + public Object testField3054 = new Integer(3054); + public Object testField3055 = new Integer(3055); + public Object testField3056 = new Integer(3056); + public Object testField3057 = new Integer(3057); + public Object testField3058 = new Integer(3058); + public Object testField3059 = new Integer(3059); + public Object testField3060 = new Integer(3060); + public Object testField3061 = new Integer(3061); + public Object testField3062 = new Integer(3062); + public Object testField3063 = new Integer(3063); + public Object testField3064 = new Integer(3064); + public Object testField3065 = new Integer(3065); + public Object testField3066 = new Integer(3066); + public Object testField3067 = new Integer(3067); + public Object testField3068 = new Integer(3068); + public Object testField3069 = new Integer(3069); + public Object testField3070 = new Integer(3070); + public Object testField3071 = new Integer(3071); + public Object testField3072 = new Integer(3072); + public Object testField3073 = new Integer(3073); + public Object testField3074 = new Integer(3074); + public Object testField3075 = new Integer(3075); + public Object testField3076 = new Integer(3076); + public Object testField3077 = new Integer(3077); + public Object testField3078 = new Integer(3078); + public Object testField3079 = new Integer(3079); + public Object testField3080 = new Integer(3080); + public Object testField3081 = new Integer(3081); + public Object testField3082 = new Integer(3082); + public Object testField3083 = new Integer(3083); + public Object testField3084 = new Integer(3084); + public Object testField3085 = new Integer(3085); + public Object testField3086 = new Integer(3086); + public Object testField3087 = new Integer(3087); + public Object testField3088 = new Integer(3088); + public Object testField3089 = new Integer(3089); + public Object testField3090 = new Integer(3090); + public Object testField3091 = new Integer(3091); + public Object testField3092 = new Integer(3092); + public Object testField3093 = new Integer(3093); + public Object testField3094 = new Integer(3094); + public Object testField3095 = new Integer(3095); + public Object testField3096 = new Integer(3096); + public Object testField3097 = new Integer(3097); + public Object testField3098 = new Integer(3098); + public Object testField3099 = new Integer(3099); + public Object testField3100 = new Integer(3100); + public Object testField3101 = new Integer(3101); + public Object testField3102 = new Integer(3102); + public Object testField3103 = new Integer(3103); + public Object testField3104 = new Integer(3104); + public Object testField3105 = new Integer(3105); + public Object testField3106 = new Integer(3106); + public Object testField3107 = new Integer(3107); + public Object testField3108 = new Integer(3108); + public Object testField3109 = new Integer(3109); + public Object testField3110 = new Integer(3110); + public Object testField3111 = new Integer(3111); + public Object testField3112 = new Integer(3112); + public Object testField3113 = new Integer(3113); + public Object testField3114 = new Integer(3114); + public Object testField3115 = new Integer(3115); + public Object testField3116 = new Integer(3116); + public Object testField3117 = new Integer(3117); + public Object testField3118 = new Integer(3118); + public Object testField3119 = new Integer(3119); + public Object testField3120 = new Integer(3120); + public Object testField3121 = new Integer(3121); + public Object testField3122 = new Integer(3122); + public Object testField3123 = new Integer(3123); + public Object testField3124 = new Integer(3124); + public Object testField3125 = new Integer(3125); + public Object testField3126 = new Integer(3126); + public Object testField3127 = new Integer(3127); + public Object testField3128 = new Integer(3128); + public Object testField3129 = new Integer(3129); + public Object testField3130 = new Integer(3130); + public Object testField3131 = new Integer(3131); + public Object testField3132 = new Integer(3132); + public Object testField3133 = new Integer(3133); + public Object testField3134 = new Integer(3134); + public Object testField3135 = new Integer(3135); + public Object testField3136 = new Integer(3136); + public Object testField3137 = new Integer(3137); + public Object testField3138 = new Integer(3138); + public Object testField3139 = new Integer(3139); + public Object testField3140 = new Integer(3140); + public Object testField3141 = new Integer(3141); + public Object testField3142 = new Integer(3142); + public Object testField3143 = new Integer(3143); + public Object testField3144 = new Integer(3144); + public Object testField3145 = new Integer(3145); + public Object testField3146 = new Integer(3146); + public Object testField3147 = new Integer(3147); + public Object testField3148 = new Integer(3148); + public Object testField3149 = new Integer(3149); + public Object testField3150 = new Integer(3150); + public Object testField3151 = new Integer(3151); + public Object testField3152 = new Integer(3152); + public Object testField3153 = new Integer(3153); + public Object testField3154 = new Integer(3154); + public Object testField3155 = new Integer(3155); + public Object testField3156 = new Integer(3156); + public Object testField3157 = new Integer(3157); + public Object testField3158 = new Integer(3158); + public Object testField3159 = new Integer(3159); + public Object testField3160 = new Integer(3160); + public Object testField3161 = new Integer(3161); + public Object testField3162 = new Integer(3162); + public Object testField3163 = new Integer(3163); + public Object testField3164 = new Integer(3164); + public Object testField3165 = new Integer(3165); + public Object testField3166 = new Integer(3166); + public Object testField3167 = new Integer(3167); + public Object testField3168 = new Integer(3168); + public Object testField3169 = new Integer(3169); + public Object testField3170 = new Integer(3170); + public Object testField3171 = new Integer(3171); + public Object testField3172 = new Integer(3172); + public Object testField3173 = new Integer(3173); + public Object testField3174 = new Integer(3174); + public Object testField3175 = new Integer(3175); + public Object testField3176 = new Integer(3176); + public Object testField3177 = new Integer(3177); + public Object testField3178 = new Integer(3178); + public Object testField3179 = new Integer(3179); + public Object testField3180 = new Integer(3180); + public Object testField3181 = new Integer(3181); + public Object testField3182 = new Integer(3182); + public Object testField3183 = new Integer(3183); + public Object testField3184 = new Integer(3184); + public Object testField3185 = new Integer(3185); + public Object testField3186 = new Integer(3186); + public Object testField3187 = new Integer(3187); + public Object testField3188 = new Integer(3188); + public Object testField3189 = new Integer(3189); + public Object testField3190 = new Integer(3190); + public Object testField3191 = new Integer(3191); + public Object testField3192 = new Integer(3192); + public Object testField3193 = new Integer(3193); + public Object testField3194 = new Integer(3194); + public Object testField3195 = new Integer(3195); + public Object testField3196 = new Integer(3196); + public Object testField3197 = new Integer(3197); + public Object testField3198 = new Integer(3198); + public Object testField3199 = new Integer(3199); + public Object testField3200 = new Integer(3200); + public Object testField3201 = new Integer(3201); + public Object testField3202 = new Integer(3202); + public Object testField3203 = new Integer(3203); + public Object testField3204 = new Integer(3204); + public Object testField3205 = new Integer(3205); + public Object testField3206 = new Integer(3206); + public Object testField3207 = new Integer(3207); + public Object testField3208 = new Integer(3208); + public Object testField3209 = new Integer(3209); + public Object testField3210 = new Integer(3210); + public Object testField3211 = new Integer(3211); + public Object testField3212 = new Integer(3212); + public Object testField3213 = new Integer(3213); + public Object testField3214 = new Integer(3214); + public Object testField3215 = new Integer(3215); + public Object testField3216 = new Integer(3216); + public Object testField3217 = new Integer(3217); + public Object testField3218 = new Integer(3218); + public Object testField3219 = new Integer(3219); + public Object testField3220 = new Integer(3220); + public Object testField3221 = new Integer(3221); + public Object testField3222 = new Integer(3222); + public Object testField3223 = new Integer(3223); + public Object testField3224 = new Integer(3224); + public Object testField3225 = new Integer(3225); + public Object testField3226 = new Integer(3226); + public Object testField3227 = new Integer(3227); + public Object testField3228 = new Integer(3228); + public Object testField3229 = new Integer(3229); + public Object testField3230 = new Integer(3230); + public Object testField3231 = new Integer(3231); + public Object testField3232 = new Integer(3232); + public Object testField3233 = new Integer(3233); + public Object testField3234 = new Integer(3234); + public Object testField3235 = new Integer(3235); + public Object testField3236 = new Integer(3236); + public Object testField3237 = new Integer(3237); + public Object testField3238 = new Integer(3238); + public Object testField3239 = new Integer(3239); + public Object testField3240 = new Integer(3240); + public Object testField3241 = new Integer(3241); + public Object testField3242 = new Integer(3242); + public Object testField3243 = new Integer(3243); + public Object testField3244 = new Integer(3244); + public Object testField3245 = new Integer(3245); + public Object testField3246 = new Integer(3246); + public Object testField3247 = new Integer(3247); + public Object testField3248 = new Integer(3248); + public Object testField3249 = new Integer(3249); + public Object testField3250 = new Integer(3250); + public Object testField3251 = new Integer(3251); + public Object testField3252 = new Integer(3252); + public Object testField3253 = new Integer(3253); + public Object testField3254 = new Integer(3254); + public Object testField3255 = new Integer(3255); + public Object testField3256 = new Integer(3256); + public Object testField3257 = new Integer(3257); + public Object testField3258 = new Integer(3258); + public Object testField3259 = new Integer(3259); + public Object testField3260 = new Integer(3260); + public Object testField3261 = new Integer(3261); + public Object testField3262 = new Integer(3262); + public Object testField3263 = new Integer(3263); + public Object testField3264 = new Integer(3264); + public Object testField3265 = new Integer(3265); + public Object testField3266 = new Integer(3266); + public Object testField3267 = new Integer(3267); + public Object testField3268 = new Integer(3268); + public Object testField3269 = new Integer(3269); + public Object testField3270 = new Integer(3270); + public Object testField3271 = new Integer(3271); + public Object testField3272 = new Integer(3272); + public Object testField3273 = new Integer(3273); + public Object testField3274 = new Integer(3274); + public Object testField3275 = new Integer(3275); + public Object testField3276 = new Integer(3276); + public Object testField3277 = new Integer(3277); + public Object testField3278 = new Integer(3278); + public Object testField3279 = new Integer(3279); + public Object testField3280 = new Integer(3280); + public Object testField3281 = new Integer(3281); + public Object testField3282 = new Integer(3282); + public Object testField3283 = new Integer(3283); + public Object testField3284 = new Integer(3284); + public Object testField3285 = new Integer(3285); + public Object testField3286 = new Integer(3286); + public Object testField3287 = new Integer(3287); + public Object testField3288 = new Integer(3288); + public Object testField3289 = new Integer(3289); + public Object testField3290 = new Integer(3290); + public Object testField3291 = new Integer(3291); + public Object testField3292 = new Integer(3292); + public Object testField3293 = new Integer(3293); + public Object testField3294 = new Integer(3294); + public Object testField3295 = new Integer(3295); + public Object testField3296 = new Integer(3296); + public Object testField3297 = new Integer(3297); + public Object testField3298 = new Integer(3298); + public Object testField3299 = new Integer(3299); + public Object testField3300 = new Integer(3300); + public Object testField3301 = new Integer(3301); + public Object testField3302 = new Integer(3302); + public Object testField3303 = new Integer(3303); + public Object testField3304 = new Integer(3304); + public Object testField3305 = new Integer(3305); + public Object testField3306 = new Integer(3306); + public Object testField3307 = new Integer(3307); + public Object testField3308 = new Integer(3308); + public Object testField3309 = new Integer(3309); + public Object testField3310 = new Integer(3310); + public Object testField3311 = new Integer(3311); + public Object testField3312 = new Integer(3312); + public Object testField3313 = new Integer(3313); + public Object testField3314 = new Integer(3314); + public Object testField3315 = new Integer(3315); + public Object testField3316 = new Integer(3316); + public Object testField3317 = new Integer(3317); + public Object testField3318 = new Integer(3318); + public Object testField3319 = new Integer(3319); + public Object testField3320 = new Integer(3320); + public Object testField3321 = new Integer(3321); + public Object testField3322 = new Integer(3322); + public Object testField3323 = new Integer(3323); + public Object testField3324 = new Integer(3324); + public Object testField3325 = new Integer(3325); + public Object testField3326 = new Integer(3326); + public Object testField3327 = new Integer(3327); + public Object testField3328 = new Integer(3328); + public Object testField3329 = new Integer(3329); + public Object testField3330 = new Integer(3330); + public Object testField3331 = new Integer(3331); + public Object testField3332 = new Integer(3332); + public Object testField3333 = new Integer(3333); + public Object testField3334 = new Integer(3334); + public Object testField3335 = new Integer(3335); + public Object testField3336 = new Integer(3336); + public Object testField3337 = new Integer(3337); + public Object testField3338 = new Integer(3338); + public Object testField3339 = new Integer(3339); + public Object testField3340 = new Integer(3340); + public Object testField3341 = new Integer(3341); + public Object testField3342 = new Integer(3342); + public Object testField3343 = new Integer(3343); + public Object testField3344 = new Integer(3344); + public Object testField3345 = new Integer(3345); + public Object testField3346 = new Integer(3346); + public Object testField3347 = new Integer(3347); + public Object testField3348 = new Integer(3348); + public Object testField3349 = new Integer(3349); + public Object testField3350 = new Integer(3350); + public Object testField3351 = new Integer(3351); + public Object testField3352 = new Integer(3352); + public Object testField3353 = new Integer(3353); + public Object testField3354 = new Integer(3354); + public Object testField3355 = new Integer(3355); + public Object testField3356 = new Integer(3356); + public Object testField3357 = new Integer(3357); + public Object testField3358 = new Integer(3358); + public Object testField3359 = new Integer(3359); + public Object testField3360 = new Integer(3360); + public Object testField3361 = new Integer(3361); + public Object testField3362 = new Integer(3362); + public Object testField3363 = new Integer(3363); + public Object testField3364 = new Integer(3364); + public Object testField3365 = new Integer(3365); + public Object testField3366 = new Integer(3366); + public Object testField3367 = new Integer(3367); + public Object testField3368 = new Integer(3368); + public Object testField3369 = new Integer(3369); + public Object testField3370 = new Integer(3370); + public Object testField3371 = new Integer(3371); + public Object testField3372 = new Integer(3372); + public Object testField3373 = new Integer(3373); + public Object testField3374 = new Integer(3374); + public Object testField3375 = new Integer(3375); + public Object testField3376 = new Integer(3376); + public Object testField3377 = new Integer(3377); + public Object testField3378 = new Integer(3378); + public Object testField3379 = new Integer(3379); + public Object testField3380 = new Integer(3380); + public Object testField3381 = new Integer(3381); + public Object testField3382 = new Integer(3382); + public Object testField3383 = new Integer(3383); + public Object testField3384 = new Integer(3384); + public Object testField3385 = new Integer(3385); + public Object testField3386 = new Integer(3386); + public Object testField3387 = new Integer(3387); + public Object testField3388 = new Integer(3388); + public Object testField3389 = new Integer(3389); + public Object testField3390 = new Integer(3390); + public Object testField3391 = new Integer(3391); + public Object testField3392 = new Integer(3392); + public Object testField3393 = new Integer(3393); + public Object testField3394 = new Integer(3394); + public Object testField3395 = new Integer(3395); + public Object testField3396 = new Integer(3396); + public Object testField3397 = new Integer(3397); + public Object testField3398 = new Integer(3398); + public Object testField3399 = new Integer(3399); + public Object testField3400 = new Integer(3400); + public Object testField3401 = new Integer(3401); + public Object testField3402 = new Integer(3402); + public Object testField3403 = new Integer(3403); + public Object testField3404 = new Integer(3404); + public Object testField3405 = new Integer(3405); + public Object testField3406 = new Integer(3406); + public Object testField3407 = new Integer(3407); + public Object testField3408 = new Integer(3408); + public Object testField3409 = new Integer(3409); + public Object testField3410 = new Integer(3410); + public Object testField3411 = new Integer(3411); + public Object testField3412 = new Integer(3412); + public Object testField3413 = new Integer(3413); + public Object testField3414 = new Integer(3414); + public Object testField3415 = new Integer(3415); + public Object testField3416 = new Integer(3416); + public Object testField3417 = new Integer(3417); + public Object testField3418 = new Integer(3418); + public Object testField3419 = new Integer(3419); + public Object testField3420 = new Integer(3420); + public Object testField3421 = new Integer(3421); + public Object testField3422 = new Integer(3422); + public Object testField3423 = new Integer(3423); + public Object testField3424 = new Integer(3424); + public Object testField3425 = new Integer(3425); + public Object testField3426 = new Integer(3426); + public Object testField3427 = new Integer(3427); + public Object testField3428 = new Integer(3428); + public Object testField3429 = new Integer(3429); + public Object testField3430 = new Integer(3430); + public Object testField3431 = new Integer(3431); + public Object testField3432 = new Integer(3432); + public Object testField3433 = new Integer(3433); + public Object testField3434 = new Integer(3434); + public Object testField3435 = new Integer(3435); + public Object testField3436 = new Integer(3436); + public Object testField3437 = new Integer(3437); + public Object testField3438 = new Integer(3438); + public Object testField3439 = new Integer(3439); + public Object testField3440 = new Integer(3440); + public Object testField3441 = new Integer(3441); + public Object testField3442 = new Integer(3442); + public Object testField3443 = new Integer(3443); + public Object testField3444 = new Integer(3444); + public Object testField3445 = new Integer(3445); + public Object testField3446 = new Integer(3446); + public Object testField3447 = new Integer(3447); + public Object testField3448 = new Integer(3448); + public Object testField3449 = new Integer(3449); + public Object testField3450 = new Integer(3450); + public Object testField3451 = new Integer(3451); + public Object testField3452 = new Integer(3452); + public Object testField3453 = new Integer(3453); + public Object testField3454 = new Integer(3454); + public Object testField3455 = new Integer(3455); + public Object testField3456 = new Integer(3456); + public Object testField3457 = new Integer(3457); + public Object testField3458 = new Integer(3458); + public Object testField3459 = new Integer(3459); + public Object testField3460 = new Integer(3460); + public Object testField3461 = new Integer(3461); + public Object testField3462 = new Integer(3462); + public Object testField3463 = new Integer(3463); + public Object testField3464 = new Integer(3464); + public Object testField3465 = new Integer(3465); + public Object testField3466 = new Integer(3466); + public Object testField3467 = new Integer(3467); + public Object testField3468 = new Integer(3468); + public Object testField3469 = new Integer(3469); + public Object testField3470 = new Integer(3470); + public Object testField3471 = new Integer(3471); + public Object testField3472 = new Integer(3472); + public Object testField3473 = new Integer(3473); + public Object testField3474 = new Integer(3474); + public Object testField3475 = new Integer(3475); + public Object testField3476 = new Integer(3476); + public Object testField3477 = new Integer(3477); + public Object testField3478 = new Integer(3478); + public Object testField3479 = new Integer(3479); + public Object testField3480 = new Integer(3480); + public Object testField3481 = new Integer(3481); + public Object testField3482 = new Integer(3482); + public Object testField3483 = new Integer(3483); + public Object testField3484 = new Integer(3484); + public Object testField3485 = new Integer(3485); + public Object testField3486 = new Integer(3486); + public Object testField3487 = new Integer(3487); + public Object testField3488 = new Integer(3488); + public Object testField3489 = new Integer(3489); + public Object testField3490 = new Integer(3490); + public Object testField3491 = new Integer(3491); + public Object testField3492 = new Integer(3492); + public Object testField3493 = new Integer(3493); + public Object testField3494 = new Integer(3494); + public Object testField3495 = new Integer(3495); + public Object testField3496 = new Integer(3496); + public Object testField3497 = new Integer(3497); + public Object testField3498 = new Integer(3498); + public Object testField3499 = new Integer(3499); + public Object testField3500 = new Integer(3500); + public Object testField3501 = new Integer(3501); + public Object testField3502 = new Integer(3502); + public Object testField3503 = new Integer(3503); + public Object testField3504 = new Integer(3504); + public Object testField3505 = new Integer(3505); + public Object testField3506 = new Integer(3506); + public Object testField3507 = new Integer(3507); + public Object testField3508 = new Integer(3508); + public Object testField3509 = new Integer(3509); + public Object testField3510 = new Integer(3510); + public Object testField3511 = new Integer(3511); + public Object testField3512 = new Integer(3512); + public Object testField3513 = new Integer(3513); + public Object testField3514 = new Integer(3514); + public Object testField3515 = new Integer(3515); + public Object testField3516 = new Integer(3516); + public Object testField3517 = new Integer(3517); + public Object testField3518 = new Integer(3518); + public Object testField3519 = new Integer(3519); + public Object testField3520 = new Integer(3520); + public Object testField3521 = new Integer(3521); + public Object testField3522 = new Integer(3522); + public Object testField3523 = new Integer(3523); + public Object testField3524 = new Integer(3524); + public Object testField3525 = new Integer(3525); + public Object testField3526 = new Integer(3526); + public Object testField3527 = new Integer(3527); + public Object testField3528 = new Integer(3528); + public Object testField3529 = new Integer(3529); + public Object testField3530 = new Integer(3530); + public Object testField3531 = new Integer(3531); + public Object testField3532 = new Integer(3532); + public Object testField3533 = new Integer(3533); + public Object testField3534 = new Integer(3534); + public Object testField3535 = new Integer(3535); + public Object testField3536 = new Integer(3536); + public Object testField3537 = new Integer(3537); + public Object testField3538 = new Integer(3538); + public Object testField3539 = new Integer(3539); + public Object testField3540 = new Integer(3540); + public Object testField3541 = new Integer(3541); + public Object testField3542 = new Integer(3542); + public Object testField3543 = new Integer(3543); + public Object testField3544 = new Integer(3544); + public Object testField3545 = new Integer(3545); + public Object testField3546 = new Integer(3546); + public Object testField3547 = new Integer(3547); + public Object testField3548 = new Integer(3548); + public Object testField3549 = new Integer(3549); + public Object testField3550 = new Integer(3550); + public Object testField3551 = new Integer(3551); + public Object testField3552 = new Integer(3552); + public Object testField3553 = new Integer(3553); + public Object testField3554 = new Integer(3554); + public Object testField3555 = new Integer(3555); + public Object testField3556 = new Integer(3556); + public Object testField3557 = new Integer(3557); + public Object testField3558 = new Integer(3558); + public Object testField3559 = new Integer(3559); + public Object testField3560 = new Integer(3560); + public Object testField3561 = new Integer(3561); + public Object testField3562 = new Integer(3562); + public Object testField3563 = new Integer(3563); + public Object testField3564 = new Integer(3564); + public Object testField3565 = new Integer(3565); + public Object testField3566 = new Integer(3566); + public Object testField3567 = new Integer(3567); + public Object testField3568 = new Integer(3568); + public Object testField3569 = new Integer(3569); + public Object testField3570 = new Integer(3570); + public Object testField3571 = new Integer(3571); + public Object testField3572 = new Integer(3572); + public Object testField3573 = new Integer(3573); + public Object testField3574 = new Integer(3574); + public Object testField3575 = new Integer(3575); + public Object testField3576 = new Integer(3576); + public Object testField3577 = new Integer(3577); + public Object testField3578 = new Integer(3578); + public Object testField3579 = new Integer(3579); + public Object testField3580 = new Integer(3580); + public Object testField3581 = new Integer(3581); + public Object testField3582 = new Integer(3582); + public Object testField3583 = new Integer(3583); + public Object testField3584 = new Integer(3584); + public Object testField3585 = new Integer(3585); + public Object testField3586 = new Integer(3586); + public Object testField3587 = new Integer(3587); + public Object testField3588 = new Integer(3588); + public Object testField3589 = new Integer(3589); + public Object testField3590 = new Integer(3590); + public Object testField3591 = new Integer(3591); + public Object testField3592 = new Integer(3592); + public Object testField3593 = new Integer(3593); + public Object testField3594 = new Integer(3594); + public Object testField3595 = new Integer(3595); + public Object testField3596 = new Integer(3596); + public Object testField3597 = new Integer(3597); + public Object testField3598 = new Integer(3598); + public Object testField3599 = new Integer(3599); + public Object testField3600 = new Integer(3600); + public Object testField3601 = new Integer(3601); + public Object testField3602 = new Integer(3602); + public Object testField3603 = new Integer(3603); + public Object testField3604 = new Integer(3604); + public Object testField3605 = new Integer(3605); + public Object testField3606 = new Integer(3606); + public Object testField3607 = new Integer(3607); + public Object testField3608 = new Integer(3608); + public Object testField3609 = new Integer(3609); + public Object testField3610 = new Integer(3610); + public Object testField3611 = new Integer(3611); + public Object testField3612 = new Integer(3612); + public Object testField3613 = new Integer(3613); + public Object testField3614 = new Integer(3614); + public Object testField3615 = new Integer(3615); + public Object testField3616 = new Integer(3616); + public Object testField3617 = new Integer(3617); + public Object testField3618 = new Integer(3618); + public Object testField3619 = new Integer(3619); + public Object testField3620 = new Integer(3620); + public Object testField3621 = new Integer(3621); + public Object testField3622 = new Integer(3622); + public Object testField3623 = new Integer(3623); + public Object testField3624 = new Integer(3624); + public Object testField3625 = new Integer(3625); + public Object testField3626 = new Integer(3626); + public Object testField3627 = new Integer(3627); + public Object testField3628 = new Integer(3628); + public Object testField3629 = new Integer(3629); + public Object testField3630 = new Integer(3630); + public Object testField3631 = new Integer(3631); + public Object testField3632 = new Integer(3632); + public Object testField3633 = new Integer(3633); + public Object testField3634 = new Integer(3634); + public Object testField3635 = new Integer(3635); + public Object testField3636 = new Integer(3636); + public Object testField3637 = new Integer(3637); + public Object testField3638 = new Integer(3638); + public Object testField3639 = new Integer(3639); + public Object testField3640 = new Integer(3640); + public Object testField3641 = new Integer(3641); + public Object testField3642 = new Integer(3642); + public Object testField3643 = new Integer(3643); + public Object testField3644 = new Integer(3644); + public Object testField3645 = new Integer(3645); + public Object testField3646 = new Integer(3646); + public Object testField3647 = new Integer(3647); + public Object testField3648 = new Integer(3648); + public Object testField3649 = new Integer(3649); + public Object testField3650 = new Integer(3650); + public Object testField3651 = new Integer(3651); + public Object testField3652 = new Integer(3652); + public Object testField3653 = new Integer(3653); + public Object testField3654 = new Integer(3654); + public Object testField3655 = new Integer(3655); + public Object testField3656 = new Integer(3656); + public Object testField3657 = new Integer(3657); + public Object testField3658 = new Integer(3658); + public Object testField3659 = new Integer(3659); + public Object testField3660 = new Integer(3660); + public Object testField3661 = new Integer(3661); + public Object testField3662 = new Integer(3662); + public Object testField3663 = new Integer(3663); + public Object testField3664 = new Integer(3664); + public Object testField3665 = new Integer(3665); + public Object testField3666 = new Integer(3666); + public Object testField3667 = new Integer(3667); + public Object testField3668 = new Integer(3668); + public Object testField3669 = new Integer(3669); + public Object testField3670 = new Integer(3670); + public Object testField3671 = new Integer(3671); + public Object testField3672 = new Integer(3672); + public Object testField3673 = new Integer(3673); + public Object testField3674 = new Integer(3674); + public Object testField3675 = new Integer(3675); + public Object testField3676 = new Integer(3676); + public Object testField3677 = new Integer(3677); + public Object testField3678 = new Integer(3678); + public Object testField3679 = new Integer(3679); + public Object testField3680 = new Integer(3680); + public Object testField3681 = new Integer(3681); + public Object testField3682 = new Integer(3682); + public Object testField3683 = new Integer(3683); + public Object testField3684 = new Integer(3684); + public Object testField3685 = new Integer(3685); + public Object testField3686 = new Integer(3686); + public Object testField3687 = new Integer(3687); + public Object testField3688 = new Integer(3688); + public Object testField3689 = new Integer(3689); + public Object testField3690 = new Integer(3690); + public Object testField3691 = new Integer(3691); + public Object testField3692 = new Integer(3692); + public Object testField3693 = new Integer(3693); + public Object testField3694 = new Integer(3694); + public Object testField3695 = new Integer(3695); + public Object testField3696 = new Integer(3696); + public Object testField3697 = new Integer(3697); + public Object testField3698 = new Integer(3698); + public Object testField3699 = new Integer(3699); + public Object testField3700 = new Integer(3700); + public Object testField3701 = new Integer(3701); + public Object testField3702 = new Integer(3702); + public Object testField3703 = new Integer(3703); + public Object testField3704 = new Integer(3704); + public Object testField3705 = new Integer(3705); + public Object testField3706 = new Integer(3706); + public Object testField3707 = new Integer(3707); + public Object testField3708 = new Integer(3708); + public Object testField3709 = new Integer(3709); + public Object testField3710 = new Integer(3710); + public Object testField3711 = new Integer(3711); + public Object testField3712 = new Integer(3712); + public Object testField3713 = new Integer(3713); + public Object testField3714 = new Integer(3714); + public Object testField3715 = new Integer(3715); + public Object testField3716 = new Integer(3716); + public Object testField3717 = new Integer(3717); + public Object testField3718 = new Integer(3718); + public Object testField3719 = new Integer(3719); + public Object testField3720 = new Integer(3720); + public Object testField3721 = new Integer(3721); + public Object testField3722 = new Integer(3722); + public Object testField3723 = new Integer(3723); + public Object testField3724 = new Integer(3724); + public Object testField3725 = new Integer(3725); + public Object testField3726 = new Integer(3726); + public Object testField3727 = new Integer(3727); + public Object testField3728 = new Integer(3728); + public Object testField3729 = new Integer(3729); + public Object testField3730 = new Integer(3730); + public Object testField3731 = new Integer(3731); + public Object testField3732 = new Integer(3732); + public Object testField3733 = new Integer(3733); + public Object testField3734 = new Integer(3734); + public Object testField3735 = new Integer(3735); + public Object testField3736 = new Integer(3736); + public Object testField3737 = new Integer(3737); + public Object testField3738 = new Integer(3738); + public Object testField3739 = new Integer(3739); + public Object testField3740 = new Integer(3740); + public Object testField3741 = new Integer(3741); + public Object testField3742 = new Integer(3742); + public Object testField3743 = new Integer(3743); + public Object testField3744 = new Integer(3744); + public Object testField3745 = new Integer(3745); + public Object testField3746 = new Integer(3746); + public Object testField3747 = new Integer(3747); + public Object testField3748 = new Integer(3748); + public Object testField3749 = new Integer(3749); + public Object testField3750 = new Integer(3750); + public Object testField3751 = new Integer(3751); + public Object testField3752 = new Integer(3752); + public Object testField3753 = new Integer(3753); + public Object testField3754 = new Integer(3754); + public Object testField3755 = new Integer(3755); + public Object testField3756 = new Integer(3756); + public Object testField3757 = new Integer(3757); + public Object testField3758 = new Integer(3758); + public Object testField3759 = new Integer(3759); + public Object testField3760 = new Integer(3760); + public Object testField3761 = new Integer(3761); + public Object testField3762 = new Integer(3762); + public Object testField3763 = new Integer(3763); + public Object testField3764 = new Integer(3764); + public Object testField3765 = new Integer(3765); + public Object testField3766 = new Integer(3766); + public Object testField3767 = new Integer(3767); + public Object testField3768 = new Integer(3768); + public Object testField3769 = new Integer(3769); + public Object testField3770 = new Integer(3770); + public Object testField3771 = new Integer(3771); + public Object testField3772 = new Integer(3772); + public Object testField3773 = new Integer(3773); + public Object testField3774 = new Integer(3774); + public Object testField3775 = new Integer(3775); + public Object testField3776 = new Integer(3776); + public Object testField3777 = new Integer(3777); + public Object testField3778 = new Integer(3778); + public Object testField3779 = new Integer(3779); + public Object testField3780 = new Integer(3780); + public Object testField3781 = new Integer(3781); + public Object testField3782 = new Integer(3782); + public Object testField3783 = new Integer(3783); + public Object testField3784 = new Integer(3784); + public Object testField3785 = new Integer(3785); + public Object testField3786 = new Integer(3786); + public Object testField3787 = new Integer(3787); + public Object testField3788 = new Integer(3788); + public Object testField3789 = new Integer(3789); + public Object testField3790 = new Integer(3790); + public Object testField3791 = new Integer(3791); + public Object testField3792 = new Integer(3792); + public Object testField3793 = new Integer(3793); + public Object testField3794 = new Integer(3794); + public Object testField3795 = new Integer(3795); + public Object testField3796 = new Integer(3796); + public Object testField3797 = new Integer(3797); + public Object testField3798 = new Integer(3798); + public Object testField3799 = new Integer(3799); + public Object testField3800 = new Integer(3800); + public Object testField3801 = new Integer(3801); + public Object testField3802 = new Integer(3802); + public Object testField3803 = new Integer(3803); + public Object testField3804 = new Integer(3804); + public Object testField3805 = new Integer(3805); + public Object testField3806 = new Integer(3806); + public Object testField3807 = new Integer(3807); + public Object testField3808 = new Integer(3808); + public Object testField3809 = new Integer(3809); + public Object testField3810 = new Integer(3810); + public Object testField3811 = new Integer(3811); + public Object testField3812 = new Integer(3812); + public Object testField3813 = new Integer(3813); + public Object testField3814 = new Integer(3814); + public Object testField3815 = new Integer(3815); + public Object testField3816 = new Integer(3816); + public Object testField3817 = new Integer(3817); + public Object testField3818 = new Integer(3818); + public Object testField3819 = new Integer(3819); + public Object testField3820 = new Integer(3820); + public Object testField3821 = new Integer(3821); + public Object testField3822 = new Integer(3822); + public Object testField3823 = new Integer(3823); + public Object testField3824 = new Integer(3824); + public Object testField3825 = new Integer(3825); + public Object testField3826 = new Integer(3826); + public Object testField3827 = new Integer(3827); + public Object testField3828 = new Integer(3828); + public Object testField3829 = new Integer(3829); + public Object testField3830 = new Integer(3830); + public Object testField3831 = new Integer(3831); + public Object testField3832 = new Integer(3832); + public Object testField3833 = new Integer(3833); + public Object testField3834 = new Integer(3834); + public Object testField3835 = new Integer(3835); + public Object testField3836 = new Integer(3836); + public Object testField3837 = new Integer(3837); + public Object testField3838 = new Integer(3838); + public Object testField3839 = new Integer(3839); + public Object testField3840 = new Integer(3840); + public Object testField3841 = new Integer(3841); + public Object testField3842 = new Integer(3842); + public Object testField3843 = new Integer(3843); + public Object testField3844 = new Integer(3844); + public Object testField3845 = new Integer(3845); + public Object testField3846 = new Integer(3846); + public Object testField3847 = new Integer(3847); + public Object testField3848 = new Integer(3848); + public Object testField3849 = new Integer(3849); + public Object testField3850 = new Integer(3850); + public Object testField3851 = new Integer(3851); + public Object testField3852 = new Integer(3852); + public Object testField3853 = new Integer(3853); + public Object testField3854 = new Integer(3854); + public Object testField3855 = new Integer(3855); + public Object testField3856 = new Integer(3856); + public Object testField3857 = new Integer(3857); + public Object testField3858 = new Integer(3858); + public Object testField3859 = new Integer(3859); + public Object testField3860 = new Integer(3860); + public Object testField3861 = new Integer(3861); + public Object testField3862 = new Integer(3862); + public Object testField3863 = new Integer(3863); + public Object testField3864 = new Integer(3864); + public Object testField3865 = new Integer(3865); + public Object testField3866 = new Integer(3866); + public Object testField3867 = new Integer(3867); + public Object testField3868 = new Integer(3868); + public Object testField3869 = new Integer(3869); + public Object testField3870 = new Integer(3870); + public Object testField3871 = new Integer(3871); + public Object testField3872 = new Integer(3872); + public Object testField3873 = new Integer(3873); + public Object testField3874 = new Integer(3874); + public Object testField3875 = new Integer(3875); + public Object testField3876 = new Integer(3876); + public Object testField3877 = new Integer(3877); + public Object testField3878 = new Integer(3878); + public Object testField3879 = new Integer(3879); + public Object testField3880 = new Integer(3880); + public Object testField3881 = new Integer(3881); + public Object testField3882 = new Integer(3882); + public Object testField3883 = new Integer(3883); + public Object testField3884 = new Integer(3884); + public Object testField3885 = new Integer(3885); + public Object testField3886 = new Integer(3886); + public Object testField3887 = new Integer(3887); + public Object testField3888 = new Integer(3888); + public Object testField3889 = new Integer(3889); + public Object testField3890 = new Integer(3890); + public Object testField3891 = new Integer(3891); + public Object testField3892 = new Integer(3892); + public Object testField3893 = new Integer(3893); + public Object testField3894 = new Integer(3894); + public Object testField3895 = new Integer(3895); + public Object testField3896 = new Integer(3896); + public Object testField3897 = new Integer(3897); + public Object testField3898 = new Integer(3898); + public Object testField3899 = new Integer(3899); + public Object testField3900 = new Integer(3900); + public Object testField3901 = new Integer(3901); + public Object testField3902 = new Integer(3902); + public Object testField3903 = new Integer(3903); + public Object testField3904 = new Integer(3904); + public Object testField3905 = new Integer(3905); + public Object testField3906 = new Integer(3906); + public Object testField3907 = new Integer(3907); + public Object testField3908 = new Integer(3908); + public Object testField3909 = new Integer(3909); + public Object testField3910 = new Integer(3910); + public Object testField3911 = new Integer(3911); + public Object testField3912 = new Integer(3912); + public Object testField3913 = new Integer(3913); + public Object testField3914 = new Integer(3914); + public Object testField3915 = new Integer(3915); + public Object testField3916 = new Integer(3916); + public Object testField3917 = new Integer(3917); + public Object testField3918 = new Integer(3918); + public Object testField3919 = new Integer(3919); + public Object testField3920 = new Integer(3920); + public Object testField3921 = new Integer(3921); + public Object testField3922 = new Integer(3922); + public Object testField3923 = new Integer(3923); + public Object testField3924 = new Integer(3924); + public Object testField3925 = new Integer(3925); + public Object testField3926 = new Integer(3926); + public Object testField3927 = new Integer(3927); + public Object testField3928 = new Integer(3928); + public Object testField3929 = new Integer(3929); + public Object testField3930 = new Integer(3930); + public Object testField3931 = new Integer(3931); + public Object testField3932 = new Integer(3932); + public Object testField3933 = new Integer(3933); + public Object testField3934 = new Integer(3934); + public Object testField3935 = new Integer(3935); + public Object testField3936 = new Integer(3936); + public Object testField3937 = new Integer(3937); + public Object testField3938 = new Integer(3938); + public Object testField3939 = new Integer(3939); + public Object testField3940 = new Integer(3940); + public Object testField3941 = new Integer(3941); + public Object testField3942 = new Integer(3942); + public Object testField3943 = new Integer(3943); + public Object testField3944 = new Integer(3944); + public Object testField3945 = new Integer(3945); + public Object testField3946 = new Integer(3946); + public Object testField3947 = new Integer(3947); + public Object testField3948 = new Integer(3948); + public Object testField3949 = new Integer(3949); + public Object testField3950 = new Integer(3950); + public Object testField3951 = new Integer(3951); + public Object testField3952 = new Integer(3952); + public Object testField3953 = new Integer(3953); + public Object testField3954 = new Integer(3954); + public Object testField3955 = new Integer(3955); + public Object testField3956 = new Integer(3956); + public Object testField3957 = new Integer(3957); + public Object testField3958 = new Integer(3958); + public Object testField3959 = new Integer(3959); + public Object testField3960 = new Integer(3960); + public Object testField3961 = new Integer(3961); + public Object testField3962 = new Integer(3962); + public Object testField3963 = new Integer(3963); + public Object testField3964 = new Integer(3964); + public Object testField3965 = new Integer(3965); + public Object testField3966 = new Integer(3966); + public Object testField3967 = new Integer(3967); + public Object testField3968 = new Integer(3968); + public Object testField3969 = new Integer(3969); + public Object testField3970 = new Integer(3970); + public Object testField3971 = new Integer(3971); + public Object testField3972 = new Integer(3972); + public Object testField3973 = new Integer(3973); + public Object testField3974 = new Integer(3974); + public Object testField3975 = new Integer(3975); + public Object testField3976 = new Integer(3976); + public Object testField3977 = new Integer(3977); + public Object testField3978 = new Integer(3978); + public Object testField3979 = new Integer(3979); + public Object testField3980 = new Integer(3980); + public Object testField3981 = new Integer(3981); + public Object testField3982 = new Integer(3982); + public Object testField3983 = new Integer(3983); + public Object testField3984 = new Integer(3984); + public Object testField3985 = new Integer(3985); + public Object testField3986 = new Integer(3986); + public Object testField3987 = new Integer(3987); + public Object testField3988 = new Integer(3988); + public Object testField3989 = new Integer(3989); + public Object testField3990 = new Integer(3990); + public Object testField3991 = new Integer(3991); + public Object testField3992 = new Integer(3992); + public Object testField3993 = new Integer(3993); + public Object testField3994 = new Integer(3994); + public Object testField3995 = new Integer(3995); + public Object testField3996 = new Integer(3996); + public Object testField3997 = new Integer(3997); + public Object testField3998 = new Integer(3998); + public Object testField3999 = new Integer(3999); +} diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java index f0b327840c..2b30986ab3 100644 --- a/test/623-checker-loop-regressions/src/Main.java +++ b/test/623-checker-loop-regressions/src/Main.java @@ -288,6 +288,28 @@ public class Main { } } + // A strange function that does not inline. + private static void $noinline$foo(boolean x, int n) { + if (n < 0) + throw new Error("oh no"); + if (n > 100) { + $noinline$foo(!x, n - 1); + $noinline$foo(!x, n - 2); + $noinline$foo(!x, n - 3); + $noinline$foo(!x, n - 4); + } + } + + // A loop with environment uses of x (the terminating condition). As exposed by bug + // b/37247891, the loop can be unrolled, but should handle the (unlikely, but clearly + // not impossible) environment uses of the terminating condition in a correct manner. + private static void envUsesInCond() { + boolean x = false; + for (int i = 0; !(x = i >= 1); i++) { + $noinline$foo(true, i); + } + } + public static void main(String[] args) { expectEquals(10, earlyExitFirst(-1)); for (int i = 0; i <= 10; i++) { @@ -369,6 +391,8 @@ public class Main { expectEquals(aa[i], bb.charAt(i)); } + envUsesInCond(); + System.out.println("passed"); } diff --git a/test/646-checker-arraycopy-large-cst-pos/expected.txt b/test/646-checker-arraycopy-large-cst-pos/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/646-checker-arraycopy-large-cst-pos/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/646-checker-arraycopy-large-cst-pos/info.txt b/test/646-checker-arraycopy-large-cst-pos/info.txt new file mode 100644 index 0000000000..9ac21db411 --- /dev/null +++ b/test/646-checker-arraycopy-large-cst-pos/info.txt @@ -0,0 +1,4 @@ +Regression test for an issue with a depleted VIXL scratch register +pool during the emission of a SystemArrayCopy intrinsic with a large +constant destination position, on ARM64, with read barriers +(b/37256530). diff --git a/test/646-checker-arraycopy-large-cst-pos/src/Main.java b/test/646-checker-arraycopy-large-cst-pos/src/Main.java new file mode 100644 index 0000000000..3144fc18e7 --- /dev/null +++ b/test/646-checker-arraycopy-large-cst-pos/src/Main.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +public class Main { + + public static void main(String[] args) { + System.out.println("passed"); + } + + /// CHECK-START-ARM64: void Main.test() disassembly (after) + /// CHECK: InvokeStaticOrDirect method_name:java.lang.System.arraycopy intrinsic:SystemArrayCopy + /// CHECK-NOT: blr + /// CHECK: ReturnVoid + + static void test() { + Object[] src = new Object[1024]; + Object[] dst = new Object[2048]; + // The length of the copied data must not be too large (smaller + // than kSystemArrayCopyThreshold = 128) for the call to + // System.arraycopy to be intrinsified. + System.arraycopy(src, 0, dst, 1024, 64); + } + +} diff --git a/test/646-checker-hadd-alt-byte/expected.txt b/test/646-checker-hadd-alt-byte/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/646-checker-hadd-alt-byte/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/646-checker-hadd-alt-byte/info.txt b/test/646-checker-hadd-alt-byte/info.txt new file mode 100644 index 0000000000..46e73345d8 --- /dev/null +++ b/test/646-checker-hadd-alt-byte/info.txt @@ -0,0 +1 @@ +Functional tests on halving-add SIMD vectorization. diff --git a/test/646-checker-hadd-alt-byte/src/Main.java b/test/646-checker-hadd-alt-byte/src/Main.java new file mode 100644 index 0000000000..d1b33ea0da --- /dev/null +++ b/test/646-checker-hadd-alt-byte/src/Main.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +/** + * Tests for halving-add idiomatic vectorization. + * + * Alternative version expressed with logical shift right + * in the higher precision (has no impact on idiom). + */ +public class Main { + + private static final int N = 256; + private static final int M = N * N + 15; + + static byte[] sB1 = new byte[M]; + static byte[] sB2 = new byte[M]; + static byte[] sBo = new byte[M]; + + /// CHECK-START: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_signed(byte[] b1, byte[] b2, byte[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) ((b1[i] + b2[i]) >>> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned(byte[] b1, byte[] b2, byte[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) (((b1[i] & 0xff) + (b2[i] & 0xff)) >>> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_signed(byte[] b1, byte[] b2, byte[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) ((b1[i] + b2[i] + 1) >>> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_unsigned(byte[] b1, byte[] b2, byte[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) (((b1[i] & 0xff) + (b2[i] & 0xff) + 1) >>> 1); + } + } + + /// CHECK-START: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<I127:i\d+>> IntConstant 127 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<I127>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<I127:i\d+>> IntConstant 127 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I127>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_signed_constant(byte[] b1, byte[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) ((b1[i] + 0x7f) >>> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And:i\d+>> And [<<Get>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I255>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned_constant(byte[] b1, byte[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) (((b1[i] & 0xff) + 0xff) >>> 1); + } + } + + public static void main(String[] args) { + // Initialize cross-values to test all cases, and also + // set up some extra values to exercise the cleanup loop. + int k = 0; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + sB1[k] = (byte) i; + sB2[k] = (byte) j; + k++; + } + } + for (int i = 0; i < 15; i++) { + sB1[k] = (byte) i; + sB2[k] = 100; + k++; + } + expectEquals(k, M); + + // Test halving add idioms. Note that the expected result is computed + // with the arithmetic >> to demonstrate the computed narrower result + // does not depend on the wider >> or >>>. + halving_add_signed(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) ((sB1[i] + sB2[i]) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) (((sB1[i] & 0xff) + (sB2[i] & 0xff)) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_signed(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) ((sB1[i] + sB2[i] + 1) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) (((sB1[i] & 0xff) + (sB2[i] & 0xff) + 1) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_signed_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) ((sB1[i] + 0x7f) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) (((sB1[i] & 0xff) + 0xff) >> 1); + expectEquals(e, sBo[i]); + } + + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/646-checker-hadd-alt-char/expected.txt b/test/646-checker-hadd-alt-char/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/646-checker-hadd-alt-char/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/646-checker-hadd-alt-char/info.txt b/test/646-checker-hadd-alt-char/info.txt new file mode 100644 index 0000000000..46e73345d8 --- /dev/null +++ b/test/646-checker-hadd-alt-char/info.txt @@ -0,0 +1 @@ +Functional tests on halving-add SIMD vectorization. diff --git a/test/646-checker-hadd-alt-char/src/Main.java b/test/646-checker-hadd-alt-char/src/Main.java new file mode 100644 index 0000000000..1ea8d3fe07 --- /dev/null +++ b/test/646-checker-hadd-alt-char/src/Main.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +/** + * Tests for halving-add idiomatic vectorization. + * + * Alternative version expressed with logical shift right + * in the higher precision (has no impact on idiom). + */ +public class Main { + + private static final int N = 64 * 1024; + private static final int M = N + 31; + + static char[] sB1 = new char[M]; + static char[] sB2 = new char[M]; + static char[] sBo = new char[M]; + + /// CHECK-START: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned(char[] b1, char[] b2, char[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) ((b1[i] + b2[i]) >>> 1); + } + } + + /// CHECK-START: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<IMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + // + // Note: HAnd has no impact (already a zero extension). + // + private static void halving_add_also_unsigned(char[] b1, char[] b2, char[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) (((b1[i] & 0xffff) + (b2[i] & 0xffff)) >>> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_unsigned(char[] b1, char[] b2, char[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) ((b1[i] + b2[i] + 1) >>> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<IMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + // + // Note: HAnd has no impact (already a zero extension). + // + private static void rounding_halving_add_also_unsigned(char[] b1, char[] b2, char[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) (((b1[i] & 0xffff) + (b2[i] & 0xffff) + 1) >>> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned_constant(char[] b1, char[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) ((b1[i] + 0xffff) >>> 1); + } + } + + /// CHECK-START: void Main.halving_add_also_unsigned_constant(char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And:i\d+>> And [<<Get>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_also_unsigned_constant(char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + // + // Note: HAnd has no impact (already a zero extension). + // + private static void halving_add_also_unsigned_constant(char[] b1, char[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) (((b1[i] & 0xffff) + 0xffff) >>> 1); + } + } + + public static void main(String[] args) { + // Some interesting values. + char[] interesting = { + (char) 0x0000, + (char) 0x0001, + (char) 0x0002, + (char) 0x1234, + (char) 0x8000, + (char) 0x8001, + (char) 0x7fff, + (char) 0xffff + }; + // Initialize cross-values to test all cases, and also + // set up some extra values to exercise the cleanup loop. + for (int i = 0; i < M; i++) { + sB1[i] = (char) i; + sB2[i] = interesting[i & 7]; + } + + // Test halving add idioms. Note that the expected result is computed + // with the arithmetic >> to demonstrate the computed narrower result + // does not depend on the wider >> or >>>. + halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + sB2[i]) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_also_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + sB2[i]) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + sB2[i] + 1) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_also_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + sB2[i] + 1) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + 0xffff) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_also_unsigned_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + 0xffff) >> 1); + expectEquals(e, sBo[i]); + } + + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/646-checker-hadd-alt-short/expected.txt b/test/646-checker-hadd-alt-short/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/646-checker-hadd-alt-short/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/646-checker-hadd-alt-short/info.txt b/test/646-checker-hadd-alt-short/info.txt new file mode 100644 index 0000000000..46e73345d8 --- /dev/null +++ b/test/646-checker-hadd-alt-short/info.txt @@ -0,0 +1 @@ +Functional tests on halving-add SIMD vectorization. diff --git a/test/646-checker-hadd-alt-short/src/Main.java b/test/646-checker-hadd-alt-short/src/Main.java new file mode 100644 index 0000000000..269e6183b4 --- /dev/null +++ b/test/646-checker-hadd-alt-short/src/Main.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +/** + * Tests for halving-add idiomatic vectorization. + * + * Alternative version expressed with logical shift right + * in the higher precision (has no impact on idiom). + */ +public class Main { + + private static final int N = 64 * 1024; + private static final int M = N + 31; + + static short[] sB1 = new short[M]; + static short[] sB2 = new short[M]; + static short[] sBo = new short[M]; + + /// CHECK-START: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_signed(short[] b1, short[] b2, short[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) ((b1[i] + b2[i]) >>> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff)) >>> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_signed(short[] b1, short[] b2, short[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) ((b1[i] + b2[i] + 1) >>> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff) + 1) >>> 1); + } + } + + /// CHECK-START: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<SMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_signed_constant(short[] b1, short[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) ((b1[i] + 0x7fff) >>> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And:i\d+>> And [<<Get>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned_constant(short[] b1, short[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) (((b1[i] & 0xffff) + 0xffff) >>> 1); + } + } + + public static void main(String[] args) { + // Some interesting values. + short[] interesting = { + (short) 0x0000, + (short) 0x0001, + (short) 0x0002, + (short) 0x1234, + (short) 0x8000, + (short) 0x8001, + (short) 0x7fff, + (short) 0xffff + }; + // Initialize cross-values to test all cases, and also + // set up some extra values to exercise the cleanup loop. + for (int i = 0; i < M; i++) { + sB1[i] = (short) i; + sB2[i] = interesting[i & 7]; + } + + // Test halving add idioms. Note that the expected result is computed + // with the arithmetic >> to demonstrate the computed narrower result + // does not depend on the wider >> or >>>. + halving_add_signed(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + short e = (short) ((sB1[i] + sB2[i]) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + short e = (short) (((sB1[i] & 0xffff) + (sB2[i] & 0xffff)) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_signed(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + short e = (short) ((sB1[i] + sB2[i] + 1) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + short e = (short) (((sB1[i] & 0xffff) + (sB2[i] & 0xffff) + 1) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_signed_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + short e = (short) ((sB1[i] + 0x7fff) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + short e = (short) (((sB1[i] & 0xffff) + 0xffff) >> 1); + expectEquals(e, sBo[i]); + } + + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/646-checker-hadd-byte/expected.txt b/test/646-checker-hadd-byte/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/646-checker-hadd-byte/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/646-checker-hadd-byte/info.txt b/test/646-checker-hadd-byte/info.txt new file mode 100644 index 0000000000..46e73345d8 --- /dev/null +++ b/test/646-checker-hadd-byte/info.txt @@ -0,0 +1 @@ +Functional tests on halving-add SIMD vectorization. diff --git a/test/646-checker-hadd-byte/src/Main.java b/test/646-checker-hadd-byte/src/Main.java new file mode 100644 index 0000000000..7e29a7e60b --- /dev/null +++ b/test/646-checker-hadd-byte/src/Main.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +/** + * Tests for halving-add idiomatic vectorization. + */ +public class Main { + + private static final int N = 256; + private static final int M = N * N + 15; + + static byte[] sB1 = new byte[M]; + static byte[] sB2 = new byte[M]; + static byte[] sBo = new byte[M]; + + /// CHECK-START: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_signed(byte[] b1, byte[] b2, byte[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) ((b1[i] + b2[i]) >> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned(byte[] b1, byte[] b2, byte[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) (((b1[i] & 0xff) + (b2[i] & 0xff)) >> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_signed(byte[] b1, byte[] b2, byte[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) ((b1[i] + b2[i] + 1) >> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_unsigned(byte[] b1, byte[] b2, byte[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) (((b1[i] & 0xff) + (b2[i] & 0xff) + 1) >> 1); + } + } + + /// CHECK-START: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<I127:i\d+>> IntConstant 127 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<I127>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<I127:i\d+>> IntConstant 127 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I127>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_signed_constant(byte[] b1, byte[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) ((b1[i] + 0x7f) >> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And:i\d+>> And [<<Get>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And>>,<<I255>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I255>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned_constant(byte[] b1, byte[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (byte) (((b1[i] & 0xff) + 0xff) >> 1); + } + } + + public static void main(String[] args) { + // Initialize cross-values to test all cases, and also + // set up some extra values to exercise the cleanup loop. + int k = 0; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + sB1[k] = (byte) i; + sB2[k] = (byte) j; + k++; + } + } + for (int i = 0; i < 15; i++) { + sB1[k] = (byte) i; + sB2[k] = 100; + k++; + } + expectEquals(k, M); + + // Test halving add idioms. + halving_add_signed(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) ((sB1[i] + sB2[i]) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) (((sB1[i] & 0xff) + (sB2[i] & 0xff)) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_signed(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) ((sB1[i] + sB2[i] + 1) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) (((sB1[i] & 0xff) + (sB2[i] & 0xff) + 1) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_signed_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) ((sB1[i] + 0x7f) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + byte e = (byte) (((sB1[i] & 0xff) + 0xff) >> 1); + expectEquals(e, sBo[i]); + } + + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/646-checker-hadd-char/expected.txt b/test/646-checker-hadd-char/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/646-checker-hadd-char/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/646-checker-hadd-char/info.txt b/test/646-checker-hadd-char/info.txt new file mode 100644 index 0000000000..46e73345d8 --- /dev/null +++ b/test/646-checker-hadd-char/info.txt @@ -0,0 +1 @@ +Functional tests on halving-add SIMD vectorization. diff --git a/test/646-checker-hadd-char/src/Main.java b/test/646-checker-hadd-char/src/Main.java new file mode 100644 index 0000000000..d24608f5af --- /dev/null +++ b/test/646-checker-hadd-char/src/Main.java @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +/** + * Tests for halving-add idiomatic vectorization. + */ +public class Main { + + private static final int N = 64 * 1024; + private static final int M = N + 31; + + static char[] sB1 = new char[M]; + static char[] sB2 = new char[M]; + static char[] sBo = new char[M]; + + /// CHECK-START: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned(char[] b1, char[] b2, char[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) ((b1[i] + b2[i]) >> 1); + } + } + + /// CHECK-START: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<IMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + // + // Note: HAnd has no impact (already a zero extension). + // + private static void halving_add_also_unsigned(char[] b1, char[] b2, char[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) (((b1[i] & 0xffff) + (b2[i] & 0xffff)) >> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_unsigned(char[] b1, char[] b2, char[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) ((b1[i] + b2[i] + 1) >> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<IMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + // + // Note: HAnd has no impact (already a zero extension). + // + private static void rounding_halving_add_also_unsigned(char[] b1, char[] b2, char[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) (((b1[i] & 0xffff) + (b2[i] & 0xffff) + 1) >> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned_constant(char[] b1, char[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) ((b1[i] + 0xffff) >> 1); + } + } + + /// CHECK-START: void Main.halving_add_also_unsigned_constant(char[], char[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And:i\d+>> And [<<Get>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_also_unsigned_constant(char[], char[]) loop_optimization (after) + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + // + // Note: HAnd has no impact (already a zero extension). + // + private static void halving_add_also_unsigned_constant(char[] b1, char[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (char) (((b1[i] & 0xffff) + 0xffff) >> 1); + } + } + + public static void main(String[] args) { + // Some interesting values. + char[] interesting = { + (char) 0x0000, + (char) 0x0001, + (char) 0x0002, + (char) 0x1234, + (char) 0x8000, + (char) 0x8001, + (char) 0x7fff, + (char) 0xffff + }; + // Initialize cross-values to test all cases, and also + // set up some extra values to exercise the cleanup loop. + for (int i = 0; i < M; i++) { + sB1[i] = (char) i; + sB2[i] = interesting[i & 7]; + } + + // Test halving add idioms. + halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + sB2[i]) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_also_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + sB2[i]) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + sB2[i] + 1) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_also_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + sB2[i] + 1) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + 0xffff) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_also_unsigned_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + char e = (char) ((sB1[i] + 0xffff) >> 1); + expectEquals(e, sBo[i]); + } + + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/646-checker-hadd-short/expected.txt b/test/646-checker-hadd-short/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/646-checker-hadd-short/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/646-checker-hadd-short/info.txt b/test/646-checker-hadd-short/info.txt new file mode 100644 index 0000000000..46e73345d8 --- /dev/null +++ b/test/646-checker-hadd-short/info.txt @@ -0,0 +1 @@ +Functional tests on halving-add SIMD vectorization. diff --git a/test/646-checker-hadd-short/src/Main.java b/test/646-checker-hadd-short/src/Main.java new file mode 100644 index 0000000000..db495f6433 --- /dev/null +++ b/test/646-checker-hadd-short/src/Main.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +/** + * Tests for halving-add idiomatic vectorization. + */ +public class Main { + + private static final int N = 64 * 1024; + private static final int M = N + 31; + + static short[] sB1 = new short[M]; + static short[] sB2 = new short[M]; + static short[] sBo = new short[M]; + + /// CHECK-START: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_signed(short[] b1, short[] b2, short[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) ((b1[i] + b2[i]) >> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff)) >> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_signed(short[] b1, short[] b2, short[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) ((b1[i] + b2[i] + 1) >> 1); + } + } + + /// CHECK-START: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) { + int min_length = Math.min(bo.length, Math.min(b1.length, b2.length)); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff) + 1) >> 1); + } + } + + /// CHECK-START: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<SMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_signed_constant(short[] b1, short[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) ((b1[i] + 0x7fff) >> 1); + } + } + + /// CHECK-START: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (before) + /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<And:i\d+>> And [<<Get>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<And>>,<<UMAX>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after) + /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none + /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none + private static void halving_add_unsigned_constant(short[] b1, short[] bo) { + int min_length = Math.min(bo.length, b1.length); + for (int i = 0; i < min_length; i++) { + bo[i] = (short) (((b1[i] & 0xffff) + 0xffff) >> 1); + } + } + + public static void main(String[] args) { + // Some interesting values. + short[] interesting = { + (short) 0x0000, + (short) 0x0001, + (short) 0x0002, + (short) 0x1234, + (short) 0x8000, + (short) 0x8001, + (short) 0x7fff, + (short) 0xffff + }; + // Initialize cross-values to test all cases, and also + // set up some extra values to exercise the cleanup loop. + for (int i = 0; i < M; i++) { + sB1[i] = (short) i; + sB2[i] = interesting[i & 7]; + } + + // Test halving add idioms. + halving_add_signed(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + short e = (short) ((sB1[i] + sB2[i]) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + short e = (short) (((sB1[i] & 0xffff) + (sB2[i] & 0xffff)) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_signed(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + short e = (short) ((sB1[i] + sB2[i] + 1) >> 1); + expectEquals(e, sBo[i]); + } + rounding_halving_add_unsigned(sB1, sB2, sBo); + for (int i = 0; i < M; i++) { + short e = (short) (((sB1[i] & 0xffff) + (sB2[i] & 0xffff) + 1) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_signed_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + short e = (short) ((sB1[i] + 0x7fff) >> 1); + expectEquals(e, sBo[i]); + } + halving_add_unsigned_constant(sB1, sBo); + for (int i = 0; i < M; i++) { + short e = (short) (((sB1[i] & 0xffff) + 0xffff) >> 1); + expectEquals(e, sBo[i]); + } + + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/646-checker-long-const-to-int/expected.txt b/test/646-checker-long-const-to-int/expected.txt new file mode 100644 index 0000000000..9abd696f97 --- /dev/null +++ b/test/646-checker-long-const-to-int/expected.txt @@ -0,0 +1 @@ +305419896 diff --git a/test/646-checker-long-const-to-int/info.txt b/test/646-checker-long-const-to-int/info.txt new file mode 100644 index 0000000000..3f560c319a --- /dev/null +++ b/test/646-checker-long-const-to-int/info.txt @@ -0,0 +1 @@ +Regression test for bogus checks that a constant input of long-to-int conversion fits into int. diff --git a/test/646-checker-long-const-to-int/src/Main.java b/test/646-checker-long-const-to-int/src/Main.java new file mode 100644 index 0000000000..85738dc8c3 --- /dev/null +++ b/test/646-checker-long-const-to-int/src/Main.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +public class Main { + + public static void main(String[] args) { + System.out.println(test()); + } + + public static long testField = 0; + public static long longField0 = 0; + public static long longField1 = 0; + public static long longField2 = 0; + public static long longField3 = 0; + public static long longField4 = 0; + public static long longField5 = 0; + public static long longField6 = 0; + public static long longField7 = 0; + + /// CHECK-START-ARM: int Main.test() register (after) + /// CHECK: TypeConversion locations:[#-8690466096623102344]->{{.*}} + public static int test() { + // To avoid constant folding TypeConversion(const), hide the constant in a field. + // We do not run constant folding after load-store-elimination. + testField = 0x8765432112345678L; + long value = testField; + // Now, the `value` is in a register because of the store but we need + // a constant location to trigger the bug, so load a bunch of other fields. + long l0 = longField0; + long l1 = longField1; + long l2 = longField2; + long l3 = longField3; + long l4 = longField4; + long l5 = longField5; + long l6 = longField6; + long l7 = longField7; + if (l0 != 0 || l1 != 0 || l2 != 0 || l3 != 0 || l4 != 0 || l5 != 0 || l6 != 0 || l7 != 0) { + throw new Error(); + } + // Do the conversion from constant location. + return (int)value; + } +} diff --git a/test/902-hello-transformation/src/Main.java b/test/902-hello-transformation/src/Main.java index ed8a5007c8..af49cb4eaa 100644 --- a/test/902-hello-transformation/src/Main.java +++ b/test/902-hello-transformation/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,53 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test902.run(); } - - public static void doTest(Transform t) { - t.sayHi(); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - t.sayHi(); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/902-hello-transformation/src/Transform.java b/test/902-hello-transformation/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/902-hello-transformation/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/902-hello-transformation/src/art/Redefinition.java b/test/902-hello-transformation/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/902-hello-transformation/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/902-hello-transformation/src/art/Test902.java b/test/902-hello-transformation/src/art/Test902.java new file mode 100644 index 0000000000..e95558f7c7 --- /dev/null +++ b/test/902-hello-transformation/src/art/Test902.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +public class Test902 { + + static class Transform { + public void sayHi() { + // Use lower 'h' to make sure the string will have a different string id + // than the transformation (the transformation code is the same except + // the actual printed String, which was making the test inacurately passing + // in JIT mode when loading the string from the dex cache, as the string ids + // of the two different strings were the same). + // We know the string ids will be different because lexicographically: + // "Goodbye" < "LTransform;" < "hello". + System.out.println("hello"); + } + } + + /** + * base64 encoded class/dex file for + * class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTAyLmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5MDIkVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTAyACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAJQABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAnAAgAKAACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCpghS3AAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTAyJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkwMjsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTAyLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAlAAcOACcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + t.sayHi(); + } +} diff --git a/test/904-object-allocation/expected.txt b/test/904-object-allocation/expected.txt index 371d2b7593..fdec470529 100644 --- a/test/904-object-allocation/expected.txt +++ b/test/904-object-allocation/expected.txt @@ -1,8 +1,8 @@ -ObjectAllocated type java.lang.Object/java.lang.Object size 8 -ObjectAllocated type java.lang.Integer/java.lang.Integer size 16 -ObjectAllocated type java.lang.Short/java.lang.Short size 16 +[] +[ObjectAllocated type java.lang.Object/java.lang.Object size 8, ObjectAllocated type java.lang.Integer/java.lang.Integer size 16, ObjectAllocated type java.lang.Short/java.lang.Short size 16] Tracking on same thread -ObjectAllocated type java.lang.Double/java.lang.Double size 16 +[ObjectAllocated type java.lang.Double/java.lang.Double size 16] Tracking on same thread, not disabling tracking -ObjectAllocated type java.lang.Double/java.lang.Double size 16 +[ObjectAllocated type java.lang.Double/java.lang.Double size 16] Tracking on different thread +[] diff --git a/test/904-object-allocation/src/art/Test904.java b/test/904-object-allocation/src/art/Test904.java index 31e0c8c1ae..70a4b9847f 100644 --- a/test/904-object-allocation/src/art/Test904.java +++ b/test/904-object-allocation/src/art/Test904.java @@ -17,6 +17,7 @@ package art; import java.util.ArrayList; +import java.util.Arrays; public class Test904 { public static void run() throws Exception { @@ -48,6 +49,8 @@ public class Test904 { // Enable actual logging callback. setupObjectAllocCallback(true); + System.out.println(Arrays.toString(getTrackingEventMessages())); + enableAllocationTracking(null, true); l.add(new Object()); @@ -65,16 +68,19 @@ public class Test904 { l.add(new Byte((byte)0)); + System.out.println(Arrays.toString(getTrackingEventMessages())); System.out.println("Tracking on same thread"); testThread(l, true, true); l.add(new Byte((byte)0)); + System.out.println(Arrays.toString(getTrackingEventMessages())); System.out.println("Tracking on same thread, not disabling tracking"); testThread(l, true, false); + System.out.println(Arrays.toString(getTrackingEventMessages())); System.out.println("Tracking on different thread"); testThread(l, false, true); @@ -84,6 +90,9 @@ public class Test904 { // Disable actual logging callback and re-enable tracking, so we can keep the event enabled and // check that shutdown works correctly. setupObjectAllocCallback(false); + + System.out.println(Arrays.toString(getTrackingEventMessages())); + enableAllocationTracking(null, true); } @@ -142,4 +151,5 @@ public class Test904 { private static native void setupObjectAllocCallback(boolean enable); private static native void enableAllocationTracking(Thread thread, boolean enable); + private static native String[] getTrackingEventMessages(); } diff --git a/test/904-object-allocation/tracking.cc b/test/904-object-allocation/tracking.cc index 8de350b06c..20b53281a2 100644 --- a/test/904-object-allocation/tracking.cc +++ b/test/904-object-allocation/tracking.cc @@ -15,11 +15,13 @@ */ #include <iostream> +#include <mutex> #include <pthread.h> #include <stdio.h> #include <vector> #include "android-base/logging.h" +#include "android-base/stringprintf.h" #include "jni.h" #include "jvmti.h" #include "scoped_local_ref.h" @@ -41,6 +43,9 @@ static std::string GetClassName(JNIEnv* jni_env, jclass cls) { return utf_chars.c_str(); } +static std::mutex gEventsMutex; +static std::vector<std::string> gEvents; + static void JNICALL ObjectAllocated(jvmtiEnv* ti_env ATTRIBUTE_UNUSED, JNIEnv* jni_env, jthread thread ATTRIBUTE_UNUSED, @@ -51,10 +56,11 @@ static void JNICALL ObjectAllocated(jvmtiEnv* ti_env ATTRIBUTE_UNUSED, ScopedLocalRef<jclass> object_klass2(jni_env, jni_env->GetObjectClass(object)); std::string object_klass_descriptor2 = GetClassName(jni_env, object_klass2.get()); - printf("ObjectAllocated type %s/%s size %zu\n", - object_klass_descriptor.c_str(), - object_klass_descriptor2.c_str(), - static_cast<size_t>(size)); + std::lock_guard<std::mutex> guard(gEventsMutex); + gEvents.push_back(android::base::StringPrintf("ObjectAllocated type %s/%s size %zu", + object_klass_descriptor.c_str(), + object_klass_descriptor2.c_str(), + static_cast<size_t>(size))); } extern "C" JNIEXPORT void JNICALL Java_art_Test904_setupObjectAllocCallback( @@ -76,5 +82,18 @@ extern "C" JNIEXPORT void JNICALL Java_art_Test904_enableAllocationTracking( JvmtiErrorToException(env, jvmti_env, ret); } +extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test904_getTrackingEventMessages( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) { + std::lock_guard<std::mutex> guard(gEventsMutex); + jobjectArray ret = CreateObjectArray(env, + static_cast<jint>(gEvents.size()), + "java/lang/String", + [&](jint i) { + return env->NewStringUTF(gEvents[i].c_str()); + }); + gEvents.clear(); + return ret; +} + } // namespace Test904ObjectAllocation } // namespace art diff --git a/test/910-methods/expected.txt b/test/910-methods/expected.txt index 8e6b6e76d9..c14c6c49e1 100644 --- a/test/910-methods/expected.txt +++ b/test/910-methods/expected.txt @@ -32,19 +32,19 @@ Is synthetic: false interface java.util.List 1025 Max locals: 0 -Argument size: 0 -Location start: 0 -Location end: 0 +Argument size: 2 +Location start: -1 +Location end: -1 Is native: false Is obsolete: false Is synthetic: false [run, ()V, null] -class $Proxy0 +class $Proxy20 17 Max locals: 0 -Argument size: 0 -Location start: 0 -Location end: 0 +Argument size: 1 +Location start: -1 +Location end: -1 Is native: false Is obsolete: false Is synthetic: false diff --git a/test/910-methods/src/art/Test910.java b/test/910-methods/src/art/Test910.java index b3490e9518..aa6d13af9a 100644 --- a/test/910-methods/src/art/Test910.java +++ b/test/910-methods/src/art/Test910.java @@ -39,17 +39,6 @@ public class Test910 { testMethod(findSyntheticMethod(), NestedSynthetic.class, false); } - private static Class<?> proxyClass = null; - - private static Class<?> getProxyClass() throws Exception { - if (proxyClass != null) { - return proxyClass; - } - - proxyClass = Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Runnable.class }); - return proxyClass; - } - private static void testMethod(String className, String methodName, Class<?>... types) throws Exception { Class<?> base = Class.forName(className); @@ -145,4 +134,62 @@ public class Test910 { private static native boolean isMethodNative(Method m); private static native boolean isMethodObsolete(Method m); private static native boolean isMethodSynthetic(Method m); + + // We need this machinery for a consistent proxy name. Names of proxy classes include a + // unique number (derived by counting). This means that a simple call to getProxyClass + // depends on the test environment. + // + // To work around this, we assume that at most twenty proxies have been created before + // the test is run, and canonicalize on "$Proxy20". We add infrastructure to create + // as many proxy classes but cycling through subsets of the test-provided interfaces + // I0...I4. + // + // + // (This is made under the judgment that we do not want to have proxy-specific behavior + // for testMethod.) + + private static Class<?> proxyClass = null; + + private static Class<?> getProxyClass() throws Exception { + if (proxyClass != null) { + return proxyClass; + } + + for (int i = 1; i <= 21; i++) { + proxyClass = createProxyClass(i); + String name = proxyClass.getName(); + if (name.equals("$Proxy20")) { + return proxyClass; + } + } + return proxyClass; + } + + private static Class<?> createProxyClass(int i) throws Exception { + int count = Integer.bitCount(i); + Class<?>[] input = new Class<?>[count + 1]; + input[0] = Runnable.class; + int inputIndex = 1; + int bitIndex = 0; + while (i != 0) { + if ((i & 1) != 0) { + input[inputIndex++] = Class.forName("art.Test910$I" + bitIndex); + } + i >>>= 1; + bitIndex++; + } + return Proxy.getProxyClass(Test910.class.getClassLoader(), input); + } + + // Need this for the proxy naming. + public static interface I0 { + } + public static interface I1 { + } + public static interface I2 { + } + public static interface I3 { + } + public static interface I4 { + } } diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc index 2636367548..869eacd82c 100644 --- a/test/912-classes/classes.cc +++ b/test/912-classes/classes.cc @@ -16,50 +16,39 @@ #include <stdio.h> +#include <mutex> +#include <vector> + #include "android-base/macros.h" +#include "android-base/stringprintf.h" -#include "class_linker.h" #include "jni.h" -#include "mirror/class_loader.h" #include "jvmti.h" -#include "runtime.h" -#include "scoped_local_ref.h" -#include "scoped_utf_chars.h" -#include "scoped_thread_state_change-inl.h" -#include "thread-inl.h" // Test infrastructure #include "jni_helper.h" #include "jvmti_helper.h" +#include "scoped_local_ref.h" +#include "scoped_utf_chars.h" #include "test_env.h" namespace art { namespace Test912Classes { -extern "C" JNIEXPORT jboolean JNICALL Java_Main_isModifiableClass( - JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { +extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isModifiableClass( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jboolean res = JNI_FALSE; jvmtiError result = jvmti_env->IsModifiableClass(klass, &res); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running IsModifiableClass: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - return JNI_FALSE; - } + JvmtiErrorToException(env, jvmti_env, result); return res; } -extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassSignature( +extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassSignature( JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { char* sig; char* gen; jvmtiError result = jvmti_env->GetClassSignature(klass, &sig, &gen); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running GetClassSignature: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); + if (JvmtiErrorToException(env, jvmti_env, result)) { return nullptr; } @@ -83,57 +72,36 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassSignature( return ret; } -extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterface( - JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { +extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isInterface( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jboolean is_interface = JNI_FALSE; jvmtiError result = jvmti_env->IsInterface(klass, &is_interface); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running IsInterface: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - return JNI_FALSE; - } + JvmtiErrorToException(env, jvmti_env, result); return is_interface; } -extern "C" JNIEXPORT jboolean JNICALL Java_Main_isArrayClass( - JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { +extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isArrayClass( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jboolean is_array_class = JNI_FALSE; jvmtiError result = jvmti_env->IsArrayClass(klass, &is_array_class); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running IsArrayClass: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - return JNI_FALSE; - } + JvmtiErrorToException(env, jvmti_env, result); return is_array_class; } -extern "C" JNIEXPORT jint JNICALL Java_Main_getClassModifiers( - JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { +extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassModifiers( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jint mod; jvmtiError result = jvmti_env->GetClassModifiers(klass, &mod); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running GetClassModifiers: %s\n", err); - return JNI_FALSE; - } + JvmtiErrorToException(env, jvmti_env, result); return mod; } -extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassFields( +extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassFields( JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jint count = 0; jfieldID* fields = nullptr; jvmtiError result = jvmti_env->GetClassFields(klass, &count, &fields); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running GetClassFields: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); + if (JvmtiErrorToException(env, jvmti_env, result)) { return nullptr; } @@ -153,15 +121,12 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassFields( return ret; } -extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassMethods( +extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassMethods( JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jint count = 0; jmethodID* methods = nullptr; jvmtiError result = jvmti_env->GetClassMethods(klass, &count, &methods); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running GetClassMethods: %s\n", err); + if (JvmtiErrorToException(env, jvmti_env, result)) { return nullptr; } @@ -181,15 +146,12 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassMethods( return ret; } -extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getImplementedInterfaces( +extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getImplementedInterfaces( JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jint count = 0; jclass* classes = nullptr; jvmtiError result = jvmti_env->GetImplementedInterfaces(klass, &count, &classes); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running GetImplementedInterfaces: %s\n", err); + if (JvmtiErrorToException(env, jvmti_env, result)) { return nullptr; } @@ -203,35 +165,23 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getImplementedInterfaces( return ret; } -extern "C" JNIEXPORT jint JNICALL Java_Main_getClassStatus( - JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { +extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassStatus( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jint status; jvmtiError result = jvmti_env->GetClassStatus(klass, &status); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running GetClassStatus: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - return JNI_FALSE; - } + JvmtiErrorToException(env, jvmti_env, result); return status; } -extern "C" JNIEXPORT jobject JNICALL Java_Main_getClassLoader( - JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { +extern "C" JNIEXPORT jobject JNICALL Java_art_Test912_getClassLoader( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jobject classloader; jvmtiError result = jvmti_env->GetClassLoader(klass, &classloader); - if (result != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(result, &err); - printf("Failure running GetClassLoader: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - return nullptr; - } + JvmtiErrorToException(env, jvmti_env, result); return classloader; } -extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassLoaderClasses( +extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoaderClasses( JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jobject jclassloader) { jint count = 0; jclass* classes = nullptr; @@ -250,7 +200,7 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassLoaderClasses( return ret; } -extern "C" JNIEXPORT jintArray JNICALL Java_Main_getClassVersion( +extern "C" JNIEXPORT jintArray JNICALL Java_art_Test912_getClassVersion( JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { jint major, minor; jvmtiError result = jvmti_env->GetClassVersionNumbers(klass, &minor, &major); @@ -325,6 +275,22 @@ static void EnableEvents(JNIEnv* env, JvmtiErrorToException(env, jvmti_env, ret); } +static std::mutex gEventsMutex; +static std::vector<std::string> gEvents; + +extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoadMessages( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) { + std::lock_guard<std::mutex> guard(gEventsMutex); + jobjectArray ret = CreateObjectArray(env, + static_cast<jint>(gEvents.size()), + "java/lang/String", + [&](jint i) { + return env->NewStringUTF(gEvents[i].c_str()); + }); + gEvents.clear(); + return ret; +} + class ClassLoadPreparePrinter { public: static void JNICALL ClassLoadCallback(jvmtiEnv* jenv, @@ -339,7 +305,14 @@ class ClassLoadPreparePrinter { if (thread_name == "") { return; } - printf("Load: %s on %s\n", name.c_str(), thread_name.c_str()); + if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) { + return; + } + + std::lock_guard<std::mutex> guard(gEventsMutex); + gEvents.push_back(android::base::StringPrintf("Load: %s on %s", + name.c_str(), + thread_name.c_str())); } static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv, @@ -354,14 +327,18 @@ class ClassLoadPreparePrinter { if (thread_name == "") { return; } - std::string cur_thread_name = GetThreadName(Thread::Current()); - printf("Prepare: %s on %s (cur=%s)\n", - name.c_str(), - thread_name.c_str(), - cur_thread_name.c_str()); + if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) { + return; + } + std::string cur_thread_name = GetThreadName(jenv, jni_env, nullptr); + + std::lock_guard<std::mutex> guard(gEventsMutex); + gEvents.push_back(android::base::StringPrintf("Prepare: %s on %s (cur=%s)", + name.c_str(), + thread_name.c_str(), + cur_thread_name.c_str())); } - private: static std::string GetThreadName(jvmtiEnv* jenv, JNIEnv* jni_env, jthread thread) { jvmtiThreadInfo info; jvmtiError result = jenv->GetThreadInfo(thread, &info); @@ -382,60 +359,28 @@ class ClassLoadPreparePrinter { return tmp; } - static std::string GetThreadName(Thread* thread) { - std::string tmp; - thread->GetThreadName(tmp); - return tmp; - } + static std::string thread_name_filter_; }; +std::string ClassLoadPreparePrinter::thread_name_filter_; + +extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPreparePrintEvents( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean enable, jthread thread) { + if (thread != nullptr) { + ClassLoadPreparePrinter::thread_name_filter_ = + ClassLoadPreparePrinter::GetThreadName(jvmti_env, env, thread); + } else { + ClassLoadPreparePrinter::thread_name_filter_ = ""; + } -extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadPreparePrintEvents( - JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean enable) { EnableEvents(env, enable, ClassLoadPreparePrinter::ClassLoadCallback, ClassLoadPreparePrinter::ClassPrepareCallback); } -struct ClassLoadSeen { - static void JNICALL ClassLoadSeenCallback(jvmtiEnv* jenv ATTRIBUTE_UNUSED, - JNIEnv* jni_env ATTRIBUTE_UNUSED, - jthread thread ATTRIBUTE_UNUSED, - jclass klass ATTRIBUTE_UNUSED) { - saw_event = true; - } - - static bool saw_event; -}; -bool ClassLoadSeen::saw_event = false; - -extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadSeenEvents( - JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) { - EnableEvents(env, b, ClassLoadSeen::ClassLoadSeenCallback, nullptr); -} - -extern "C" JNIEXPORT jboolean JNICALL Java_Main_hadLoadEvent( - JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED) { - return ClassLoadSeen::saw_event ? JNI_TRUE : JNI_FALSE; -} - -extern "C" JNIEXPORT jboolean JNICALL Java_Main_isLoadedClass( - JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring class_name) { - ScopedUtfChars name(env, class_name); - ScopedObjectAccess soa(Thread::Current()); - Runtime* current = Runtime::Current(); - ClassLinker* class_linker = current->GetClassLinker(); - bool found = - class_linker->LookupClass( - soa.Self(), - name.c_str(), - soa.Decode<mirror::ClassLoader>(current->GetSystemClassLoader())) != nullptr; - return found ? JNI_TRUE : JNI_FALSE; -} - class ClassLoadPrepareEquality { public: - static constexpr const char* kClassName = "LMain$ClassE;"; + static constexpr const char* kClassName = "Lart/Test912$ClassE;"; static constexpr const char* kStorageFieldName = "STATIC"; static constexpr const char* kStorageFieldSig = "Ljava/lang/Object;"; static constexpr const char* kStorageWeakFieldName = "WEAK"; @@ -553,13 +498,13 @@ jobject ClassLoadPrepareEquality::local_stored_class_ = nullptr; bool ClassLoadPrepareEquality::found_ = false; bool ClassLoadPrepareEquality::compared_ = false; -extern "C" JNIEXPORT void JNICALL Java_Main_setEqualityEventStorageClass( +extern "C" JNIEXPORT void JNICALL Java_art_Test912_setEqualityEventStorageClass( JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { ClassLoadPrepareEquality::storage_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(klass)); } -extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadPrepareEqualityEvents( +extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPrepareEqualityEvents( JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) { EnableEvents(env, b, diff --git a/test/912-classes/classes_art.cc b/test/912-classes/classes_art.cc new file mode 100644 index 0000000000..de2e456a53 --- /dev/null +++ b/test/912-classes/classes_art.cc @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +#include <stdio.h> + +#include <mutex> +#include <vector> + +#include "android-base/macros.h" +#include "android-base/stringprintf.h" + +#include "jni.h" +#include "jvmti.h" + +// Test infrastructure +#include "jni_helper.h" +#include "jvmti_helper.h" +#include "scoped_local_ref.h" +#include "scoped_utf_chars.h" +#include "test_env.h" + +namespace art { +namespace Test912ArtClasses { + +static void EnableEvents(JNIEnv* env, + jboolean enable, + decltype(jvmtiEventCallbacks().ClassLoad) class_load, + decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) { + if (enable == JNI_FALSE) { + jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, + JVMTI_EVENT_CLASS_LOAD, + nullptr); + if (JvmtiErrorToException(env, jvmti_env, ret)) { + return; + } + ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, + JVMTI_EVENT_CLASS_PREPARE, + nullptr); + JvmtiErrorToException(env, jvmti_env, ret); + return; + } + + jvmtiEventCallbacks callbacks; + memset(&callbacks, 0, sizeof(jvmtiEventCallbacks)); + callbacks.ClassLoad = class_load; + callbacks.ClassPrepare = class_prepare; + jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); + if (JvmtiErrorToException(env, jvmti_env, ret)) { + return; + } + + ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, + JVMTI_EVENT_CLASS_LOAD, + nullptr); + if (JvmtiErrorToException(env, jvmti_env, ret)) { + return; + } + ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, + JVMTI_EVENT_CLASS_PREPARE, + nullptr); + JvmtiErrorToException(env, jvmti_env, ret); +} + +struct ClassLoadSeen { + static void JNICALL ClassLoadSeenCallback(jvmtiEnv* jenv ATTRIBUTE_UNUSED, + JNIEnv* jni_env ATTRIBUTE_UNUSED, + jthread thread ATTRIBUTE_UNUSED, + jclass klass ATTRIBUTE_UNUSED) { + saw_event = true; + } + + static bool saw_event; +}; +bool ClassLoadSeen::saw_event = false; + +extern "C" JNIEXPORT void JNICALL Java_art_Test912Art_enableClassLoadSeenEvents( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) { + EnableEvents(env, b, ClassLoadSeen::ClassLoadSeenCallback, nullptr); +} + +extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912Art_hadLoadEvent( + JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED) { + return ClassLoadSeen::saw_event ? JNI_TRUE : JNI_FALSE; +} + +extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912Art_isLoadedClass( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring class_name) { + ScopedUtfChars name(env, class_name); + + jint class_count; + jclass* classes; + jvmtiError res = jvmti_env->GetLoadedClasses(&class_count, &classes); + if (JvmtiErrorToException(env, jvmti_env, res)) { + return JNI_FALSE; + } + + bool found = false; + for (jint i = 0; !found && i < class_count; ++i) { + char* sig; + jvmtiError res2 = jvmti_env->GetClassSignature(classes[i], &sig, nullptr); + if (JvmtiErrorToException(env, jvmti_env, res2)) { + return JNI_FALSE; + } + + found = strcmp(name.c_str(), sig) == 0; + + CheckJvmtiError(jvmti_env, jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig))); + } + + CheckJvmtiError(jvmti_env, jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes))); + + return found; +} + +// We use the implementations from runtime_state.cc. + +extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env, + jclass, + jclass cls, + jstring method_name); +extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJit(JNIEnv*, jclass); + +extern "C" JNIEXPORT void JNICALL Java_art_Test912Art_ensureJitCompiled( + JNIEnv* env, jclass klass, jclass test_class, jstring name) { + Java_Main_ensureJitCompiled(env, klass, test_class, name); +} + +extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912Art_hasJit(JNIEnv* env, jclass klass) { + return Java_Main_hasJit(env, klass); +} + +} // namespace Test912ArtClasses +} // namespace art diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt index 0f2920a0c2..9dcc5f9c90 100644 --- a/test/912-classes/expected.txt +++ b/test/912-classes/expected.txt @@ -6,14 +6,14 @@ 11 [Ljava/util/List;, <E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;>;] 601 -[L$Proxy0;, null] +[L$Proxy20;, null] 11 [I, null] 411 [[D, null] 411 int interface=false array=false modifiable=false -$Proxy0 interface=false array=false modifiable=false +$Proxy20 interface=false array=false modifiable=false java.lang.Runnable interface=true array=false modifiable=false java.lang.String interface=false array=false modifiable=false java.util.ArrayList interface=false array=false modifiable=true @@ -29,70 +29,65 @@ java.util.ArrayList interface=false array=false modifiable=true int 100000 class [Ljava.lang.String; 10000 class java.lang.Object 111 -class Main$TestForNonInit 11 -class Main$TestForInitFail 1011 +class art.Test912$TestForNonInit 11 +class art.Test912$TestForInitFail 1011 int [] class [Ljava.lang.String; [] class java.lang.Object [] -interface Main$InfA [] -interface Main$InfB [interface Main$InfA] -interface Main$InfC [interface Main$InfB] -class Main$ClassA [interface Main$InfA] -class Main$ClassB [interface Main$InfB] -class Main$ClassC [interface Main$InfA, interface Main$InfC] +interface art.Test912$InfA [] +interface art.Test912$InfB [interface art.Test912$InfA] +interface art.Test912$InfC [interface art.Test912$InfB] +class art.Test912$ClassA [interface art.Test912$InfA] +class art.Test912$ClassB [interface art.Test912$InfB] +class art.Test912$ClassC [interface art.Test912$InfA, interface art.Test912$InfC] class java.lang.String null class [Ljava.lang.String; null -interface Main$InfA dalvik.system.PathClassLoader -class $Proxy0 dalvik.system.PathClassLoader +interface art.Test912$InfA dalvik.system.PathClassLoader +class $Proxy20 dalvik.system.PathClassLoader -boot <- src <- src-ex (A,B) -912-classes-ex.jar+ -> 912-classes.jar+ -> +boot <- (B) <- (A,C) [class A, class B, class java.lang.Object] -912-classes.jar+ -> [class B, class java.lang.Object] -boot <- src (B) <- src-ex (A, List) -912-classes-ex.jar+ -> 912-classes.jar+ -> +boot <- (B) <- (A, List) [class A, class java.lang.Object, interface java.util.List] -912-classes.jar+ -> [class B, class java.lang.Object] -boot <- src+src-ex (A,B) -912-classes.jar+ -> +boot <- 1+2 (A,B) [class A, class B, class java.lang.Object] [37, 0] B, false -Load: LB; on main -Prepare: LB; on main (cur=main) +Load: LB; on ClassEvents +Prepare: LB; on ClassEvents (cur=ClassEvents) B, true -Load: LB; on main -Prepare: LB; on main (cur=main) +Load: LB; on ClassEvents +Prepare: LB; on ClassEvents (cur=ClassEvents) C, false -Load: LA; on main -Prepare: LA; on main (cur=main) -Load: LC; on main -Prepare: LC; on main (cur=main) +Load: LA; on ClassEvents +Prepare: LA; on ClassEvents (cur=ClassEvents) +Load: LC; on ClassEvents +Prepare: LC; on ClassEvents (cur=ClassEvents) A, false C, true -Load: LA; on main -Prepare: LA; on main (cur=main) -Load: LC; on main -Prepare: LC; on main (cur=main) +Load: LA; on ClassEvents +Prepare: LA; on ClassEvents (cur=ClassEvents) +Load: LC; on ClassEvents +Prepare: LC; on ClassEvents (cur=ClassEvents) A, true A, true -Load: LA; on main -Prepare: LA; on main (cur=main) +Load: LA; on ClassEvents +Prepare: LA; on ClassEvents (cur=ClassEvents) C, true -Load: LC; on main -Prepare: LC; on main (cur=main) +Load: LC; on ClassEvents +Prepare: LC; on ClassEvents (cur=ClassEvents) C, true Load: LA; on TestRunner Prepare: LA; on TestRunner (cur=TestRunner) Load: LC; on TestRunner Prepare: LC; on TestRunner (cur=TestRunner) -Load: L$Proxy1; on main -Prepare: L$Proxy1; on main (cur=main) -Load: [LMain; on main -Prepare: [LMain; on main (cur=main) +Load: L$Proxy21; on ClassEvents +Prepare: L$Proxy21; on ClassEvents (cur=ClassEvents) +Load: [Lart/Test912; on ClassEvents +Prepare: [Lart/Test912; on ClassEvents (cur=ClassEvents) diff --git a/test/912-classes/src/B.java b/test/912-classes/src/B.java deleted file mode 100644 index 52ce4dd58e..0000000000 --- a/test/912-classes/src/B.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -public class B { -} diff --git a/test/912-classes/src/Main.java b/test/912-classes/src/Main.java index 6c8858ab65..395cf6fb98 100644 --- a/test/912-classes/src/Main.java +++ b/test/912-classes/src/Main.java @@ -14,452 +14,9 @@ * limitations under the License. */ -import java.lang.ref.Reference; -import java.lang.reflect.Constructor; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; - public class Main { public static void main(String[] args) throws Exception { - art.Main.bindAgentJNIForClass(Main.class); - doTest(); - } - - public static void doTest() throws Exception { - testClass("java.lang.Object"); - testClass("java.lang.String"); - testClass("java.lang.Math"); - testClass("java.util.List"); - - testClass(getProxyClass()); - - testClass(int.class); - testClass(double[].class); - - testClassType(int.class); - testClassType(getProxyClass()); - testClassType(Runnable.class); - testClassType(String.class); - testClassType(ArrayList.class); - - testClassType(int[].class); - testClassType(Runnable[].class); - testClassType(String[].class); - - testClassFields(Integer.class); - testClassFields(int.class); - testClassFields(String[].class); - - testClassMethods(Integer.class); - testClassMethods(int.class); - testClassMethods(String[].class); - - testClassStatus(int.class); - testClassStatus(String[].class); - testClassStatus(Object.class); - testClassStatus(TestForNonInit.class); - try { - System.out.println(TestForInitFail.dummy); - } catch (ExceptionInInitializerError e) { - } - testClassStatus(TestForInitFail.class); - - testInterfaces(int.class); - testInterfaces(String[].class); - testInterfaces(Object.class); - testInterfaces(InfA.class); - testInterfaces(InfB.class); - testInterfaces(InfC.class); - testInterfaces(ClassA.class); - testInterfaces(ClassB.class); - testInterfaces(ClassC.class); - - testClassLoader(String.class); - testClassLoader(String[].class); - testClassLoader(InfA.class); - testClassLoader(getProxyClass()); - - testClassLoaderClasses(); - - System.out.println(); - - testClassVersion(); - - System.out.println(); - - testClassEvents(); - } - - private static Class<?> proxyClass = null; - - private static Class<?> getProxyClass() throws Exception { - if (proxyClass != null) { - return proxyClass; - } - - proxyClass = Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Runnable.class }); - return proxyClass; - } - - private static void testClass(String className) throws Exception { - Class<?> base = Class.forName(className); - testClass(base); - } - - private static void testClass(Class<?> base) throws Exception { - String[] result = getClassSignature(base); - System.out.println(Arrays.toString(result)); - int mod = getClassModifiers(base); - if (mod != base.getModifiers()) { - throw new RuntimeException("Unexpected modifiers: " + base.getModifiers() + " vs " + mod); - } - System.out.println(Integer.toHexString(mod)); - } - - private static void testClassType(Class<?> c) throws Exception { - boolean isInterface = isInterface(c); - boolean isArray = isArrayClass(c); - boolean isModifiable = isModifiableClass(c); - System.out.println(c.getName() + " interface=" + isInterface + " array=" + isArray + - " modifiable=" + isModifiable); - } - - private static void testClassFields(Class<?> c) throws Exception { - System.out.println(Arrays.toString(getClassFields(c))); - } - - private static void testClassMethods(Class<?> c) throws Exception { - System.out.println(Arrays.toString(getClassMethods(c))); - } - - private static void testClassStatus(Class<?> c) { - System.out.println(c + " " + Integer.toBinaryString(getClassStatus(c))); - } - - private static void testInterfaces(Class<?> c) { - System.out.println(c + " " + Arrays.toString(getImplementedInterfaces(c))); - } - - private static boolean IsBootClassLoader(ClassLoader l) { - // Hacky check for Android's fake boot classloader. - return l.getClass().getName().equals("java.lang.BootClassLoader"); - } - - private static void testClassLoader(Class<?> c) { - Object cl = getClassLoader(c); - System.out.println(c + " " + (cl != null ? cl.getClass().getName() : "null")); - if (cl == null) { - if (c.getClassLoader() != null && !IsBootClassLoader(c.getClassLoader())) { - throw new RuntimeException("Expected " + c.getClassLoader() + ", but got null."); - } - } else { - if (!(cl instanceof ClassLoader)) { - throw new RuntimeException("Unexpected \"classloader\": " + cl + " (" + cl.getClass() + - ")"); - } - if (cl != c.getClassLoader()) { - throw new RuntimeException("Unexpected classloader: " + c.getClassLoader() + " vs " + cl); - } - } - } - - private static void testClassLoaderClasses() throws Exception { - ClassLoader boot = ClassLoader.getSystemClassLoader().getParent(); - while (boot.getParent() != null) { - boot = boot.getParent(); - } - - System.out.println(); - System.out.println("boot <- src <- src-ex (A,B)"); - ClassLoader cl1 = create(create(boot, DEX1), DEX2); - Class.forName("B", false, cl1); - Class.forName("A", false, cl1); - printClassLoaderClasses(cl1); - - System.out.println(); - System.out.println("boot <- src (B) <- src-ex (A, List)"); - ClassLoader cl2 = create(create(boot, DEX1), DEX2); - Class.forName("A", false, cl2); - Class.forName("java.util.List", false, cl2); - Class.forName("B", false, cl2.getParent()); - printClassLoaderClasses(cl2); - - System.out.println(); - System.out.println("boot <- src+src-ex (A,B)"); - ClassLoader cl3 = create(boot, DEX1, DEX2); - Class.forName("B", false, cl3); - Class.forName("A", false, cl3); - printClassLoaderClasses(cl3); - - // Check that the boot classloader dumps something non-empty. - Class<?>[] bootClasses = getClassLoaderClasses(boot); - if (bootClasses.length == 0) { - throw new RuntimeException("No classes initiated by boot classloader."); - } - // Check that at least java.util.List is loaded. - boolean foundList = false; - for (Class<?> c : bootClasses) { - if (c == java.util.List.class) { - foundList = true; - break; - } - } - if (!foundList) { - System.out.println(Arrays.toString(bootClasses)); - throw new RuntimeException("Could not find class java.util.List."); - } - } - - private static void testClassVersion() { - System.out.println(Arrays.toString(getClassVersion(Main.class))); - } - - private static void testClassEvents() throws Exception { - ClassLoader cl = Main.class.getClassLoader(); - while (cl.getParent() != null) { - cl = cl.getParent(); - } - final ClassLoader boot = cl; - - // The JIT may deeply inline and load some classes. Preload these for test determinism. - final String PRELOAD_FOR_JIT[] = { - "java.nio.charset.CoderMalfunctionError", - "java.util.NoSuchElementException" - }; - for (String s : PRELOAD_FOR_JIT) { - Class.forName(s); - } - - Runnable r = new Runnable() { - @Override - public void run() { - try { - ClassLoader cl6 = create(boot, DEX1, DEX2); - System.out.println("C, true"); - Class.forName("C", true, cl6); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }; - - Thread dummyThread = new Thread(); - dummyThread.start(); - dummyThread.join(); - - ensureJitCompiled(Main.class, "testClassEvents"); - - enableClassLoadPreparePrintEvents(true); - - ClassLoader cl1 = create(boot, DEX1, DEX2); - System.out.println("B, false"); - Class.forName("B", false, cl1); - - ClassLoader cl2 = create(boot, DEX1, DEX2); - System.out.println("B, true"); - Class.forName("B", true, cl2); - - ClassLoader cl3 = create(boot, DEX1, DEX2); - System.out.println("C, false"); - Class.forName("C", false, cl3); - System.out.println("A, false"); - Class.forName("A", false, cl3); - - ClassLoader cl4 = create(boot, DEX1, DEX2); - System.out.println("C, true"); - Class.forName("C", true, cl4); - System.out.println("A, true"); - Class.forName("A", true, cl4); - - ClassLoader cl5 = create(boot, DEX1, DEX2); - System.out.println("A, true"); - Class.forName("A", true, cl5); - System.out.println("C, true"); - Class.forName("C", true, cl5); - - Thread t = new Thread(r, "TestRunner"); - t.start(); - t.join(); - - // Check creation of arrays and proxies. - Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Comparable.class }); - Class.forName("[LMain;"); - - enableClassLoadPreparePrintEvents(false); - - // Note: the JIT part of this test is about the JIT pulling in a class not yet touched by - // anything else in the system. This could be the verifier or the interpreter. We - // block the interpreter by calling ensureJitCompiled. The verifier, however, must - // run in configurations where dex2oat didn't verify the class itself. So explicitly - // check whether the class has been already loaded, and skip then. - // TODO: Add multiple configurations to the run script once that becomes easier to do. - if (hasJit() && !isLoadedClass("Main$ClassD")) { - testClassEventsJit(); - } - - testClassLoadPrepareEquality(); - } - - private static void testClassEventsJit() throws Exception { - enableClassLoadSeenEvents(true); - - testClassEventsJitImpl(); - - enableClassLoadSeenEvents(false); - - if (!hadLoadEvent()) { - throw new RuntimeException("Did not get expected load event."); - } - } - - private static void testClassEventsJitImpl() throws Exception { - ensureJitCompiled(Main.class, "testClassEventsJitImpl"); - - if (ClassD.x != 1) { - throw new RuntimeException("Unexpected value"); - } - } - - private static void testClassLoadPrepareEquality() throws Exception { - setEqualityEventStorageClass(ClassF.class); - - enableClassLoadPrepareEqualityEvents(true); - - Class.forName("Main$ClassE"); - - enableClassLoadPrepareEqualityEvents(false); - } - - private static void printClassLoaderClasses(ClassLoader cl) { - for (;;) { - if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) { - break; - } - - ClassLoader saved = cl; - for (;;) { - if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) { - break; - } - String s = cl.toString(); - int index1 = s.indexOf("zip file"); - int index2 = s.indexOf(']', index1); - if (index2 < 0) { - throw new RuntimeException("Unexpected classloader " + s); - } - String zip_file = s.substring(index1, index2); - int index3 = zip_file.indexOf('"'); - int index4 = zip_file.indexOf('"', index3 + 1); - if (index4 < 0) { - throw new RuntimeException("Unexpected classloader " + s); - } - String paths = zip_file.substring(index3 + 1, index4); - String pathArray[] = paths.split(":"); - for (String path : pathArray) { - int index5 = path.lastIndexOf('/'); - System.out.print(path.substring(index5 + 1)); - System.out.print('+'); - } - System.out.print(" -> "); - cl = cl.getParent(); - } - System.out.println(); - Class<?> classes[] = getClassLoaderClasses(saved); - Arrays.sort(classes, new ClassNameComparator()); - System.out.println(Arrays.toString(classes)); - - cl = saved.getParent(); - } - } - - private static native boolean isModifiableClass(Class<?> c); - private static native String[] getClassSignature(Class<?> c); - - private static native boolean isInterface(Class<?> c); - private static native boolean isArrayClass(Class<?> c); - - private static native int getClassModifiers(Class<?> c); - - private static native Object[] getClassFields(Class<?> c); - private static native Object[] getClassMethods(Class<?> c); - private static native Class<?>[] getImplementedInterfaces(Class<?> c); - - private static native int getClassStatus(Class<?> c); - - private static native Object getClassLoader(Class<?> c); - - private static native Class<?>[] getClassLoaderClasses(ClassLoader cl); - - private static native int[] getClassVersion(Class<?> c); - - private static native void enableClassLoadPreparePrintEvents(boolean b); - - private static native void ensureJitCompiled(Class<?> c, String name); - - private static native boolean hasJit(); - private static native boolean isLoadedClass(String name); - private static native void enableClassLoadSeenEvents(boolean b); - private static native boolean hadLoadEvent(); - - private static native void setEqualityEventStorageClass(Class<?> c); - private static native void enableClassLoadPrepareEqualityEvents(boolean b); - - private static class TestForNonInit { - public static double dummy = Math.random(); // So it can't be compile-time initialized. - } - - private static class TestForInitFail { - public static int dummy = ((int)Math.random())/0; // So it throws when initializing. - } - - public static interface InfA { - } - public static interface InfB extends InfA { - } - public static interface InfC extends InfB { - } - - public abstract static class ClassA implements InfA { - } - public abstract static class ClassB extends ClassA implements InfB { - } - public abstract static class ClassC implements InfA, InfC { - } - - public static class ClassD { - static int x = 1; - } - - public static class ClassE { - public void foo() { - } - public void bar() { - } - } - - public static class ClassF { - public static Object STATIC = null; - public static Reference<Object> WEAK = null; - } - - private static final String DEX1 = System.getenv("DEX_LOCATION") + "/912-classes.jar"; - private static final String DEX2 = System.getenv("DEX_LOCATION") + "/912-classes-ex.jar"; - - private static ClassLoader create(ClassLoader parent, String... elements) throws Exception { - // Note: We use a PathClassLoader, as we do not care about code performance. We only load - // the classes, and they're empty. - Class<?> pathClassLoaderClass = Class.forName("dalvik.system.PathClassLoader"); - Constructor<?> pathClassLoaderInit = pathClassLoaderClass.getConstructor(String.class, - ClassLoader.class); - String path = String.join(":", elements); - return (ClassLoader) pathClassLoaderInit.newInstance(path, parent); - } - - private static class ClassNameComparator implements Comparator<Class<?>> { - public int compare(Class<?> c1, Class<?> c2) { - return c1.getName().compareTo(c2.getName()); - } + art.Test912.run(); + art.Test912Art.run(); } } diff --git a/test/912-classes/src/art/DexData.java b/test/912-classes/src/art/DexData.java new file mode 100644 index 0000000000..7d150322ca --- /dev/null +++ b/test/912-classes/src/art/DexData.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.nio.ByteBuffer; +import java.util.Base64; + +import dalvik.system.InMemoryDexClassLoader; + +public class DexData { + public static ClassLoader getBootClassLoader() { + ClassLoader cl = DexData.class.getClassLoader(); + while (cl.getParent() != null) { + cl = cl.getParent(); + } + return cl; + } + + public static ClassLoader create1() { + return create1(getBootClassLoader()); + } + public static ClassLoader create1(ClassLoader parent) { + return create(parent, DEX_DATA_B); + } + + public static ClassLoader create2() { + return create2(getBootClassLoader()); + } + public static ClassLoader create2(ClassLoader parent) { + return create(parent, DEX_DATA_AC); + } + + public static ClassLoader create12() { + return create12(getBootClassLoader()); + } + public static ClassLoader create12(ClassLoader parent) { + return create(parent, DEX_DATA_AC, DEX_DATA_B); + } + + private static ClassLoader create(ClassLoader parent, String... stringData) { + ByteBuffer byteBuffers[] = new ByteBuffer[stringData.length]; + for (int i = 0; i < stringData.length; i++) { + byteBuffers[i] = ByteBuffer.wrap(Base64.getDecoder().decode(stringData[i])); + } + return new InMemoryDexClassLoader(byteBuffers, parent); + } + + /* + * Derived from: + * + * public class A { + * } + * + * public class C extends A { + * } + * + */ + private final static String DEX_DATA_AC = + "ZGV4CjAzNQD5KyH7WmGuqVEyL+2aKG1nyb27UJaCjFwQAgAAcAAAAHhWNBIAAAAAAAAAAIgBAAAH" + + "AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAQAQAAAAEAADAB" + + "AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA" + + "AAAAAAABAAAAAAAAAAIAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAEAAAAAAAAAcwEAAAAAAAABAAAA" + + "AQAAAAAAAAAAAAAAAgAAAAAAAAB9AQAAAAAAAAEAAQABAAAAaQEAAAQAAABwEAIAAAAOAAEAAQAB" + + "AAAAbgEAAAQAAABwEAAAAAAOAAY8aW5pdD4ABkEuamF2YQAGQy5qYXZhAANMQTsAA0xDOwASTGph" + + "dmEvbGFuZy9PYmplY3Q7AAFWABEABw4AEQAHDgAAAAEAAIGABIACAAABAAGBgASYAgALAAAAAAAA" + + "AAEAAAAAAAAAAQAAAAcAAABwAAAAAgAAAAQAAACMAAAAAwAAAAEAAACcAAAABQAAAAMAAACoAAAA" + + "BgAAAAIAAADAAAAAASAAAAIAAAAAAQAAAiAAAAcAAAAwAQAAAyAAAAIAAABpAQAAACAAAAIAAABz" + + "AQAAABAAAAEAAACIAQAA"; + + /* + * Derived from: + * + * public class B { + * } + * + */ + private final static String DEX_DATA_B = + "ZGV4CjAzNQBgKV6iWFG4aOm5WEy8oGtDZjqsftBgwJ2oAQAAcAAAAHhWNBIAAAAAAAAAACABAAAF" + + "AAAAcAAAAAMAAACEAAAAAQAAAJAAAAAAAAAAAAAAAAIAAACcAAAAAQAAAKwAAADcAAAAzAAAAOQA" + + "AADsAAAA9AAAAPkAAAANAQAAAgAAAAMAAAAEAAAABAAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAA" + + "AAAAAAABAAAAAQAAAAAAAAABAAAAAAAAABUBAAAAAAAAAQABAAEAAAAQAQAABAAAAHAQAQAAAA4A" + + "Bjxpbml0PgAGQi5qYXZhAANMQjsAEkxqYXZhL2xhbmcvT2JqZWN0OwABVgARAAcOAAAAAQAAgYAE" + + "zAEACwAAAAAAAAABAAAAAAAAAAEAAAAFAAAAcAAAAAIAAAADAAAAhAAAAAMAAAABAAAAkAAAAAUA" + + "AAACAAAAnAAAAAYAAAABAAAArAAAAAEgAAABAAAAzAAAAAIgAAAFAAAA5AAAAAMgAAABAAAAEAEA" + + "AAAgAAABAAAAFQEAAAAQAAABAAAAIAEAAA=="; +} diff --git a/test/912-classes/src/art/Test912.java b/test/912-classes/src/art/Test912.java new file mode 100644 index 0000000000..f3ff2b0668 --- /dev/null +++ b/test/912-classes/src/art/Test912.java @@ -0,0 +1,454 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.lang.ref.Reference; +import java.lang.reflect.Constructor; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; + +public class Test912 { + public static void run() throws Exception { + art.Main.bindAgentJNIForClass(Test912.class); + doTest(); + } + + public static void doTest() throws Exception { + testClass("java.lang.Object"); + testClass("java.lang.String"); + testClass("java.lang.Math"); + testClass("java.util.List"); + + testClass(getProxyClass()); + + testClass(int.class); + testClass(double[].class); + + testClassType(int.class); + testClassType(getProxyClass()); + testClassType(Runnable.class); + testClassType(String.class); + testClassType(ArrayList.class); + + testClassType(int[].class); + testClassType(Runnable[].class); + testClassType(String[].class); + + testClassFields(Integer.class); + testClassFields(int.class); + testClassFields(String[].class); + + testClassMethods(Integer.class); + testClassMethods(int.class); + testClassMethods(String[].class); + + testClassStatus(int.class); + testClassStatus(String[].class); + testClassStatus(Object.class); + testClassStatus(TestForNonInit.class); + try { + System.out.println(TestForInitFail.dummy); + } catch (ExceptionInInitializerError e) { + } + testClassStatus(TestForInitFail.class); + + testInterfaces(int.class); + testInterfaces(String[].class); + testInterfaces(Object.class); + testInterfaces(InfA.class); + testInterfaces(InfB.class); + testInterfaces(InfC.class); + testInterfaces(ClassA.class); + testInterfaces(ClassB.class); + testInterfaces(ClassC.class); + + testClassLoader(String.class); + testClassLoader(String[].class); + testClassLoader(InfA.class); + testClassLoader(getProxyClass()); + + testClassLoaderClasses(); + + System.out.println(); + + testClassVersion(); + + System.out.println(); + + // Use a dedicated thread to have a well-defined current thread. + Thread classEventsThread = new Thread("ClassEvents") { + @Override + public void run() { + try { + testClassEvents(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + classEventsThread.start(); + classEventsThread.join(); + } + + private static void testClass(String className) throws Exception { + Class<?> base = Class.forName(className); + testClass(base); + } + + private static void testClass(Class<?> base) throws Exception { + String[] result = getClassSignature(base); + System.out.println(Arrays.toString(result)); + int mod = getClassModifiers(base); + if (mod != base.getModifiers()) { + throw new RuntimeException("Unexpected modifiers: " + base.getModifiers() + " vs " + mod); + } + System.out.println(Integer.toHexString(mod)); + } + + private static void testClassType(Class<?> c) throws Exception { + boolean isInterface = isInterface(c); + boolean isArray = isArrayClass(c); + boolean isModifiable = isModifiableClass(c); + System.out.println(c.getName() + " interface=" + isInterface + " array=" + isArray + + " modifiable=" + isModifiable); + } + + private static void testClassFields(Class<?> c) throws Exception { + System.out.println(Arrays.toString(getClassFields(c))); + } + + private static void testClassMethods(Class<?> c) throws Exception { + System.out.println(Arrays.toString(getClassMethods(c))); + } + + private static void testClassStatus(Class<?> c) { + System.out.println(c + " " + Integer.toBinaryString(getClassStatus(c))); + } + + private static void testInterfaces(Class<?> c) { + System.out.println(c + " " + Arrays.toString(getImplementedInterfaces(c))); + } + + private static boolean IsBootClassLoader(ClassLoader l) { + // Hacky check for Android's fake boot classloader. + return l.getClass().getName().equals("java.lang.BootClassLoader"); + } + + private static void testClassLoader(Class<?> c) { + Object cl = getClassLoader(c); + System.out.println(c + " " + (cl != null ? cl.getClass().getName() : "null")); + if (cl == null) { + if (c.getClassLoader() != null && !IsBootClassLoader(c.getClassLoader())) { + throw new RuntimeException("Expected " + c.getClassLoader() + ", but got null."); + } + } else { + if (!(cl instanceof ClassLoader)) { + throw new RuntimeException("Unexpected \"classloader\": " + cl + " (" + cl.getClass() + + ")"); + } + if (cl != c.getClassLoader()) { + throw new RuntimeException("Unexpected classloader: " + c.getClassLoader() + " vs " + cl); + } + } + } + + private static void testClassLoaderClasses() throws Exception { + System.out.println(); + System.out.println("boot <- (B) <- (A,C)"); + ClassLoader cl1 = DexData.create2(DexData.create1()); + Class.forName("B", false, cl1); + Class.forName("A", false, cl1); + printClassLoaderClasses(cl1); + + System.out.println(); + System.out.println("boot <- (B) <- (A, List)"); + ClassLoader cl2 = DexData.create2(DexData.create1()); + Class.forName("A", false, cl2); + Class.forName("java.util.List", false, cl2); + Class.forName("B", false, cl2.getParent()); + printClassLoaderClasses(cl2); + + System.out.println(); + System.out.println("boot <- 1+2 (A,B)"); + ClassLoader cl3 = DexData.create12(); + Class.forName("B", false, cl3); + Class.forName("A", false, cl3); + printClassLoaderClasses(cl3); + + // Check that the boot classloader dumps something non-empty. + ClassLoader boot = ClassLoader.getSystemClassLoader().getParent(); + while (boot.getParent() != null) { + boot = boot.getParent(); + } + + Class<?>[] bootClasses = getClassLoaderClasses(boot); + if (bootClasses.length == 0) { + throw new RuntimeException("No classes initiated by boot classloader."); + } + // Check that at least java.util.List is loaded. + boolean foundList = false; + for (Class<?> c : bootClasses) { + if (c == java.util.List.class) { + foundList = true; + break; + } + } + if (!foundList) { + System.out.println(Arrays.toString(bootClasses)); + throw new RuntimeException("Could not find class java.util.List."); + } + } + + private static void testClassVersion() { + System.out.println(Arrays.toString(getClassVersion(Main.class))); + } + + private static void testClassEvents() throws Exception { + ClassLoader cl = Main.class.getClassLoader(); + while (cl.getParent() != null) { + cl = cl.getParent(); + } + final ClassLoader boot = cl; + + // The JIT may deeply inline and load some classes. Preload these for test determinism. + final String PRELOAD_FOR_JIT[] = { + "java.nio.charset.CoderMalfunctionError", + "java.util.NoSuchElementException" + }; + for (String s : PRELOAD_FOR_JIT) { + Class.forName(s); + } + + Runnable r = new Runnable() { + @Override + public void run() { + try { + ClassLoader cl6 = DexData.create12(); + System.out.println("C, true"); + Class.forName("C", true, cl6); + printClassLoadMessages(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + + Thread dummyThread = new Thread(); + dummyThread.start(); + dummyThread.join(); + + enableClassLoadPreparePrintEvents(true, Thread.currentThread()); + + ClassLoader cl1 = DexData.create12(); + System.out.println("B, false"); + Class.forName("B", false, cl1); + printClassLoadMessages(); + + ClassLoader cl2 = DexData.create12(); + System.out.println("B, true"); + Class.forName("B", true, cl2); + printClassLoadMessages(); + + ClassLoader cl3 = DexData.create12(); + System.out.println("C, false"); + Class.forName("C", false, cl3); + printClassLoadMessages(); + System.out.println("A, false"); + Class.forName("A", false, cl3); + printClassLoadMessages(); + + ClassLoader cl4 = DexData.create12(); + System.out.println("C, true"); + Class.forName("C", true, cl4); + printClassLoadMessages(); + System.out.println("A, true"); + Class.forName("A", true, cl4); + printClassLoadMessages(); + + ClassLoader cl5 = DexData.create12(); + System.out.println("A, true"); + Class.forName("A", true, cl5); + printClassLoadMessages(); + System.out.println("C, true"); + Class.forName("C", true, cl5); + printClassLoadMessages(); + + enableClassLoadPreparePrintEvents(false, null); + + Thread t = new Thread(r, "TestRunner"); + enableClassLoadPreparePrintEvents(true, t); + t.start(); + t.join(); + enableClassLoadPreparePrintEvents(false, null); + + enableClassLoadPreparePrintEvents(true, Thread.currentThread()); + + // Check creation of arrays and proxies. + Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Comparable.class, I0.class }); + Class.forName("[Lart.Test912;"); + printClassLoadMessages(); + + enableClassLoadPreparePrintEvents(false, null); + + testClassLoadPrepareEquality(); + } + + private static void testClassLoadPrepareEquality() throws Exception { + setEqualityEventStorageClass(ClassF.class); + + enableClassLoadPrepareEqualityEvents(true); + + Class.forName("art.Test912$ClassE"); + + enableClassLoadPrepareEqualityEvents(false); + } + + private static void printClassLoaderClasses(ClassLoader cl) { + for (;;) { + if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) { + break; + } + + Class<?> classes[] = getClassLoaderClasses(cl); + Arrays.sort(classes, new ClassNameComparator()); + System.out.println(Arrays.toString(classes)); + + cl = cl.getParent(); + } + } + + private static void printClassLoadMessages() { + for (String s : getClassLoadMessages()) { + System.out.println(s); + } + } + + private static native boolean isModifiableClass(Class<?> c); + private static native String[] getClassSignature(Class<?> c); + + private static native boolean isInterface(Class<?> c); + private static native boolean isArrayClass(Class<?> c); + + private static native int getClassModifiers(Class<?> c); + + private static native Object[] getClassFields(Class<?> c); + private static native Object[] getClassMethods(Class<?> c); + private static native Class<?>[] getImplementedInterfaces(Class<?> c); + + private static native int getClassStatus(Class<?> c); + + private static native Object getClassLoader(Class<?> c); + + private static native Class<?>[] getClassLoaderClasses(ClassLoader cl); + + private static native int[] getClassVersion(Class<?> c); + + private static native void enableClassLoadPreparePrintEvents(boolean b, Thread filter); + private static native String[] getClassLoadMessages(); + + private static native void setEqualityEventStorageClass(Class<?> c); + private static native void enableClassLoadPrepareEqualityEvents(boolean b); + + private static class TestForNonInit { + public static double dummy = Math.random(); // So it can't be compile-time initialized. + } + + private static class TestForInitFail { + public static int dummy = ((int)Math.random())/0; // So it throws when initializing. + } + + public static interface InfA { + } + public static interface InfB extends InfA { + } + public static interface InfC extends InfB { + } + + public abstract static class ClassA implements InfA { + } + public abstract static class ClassB extends ClassA implements InfB { + } + public abstract static class ClassC implements InfA, InfC { + } + + public static class ClassE { + public void foo() { + } + public void bar() { + } + } + + public static class ClassF { + public static Object STATIC = null; + public static Reference<Object> WEAK = null; + } + + private static class ClassNameComparator implements Comparator<Class<?>> { + public int compare(Class<?> c1, Class<?> c2) { + return c1.getName().compareTo(c2.getName()); + } + } + + // See run-test 910 for an explanation. + + private static Class<?> proxyClass = null; + + private static Class<?> getProxyClass() throws Exception { + if (proxyClass != null) { + return proxyClass; + } + + for (int i = 1; i <= 21; i++) { + proxyClass = createProxyClass(i); + String name = proxyClass.getName(); + if (name.equals("$Proxy20")) { + return proxyClass; + } + } + return proxyClass; + } + + private static Class<?> createProxyClass(int i) throws Exception { + int count = Integer.bitCount(i); + Class<?>[] input = new Class<?>[count + 1]; + input[0] = Runnable.class; + int inputIndex = 1; + int bitIndex = 0; + while (i != 0) { + if ((i & 1) != 0) { + input[inputIndex++] = Class.forName("art.Test912$I" + bitIndex); + } + i >>>= 1; + bitIndex++; + } + return Proxy.getProxyClass(Test912.class.getClassLoader(), input); + } + + // Need this for the proxy naming. + public static interface I0 { + } + public static interface I1 { + } + public static interface I2 { + } + public static interface I3 { + } + public static interface I4 { + } +} diff --git a/test/912-classes/src/art/Test912Art.java b/test/912-classes/src/art/Test912Art.java new file mode 100644 index 0000000000..e4384734d8 --- /dev/null +++ b/test/912-classes/src/art/Test912Art.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.lang.ref.Reference; +import java.lang.reflect.Constructor; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; + +public class Test912Art { + public static void run() throws Exception { + art.Main.bindAgentJNIForClass(Test912Art.class); + doTest(); + } + + public static void doTest() throws Exception { + testClassEvents(); + } + + private static void testClassEvents() throws Exception { + // Note: the JIT part of this test is about the JIT pulling in a class not yet touched by + // anything else in the system. This could be the verifier or the interpreter. We + // block the interpreter by calling ensureJitCompiled. The verifier, however, must + // run in configurations where dex2oat didn't verify the class itself. So explicitly + // check whether the class has been already loaded, and skip then. + // TODO: Add multiple configurations to the run script once that becomes easier to do. + if (hasJit() && !isLoadedClass("art.Test912Art$ClassD")) { + testClassEventsJit(); + } + } + + private static void testClassEventsJit() throws Exception { + enableClassLoadSeenEvents(true); + + testClassEventsJitImpl(); + + enableClassLoadSeenEvents(false); + + if (!hadLoadEvent()) { + throw new RuntimeException("Did not get expected load event."); + } + } + + private static void testClassEventsJitImpl() throws Exception { + ensureJitCompiled(Test912Art.class, "testClassEventsJitImpl"); + + if (ClassD.x != 1) { + throw new RuntimeException("Unexpected value"); + } + } + + private static native void ensureJitCompiled(Class<?> c, String name); + + private static native boolean hasJit(); + private static native boolean isLoadedClass(String name); + private static native void enableClassLoadSeenEvents(boolean b); + private static native boolean hadLoadEvent(); + + public static class ClassD { + static int x = 1; + } +} diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt index 2a183ee06b..702b247819 100644 --- a/test/913-heaps/expected.txt +++ b/test/913-heaps/expected.txt @@ -1,9 +1,10 @@ --- true true +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -14,11 +15,13 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -31,20 +34,24 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -55,11 +62,13 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -72,43 +81,48 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] --- 3@1001 --(class)--> 1001@0 [size=123, length=-1] --- -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] --- 3@1001 --(class)--> 1001@0 [size=123, length=-1] --- +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] --- [1@0 (32, 'HelloWorld'), 2@0 (16, '')] 2 @@ -148,16 +162,17 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 10008 --- klass --- root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] @@ -167,13 +182,15 @@ root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot root@root --(thread)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- --- heap_filter --- ---- tagged objects @@ -182,10 +199,11 @@ root@root --(thread)--> 1@1000 [size=16, length=-1] --- --- ---- untagged objects +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -196,11 +214,13 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -213,20 +233,24 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -237,11 +261,13 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -254,16 +280,20 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 2@1000 --(class)--> 1000@0 [size=123, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- ---- tagged classes -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -273,6 +303,7 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -284,9 +315,12 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- -root@root --(thread)--> 3000@0 [size=132, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] +root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] 1002@0 --(interface)--> 2001@0 [size=124, length=-1] 1002@0 --(superclass)--> 1001@0 [size=123, length=-1] @@ -296,6 +330,7 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -307,24 +342,26 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] 3@1001 --(class)--> 1001@0 [size=123, length=-1] 4@1000 --(class)--> 1000@0 [size=123, length=-1] 5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@8)--> 500@0 [size=20, length=2] 6@1000 --(class)--> 1000@0 [size=123, length=-1] --- ---- untagged classes root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] @@ -335,14 +372,16 @@ root@root --(thread)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] -3@1001 --(field@5)--> 5@1002 [size=32, length=-1] -5@1002 --(field@8)--> 6@1000 [size=16, length=-1] -5@1002 --(field@9)--> 1@1000 [size=16, length=-1] +3@1001 --(field@5)--> 5@1002 [size=36, length=-1] +500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] +5@1002 --(field@10)--> 1@1000 [size=16, length=-1] +5@1002 --(field@9)--> 6@1000 [size=16, length=-1] --- diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc index 6a06b29152..e319f7d98c 100644 --- a/test/913-heaps/heaps.cc +++ b/test/913-heaps/heaps.cc @@ -19,40 +19,35 @@ #include <string.h> #include <iostream> +#include <sstream> #include <vector> #include "android-base/macros.h" #include "android-base/logging.h" #include "android-base/stringprintf.h" -#include "jit/jit.h" #include "jni.h" -#include "native_stack_dump.h" #include "jvmti.h" -#include "runtime.h" -#include "scoped_thread_state_change-inl.h" -#include "thread-inl.h" -#include "thread_list.h" // Test infrastructure #include "jni_helper.h" #include "jvmti_helper.h" #include "test_env.h" +#include "ti_utf.h" namespace art { namespace Test913Heaps { using android::base::StringPrintf; +#define FINAL final +#define OVERRIDE override +#define UNREACHABLE __builtin_unreachable + extern "C" JNIEXPORT void JNICALL Java_art_Test913_forceGarbageCollection( - JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) { + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { jvmtiError ret = jvmti_env->ForceGarbageCollection(); - if (ret != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(ret, &err); - printf("Error forcing a garbage collection: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - } + JvmtiErrorToException(env, jvmti_env, ret); } class IterationConfig { @@ -92,7 +87,8 @@ static jint JNICALL HeapReferenceCallback(jvmtiHeapReferenceKind reference_kind, user_data); } -static bool Run(jint heap_filter, +static bool Run(JNIEnv* env, + jint heap_filter, jclass klass_filter, jobject initial_object, IterationConfig* config) { @@ -105,14 +101,7 @@ static bool Run(jint heap_filter, initial_object, &callbacks, config); - if (ret != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(ret, &err); - printf("Failure running FollowReferences: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - return false; - } - return true; + return !JvmtiErrorToException(env, jvmti_env, ret); } extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( @@ -142,6 +131,27 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( jint length, void* user_data ATTRIBUTE_UNUSED) OVERRIDE { jlong tag = *tag_ptr; + + // Ignore any jni-global roots with untagged classes. These can be from the environment, + // or the JIT. + if (reference_kind == JVMTI_HEAP_REFERENCE_JNI_GLOBAL && class_tag == 0) { + return 0; + } + // Ignore classes (1000 <= tag < 3000) for thread objects. These can be held by the JIT. + if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && class_tag == 0 && + (1000 <= *tag_ptr && *tag_ptr < 3000)) { + return 0; + } + // Ignore stack-locals of untagged threads. That is the environment. + if (reference_kind == JVMTI_HEAP_REFERENCE_STACK_LOCAL && + reference_info->stack_local.thread_tag != 3000) { + return 0; + } + // Ignore array elements with an untagged source. These are from the environment. + if (reference_kind == JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT && *referrer_tag_ptr == 0) { + return 0; + } + // Only check tagged objects. if (tag == 0) { return JVMTI_VISIT_OBJECTS; @@ -201,10 +211,6 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( reference_info, adapted_size, length)); - - if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && *tag_ptr == 1000) { - DumpStacks(); - } } std::vector<std::string> GetLines() const { @@ -259,9 +265,15 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( if (info_.jni_local.method != nullptr) { jvmti_env->GetMethodName(info_.jni_local.method, &name, nullptr, nullptr); } + // Normalize the thread id, as this depends on the number of other threads + // and which thread is running the test. Should be: + // jlong thread_id = info_.jni_local.thread_id; + // TODO: A pre-pass before the test should be able fetch this number, so it can + // be compared explicitly. + jlong thread_id = 1; std::string ret = StringPrintf("jni-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d," "method=%s]", - info_.jni_local.thread_id, + thread_id, info_.jni_local.thread_tag, info_.jni_local.depth, name == nullptr ? "<null>" : name); @@ -284,13 +296,12 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( jlong size, jint length, const jvmtiHeapReferenceInfo* reference_info) - REQUIRES_SHARED(Locks::mutator_lock_) : Elem(referrer, referree, size, length) { memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo)); - // Debug stack trace for failure condition. Remove when done. - if (info_.stack_local.depth == 3 && info_.stack_local.slot == 13) { - DumpNativeStack(std::cerr, GetTid()); - Thread::Current()->DumpJavaStack(std::cerr, false, false); + + // Debug code. Try to figure out where bad depth is coming from. + if (reference_info->stack_local.depth == 6) { + LOG(FATAL) << "Unexpected depth of 6"; } } @@ -300,9 +311,15 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( if (info_.stack_local.method != nullptr) { jvmti_env->GetMethodName(info_.stack_local.method, &name, nullptr, nullptr); } + // Normalize the thread id, as this depends on the number of other threads + // and which thread is running the test. Should be: + // jlong thread_id = info_.stack_local.thread_id; + // TODO: A pre-pass before the test should be able fetch this number, so it can + // be compared explicitly. + jlong thread_id = 1; std::string ret = StringPrintf("stack-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d," "method=%s,vreg=%d,location=% " PRId64 "]", - info_.stack_local.thread_id, + thread_id, info_.stack_local.thread_tag, info_.stack_local.depth, name == nullptr ? "<null>" : name, @@ -361,7 +378,13 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( tmp)); } case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: { - std::string tmp = StringPrintf("array-element@%d", reference_info->array.index); + jint index = reference_info->array.index; + // Normalize if it's "0@0" -> "3000@1". + // TODO: A pre-pass could probably give us this index to check explicitly. + if (referrer == "0@0" && referree == "3000@0") { + index = 0; + } + std::string tmp = StringPrintf("array-element@%d", index); return std::unique_ptr<Elem>(new StringElement(referrer, referree, size, @@ -459,16 +482,6 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( UNREACHABLE(); } - static void DumpStacks() NO_THREAD_SAFETY_ANALYSIS { - auto dump_function = [](art::Thread* t, void* data ATTRIBUTE_UNUSED) { - std::string name; - t->GetThreadName(name); - LOG(ERROR) << name; - art::DumpNativeStack(LOG_STREAM(ERROR), t->GetTid()); - }; - art::Runtime::Current()->GetThreadList()->ForEach(dump_function, nullptr); - } - jint counter_; const jint stop_after_; const jint follow_set_; @@ -476,8 +489,6 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( std::vector<std::unique_ptr<Elem>> lines_; }; - jit::ScopedJitSuspend sjs; // Wait to avoid JIT influence (e.g., JNI globals). - // If jniRef isn't null, add a local and a global ref. ScopedLocalRef<jobject> jni_local_ref(env, nullptr); jobject jni_global_ref = nullptr; @@ -487,7 +498,9 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences( } PrintIterationConfig config(stop_after, follow_set); - Run(heap_filter, klass_filter, initial_object, &config); + if (!Run(env, heap_filter, klass_filter, initial_object, &config)) { + return nullptr; + } std::vector<std::string> lines = config.GetLines(); jobjectArray ret = CreateObjectArray(env, @@ -528,10 +541,10 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferencesStrin void* user_data) { FindStringCallbacks* p = reinterpret_cast<FindStringCallbacks*>(user_data); if (*tag_ptr != 0) { - size_t utf_byte_count = CountUtf8Bytes(value, value_length); + size_t utf_byte_count = ti::CountUtf8Bytes(value, value_length); std::unique_ptr<char[]> mod_utf(new char[utf_byte_count + 1]); memset(mod_utf.get(), 0, utf_byte_count + 1); - ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length); + ti::ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length); p->data.push_back(android::base::StringPrintf("%" PRId64 "@%" PRId64 " (%" PRId64 ", '%s')", *tag_ptr, class_tag, diff --git a/test/913-heaps/src/art/Test913.java b/test/913-heaps/src/art/Test913.java index c54ecb049f..d3b29cf2b5 100644 --- a/test/913-heaps/src/art/Test913.java +++ b/test/913-heaps/src/art/Test913.java @@ -21,12 +21,34 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.concurrent.CountDownLatch; public class Test913 { public static void run() throws Exception { Main.bindAgentJNIForClass(Test913.class); doTest(); + + // Use a countdown latch for synchronization, as join() will introduce more roots. + final CountDownLatch cdl1 = new CountDownLatch(1); + + // Run the follow-references tests on a dedicated thread so we know the specific Thread type. + Thread t = new Thread() { + @Override + public void run() { + try { + Test913.runFollowReferences(); + } catch (Exception e) { + throw new RuntimeException(e); + } + cdl1.countDown(); + } + }; + t.start(); + cdl1.await(); + } + + public static void runFollowReferences() throws Exception { new TestConfig().doFollowReferencesTest(); Runtime.getRuntime().gc(); @@ -349,6 +371,14 @@ public class Test913 { cInst.baz2 = aInst; v.add(cInstStr, aInstStr); // C -->(field) --> A. + A[] aArray = new A[2]; + setTag(aArray, 500); + aArray[1] = a2Inst; + cInst.array = aArray; + String aArrayStr = "500@0"; + v.add(cInstStr, aArrayStr); + v.add(aArrayStr, a2InstStr); + return aInst; } } @@ -386,6 +416,7 @@ public class Test913 { public static class C extends B implements I2 { public A baz; public A baz2; + public A[] array; public C() {} public C(A a, A b) { @@ -481,7 +512,8 @@ public class Test913 { if (currentHead == null) { currentHead = referrer; } else { - if (!currentHead.equals(referrer)) { + // Ignore 0@0, as it can happen at any time (as it stands for all other objects). + if (!currentHead.equals(referrer) && !referrer.equals("0@0")) { completedReferrers.add(currentHead); currentHead = referrer; if (completedReferrers.contains(referrer)) { diff --git a/test/914-hello-obsolescence/src/Main.java b/test/914-hello-obsolescence/src/Main.java index 2ec7664f0f..ab5c7f421f 100644 --- a/test/914-hello-obsolescence/src/Main.java +++ b/test/914-hello-obsolescence/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,60 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" + - "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test914.run(); } - - public static void doTest(Transform t) { - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - t.sayHi(() -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/914-hello-obsolescence/src/Transform.java b/test/914-hello-obsolescence/src/Transform.java deleted file mode 100644 index 8cda6cdf53..0000000000 --- a/test/914-hello-obsolescence/src/Transform.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Hello" < "LTransform;" < "hello". - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/914-hello-obsolescence/src/art/Redefinition.java b/test/914-hello-obsolescence/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/914-hello-obsolescence/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/914-hello-obsolescence/src/art/Test914.java b/test/914-hello-obsolescence/src/art/Test914.java new file mode 100644 index 0000000000..ef2710da5b --- /dev/null +++ b/test/914-hello-obsolescence/src/art/Test914.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test914 { + + // The class we will be transforming. + static class Transform { + public void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + + // static class Transform { + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDkxNC5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5MTQkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTE0ACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7AAIAAgAA" + + "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBlmxNYAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5MTQkVHJhbnNmb3JtOwANTGFydC9UZXN0OTE0OwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTE0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/915-obsolete-2/src/Main.java b/test/915-obsolete-2/src/Main.java index fc73ee86fc..be51234c87 100644 --- a/test/915-obsolete-2/src/Main.java +++ b/test/915-obsolete-2/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,86 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - // class Transform { - // private void Start() { - // System.out.println("Hello - private - Transformed"); - // } - // - // private void Finish() { - // System.out.println("Goodbye - private - Transformed"); - // } - // - // public void sayHi(Runnable r) { - // System.out.println("Pre Start private method call - Transformed"); - // Start(); - // System.out.println("Post Start private method call - Transformed"); - // r.run(); - // System.out.println("Pre Finish private method call - Transformed"); - // Finish(); - // System.out.println("Post Finish private method call - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAMgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" + - "JwcAKAcAKQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" + - "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAO" + - "VHJhbnNmb3JtLmphdmEMAA8AEAcAKgwAKwAsAQAdSGVsbG8gLSBwcml2YXRlIC0gVHJhbnNmb3Jt" + - "ZWQHAC0MAC4ALwEAH0dvb2RieWUgLSBwcml2YXRlIC0gVHJhbnNmb3JtZWQBACtQcmUgU3RhcnQg" + - "cHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAATABABACxQb3N0IFN0YXJ0IHByaXZh" + - "dGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcAMAwAMQAQAQAsUHJlIEZpbmlzaCBwcml2YXRl" + - "IG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQMABQAEAEALVBvc3QgRmluaXNoIHByaXZhdGUgbWV0" + - "aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAEACVRyYW5zZm9ybQEAEGphdmEvbGFuZy9PYmplY3QBABBq" + - "YXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9Q" + - "cmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABJqYXZhL2xhbmcv" + - "UnVubmFibGUBAANydW4AIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAAB" + - "ABIAAAAGAAEAAAABAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAA" + - "AAMACAAEAAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAcACAAI" + - "AAEAFQAWAAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQq" + - "twALsgACEgy2AASxAAAAAQASAAAAIgAIAAAACwAIAAwADAANABQADgAaAA8AIgAQACYAEQAuABIA" + - "AQAXAAAAAgAY"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCM0QYTJmX+NsZXkImojgSkJtXyuew3oaXcBAAAcAAAAHhWNBIAAAAAAAAAADwEAAAX" + - "AAAAcAAAAAcAAADMAAAAAwAAAOgAAAABAAAADAEAAAcAAAAUAQAAAQAAAEwBAABwAwAAbAEAAD4C" + - "AABGAgAATgIAAG8CAACOAgAAmwIAALICAADGAgAA3AIAAPACAAAEAwAAMwMAAGEDAACPAwAAvAMA" + - "AMMDAADTAwAA1gMAANoDAADuAwAA8wMAAPwDAAABBAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAA" + - "EAAAABAAAAAGAAAAAAAAABEAAAAGAAAAMAIAABEAAAAGAAAAOAIAAAUAAQATAAAAAAAAAAAAAAAA" + - "AAAAAQAAAAAAAAAOAAAAAAABABYAAAABAAIAFAAAAAIAAAAAAAAAAwAAABUAAAAAAAAAAAAAAAIA" + - "AAAAAAAADwAAAAAAAAAmBAAAAAAAAAEAAQABAAAACAQAAAQAAABwEAUAAAAOAAMAAQACAAAADQQA" + - "AAkAAABiAAAAGwECAAAAbiAEABAADgAAAAMAAQACAAAAEwQAAAkAAABiAAAAGwEDAAAAbiAEABAA" + - "DgAAAAQAAgACAAAAGQQAACoAAABiAAAAGwENAAAAbiAEABAAcBACAAIAYgAAABsBCwAAAG4gBAAQ" + - "AHIQBgADAGIAAAAbAQwAAABuIAQAEABwEAEAAgBiAAAAGwEKAAAAbiAEABAADgABAAAAAwAAAAEA" + - "AAAEAAY8aW5pdD4ABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVs" + - "bG8gLSBwcml2YXRlIC0gVHJhbnNmb3JtZWQAC0xUcmFuc2Zvcm07ABVMamF2YS9pby9QcmludFN0" + - "cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xh" + - "bmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AC1Qb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhv" + - "ZCBjYWxsIC0gVHJhbnNmb3JtZWQALFBvc3QgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRy" + - "YW5zZm9ybWVkACxQcmUgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAr" + - "UHJlIFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAFU3RhcnQADlRyYW5z" + - "Zm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00LjEzAANvdXQAB3ByaW50bG4AA3J1bgAF" + - "c2F5SGkAAQAHDgAHAAcOhwADAAcOhwALAQAHDoc8hzyHPIcAAAADAQCAgATsAgEChAMBAqgDAwHM" + - "Aw0AAAAAAAAAAQAAAAAAAAABAAAAFwAAAHAAAAACAAAABwAAAMwAAAADAAAAAwAAAOgAAAAEAAAA" + - "AQAAAAwBAAAFAAAABwAAABQBAAAGAAAAAQAAAEwBAAABIAAABAAAAGwBAAABEAAAAgAAADACAAAC" + - "IAAAFwAAAD4CAAADIAAABAAAAAgEAAAAIAAAAQAAACYEAAAAEAAAAQAAADwEAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test915.run(); } - - public static void doTest(Transform t) { - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - t.sayHi(() -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/915-obsolete-2/src/art/Redefinition.java b/test/915-obsolete-2/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/915-obsolete-2/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/915-obsolete-2/src/art/Test915.java b/test/915-obsolete-2/src/art/Test915.java new file mode 100644 index 0000000000..63c7f344dd --- /dev/null +++ b/test/915-obsolete-2/src/art/Test915.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test915 { + + static class Transform { + private void Start() { + System.out.println("hello - private"); + } + + private void Finish() { + System.out.println("goodbye - private"); + } + + public void sayHi(Runnable r) { + System.out.println("Pre Start private method call"); + Start(); + System.out.println("Post Start private method call"); + r.run(); + System.out.println("Pre Finish private method call"); + Finish(); + System.out.println("Post Finish private method call"); + } + } + + // static class Transform { + // private void Start() { + // System.out.println("Hello - private - Transformed"); + // } + // + // private void Finish() { + // System.out.println("Goodbye - private - Transformed"); + // } + // + // public void sayHi(Runnable r) { + // System.out.println("Pre Start private method call - Transformed"); + // Start(); + // System.out.println("Post Start private method call - Transformed"); + // r.run(); + // System.out.println("Pre Finish private method call - Transformed"); + // Finish(); + // System.out.println("Post Finish private method call - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQANgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" + + "JwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" + + "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAM" + + "VGVzdDkxNS5qYXZhDAAPABAHAC0MAC4ALwEAHUhlbGxvIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVk" + + "BwAwDAAxADIBAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkAQArUHJlIFN0YXJ0IHBy" + + "aXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAwAEwAQAQAsUG9zdCBTdGFydCBwcml2YXRl" + + "IG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQHADMMADQAEAEALFByZSBGaW5pc2ggcHJpdmF0ZSBt" + + "ZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAUABABAC1Qb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhv" + + "ZCBjYWxsIC0gVHJhbnNmb3JtZWQHADUBABVhcnQvVGVzdDkxNSRUcmFuc2Zvcm0BAAlUcmFuc2Zv" + + "cm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEA" + + "A291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmlu" + + "dGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuAQAL" + + "YXJ0L1Rlc3Q5MTUAIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAABABIA" + + "AAAGAAEAAAAFAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAAAAcA" + + "CAAIAAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAoACAALAAEA" + + "FQAWAAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQqtwAL" + + "sgACEgy2AASxAAAAAQASAAAAIgAIAAAADQAIAA4ADAAPABQAEAAaABEAIgASACYAEwAuABQAAgAX" + + "AAAAAgAYACsAAAAKAAEADQAoACoACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAQ+GYcAAAAAAAAAAAAAAAAAAAAAAAAAADUBQAAcAAAAHhWNBIAAAAAAAAAABAFAAAd" + + "AAAAcAAAAAoAAADkAAAAAwAAAAwBAAABAAAAMAEAAAcAAAA4AQAAAQAAAHABAABEBAAAkAEAAJAB" + + "AACYAQAAoAEAAMEBAADgAQAA+QEAAAgCAAAsAgAATAIAAGMCAAB3AgAAjQIAAKECAAC1AgAA5AIA" + + "ABIDAABAAwAAbQMAAHQDAACCAwAAjQMAAJADAACUAwAAoQMAAKcDAACsAwAAtQMAALoDAADBAwAA" + + "BAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAAFAAAABQAAAAJAAAAAAAAABUAAAAJ" + + "AAAA0AMAABUAAAAJAAAAyAMAAAgABAAYAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAARAAAAAAABABsA" + + "AAAEAAIAGQAAAAUAAAAAAAAABgAAABoAAAAAAAAAAAAAAAUAAAAAAAAAEgAAAAAFAADMBAAAAAAA" + + "AAY8aW5pdD4ABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVsbG8g" + + "LSBwcml2YXRlIC0gVHJhbnNmb3JtZWQAF0xhcnQvVGVzdDkxNSRUcmFuc2Zvcm07AA1MYXJ0L1Rl" + + "c3Q5MTU7ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90" + + "YXRpb24vSW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmpl" + + "Y3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5n" + + "L1N5c3RlbTsALVBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAs" + + "UG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALFByZSBGaW5pc2gg" + + "cHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkACtQcmUgU3RhcnQgcHJpdmF0ZSBtZXRo" + + "b2QgY2FsbCAtIFRyYW5zZm9ybWVkAAVTdGFydAAMVGVzdDkxNS5qYXZhAAlUcmFuc2Zvcm0AAVYA" + + "AlZMAAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxuAANydW4ABXNheUhpAAV2YWx1ZQAB" + + "AAAABwAAAAEAAAAGAAAABQAHDgAKAAcOAQgPAAcABw4BCA8ADQEABw4BCA8BAw8BCA8BAw8BCA8B" + + "Aw8BCA8AAQABAAEAAADYAwAABAAAAHAQBQAAAA4AAwABAAIAAADdAwAACQAAAGIAAAAbAQIAAABu" + + "IAQAEAAOAAAAAwABAAIAAADlAwAACQAAAGIAAAAbAQMAAABuIAQAEAAOAAAABAACAAIAAADtAwAA" + + "KgAAAGIAAAAbARAAAABuIAQAEABwEAIAAgBiAAAAGwEOAAAAbiAEABAAchAGAAMAYgAAABsBDwAA" + + "AG4gBAAQAHAQAQACAGIAAAAbAQ0AAABuIAQAEAAOAAAAAwEAgIAEiAgBAqAIAQLECAMB6AgAAAIC" + + "ARwYAQIDAhYECBcXEwACAAAA5AQAAOoEAAD0BAAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAA" + + "AAEAAAAdAAAAcAAAAAIAAAAKAAAA5AAAAAMAAAADAAAADAEAAAQAAAABAAAAMAEAAAUAAAAHAAAA" + + "OAEAAAYAAAABAAAAcAEAAAIgAAAdAAAAkAEAAAEQAAACAAAAyAMAAAMgAAAEAAAA2AMAAAEgAAAE" + + "AAAACAQAAAAgAAABAAAAzAQAAAQgAAACAAAA5AQAAAMQAAABAAAA9AQAAAYgAAABAAAAAAUAAAAQ" + + "AAABAAAAEAUAAA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/916-obsolete-jit/src/Main.java b/test/916-obsolete-jit/src/Main.java index 3453261f44..cb202e400d 100644 --- a/test/916-obsolete-jit/src/Main.java +++ b/test/916-obsolete-jit/src/Main.java @@ -14,6 +14,9 @@ * limitations under the License. */ + +import art.Redefinition; + import java.util.function.Consumer; import java.lang.reflect.Method; import java.util.Base64; @@ -144,7 +147,7 @@ public class Main { // Actually do the redefinition. The stack looks good. retry = false; w.accept("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); } }; // This just prints something out to show we are running the Runnable. @@ -168,9 +171,4 @@ public class Main { private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable); private static native void ensureJitCompiled(Class c, String name); - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/916-obsolete-jit/src/art/Redefinition.java b/test/916-obsolete-jit/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/916-obsolete-jit/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/917-fields-transformation/src/Main.java b/test/917-fields-transformation/src/Main.java index 588af49cca..289b89f2f6 100644 --- a/test/917-fields-transformation/src/Main.java +++ b/test/917-fields-transformation/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,67 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - // base64 encoded class/dex file for - // class Transform { - // public String take1; - // public String take2; - // - // public Transform(String a, String b) { - // take1 = a; - // take2 = b; - // } - // - // public String getResult() { - // return take2; - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAFwoABQARCQAEABIJAAQAEwcAFAcAFQEABXRha2UxAQASTGphdmEvbGFuZy9TdHJp" + - "bmc7AQAFdGFrZTIBAAY8aW5pdD4BACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9TdHJp" + - "bmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAJZ2V0UmVzdWx0AQAUKClMamF2YS9sYW5n" + - "L1N0cmluZzsBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkAFgwABgAHDAAIAAcBAAlU" + - "cmFuc2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQADKClWACAABAAFAAAAAgABAAYABwAAAAEACAAH" + - "AAAAAgABAAkACgABAAsAAAAzAAIAAwAAAA8qtwABKiu1AAIqLLUAA7EAAAABAAwAAAASAAQAAAAU" + - "AAQAFQAJABYADgAXAAEADQAOAAEACwAAAB0AAQABAAAABSq0AAOwAAAAAQAMAAAABgABAAAAGgAB" + - "AA8AAAACABA="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAGUTBb4jIABRlaI9rejdk7RCfyqR2kmNSkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAM" + - "AAAAcAAAAAQAAACgAAAAAwAAALAAAAACAAAA1AAAAAMAAADkAAAAAQAAAPwAAACIAQAAHAEAAFwB" + - "AABkAQAAZwEAAHQBAACIAQAAnAEAAKwBAACvAQAAtAEAAMgBAADTAQAA2gEAAAIAAAADAAAABAAA" + - "AAYAAAABAAAAAgAAAAAAAAAGAAAAAwAAAAAAAAAHAAAAAwAAAFQBAAAAAAIACgAAAAAAAgALAAAA" + - "AAACAAAAAAAAAAAACQAAAAEAAQAAAAAAAAAAAAAAAAABAAAAAAAAAAUAAAAAAAAA8AEAAAAAAAAD" + - "AAMAAQAAAOEBAAAIAAAAcBACAAAAWwEAAFsCAQAOAAIAAQAAAAAA6wEAAAMAAABUEAEAEQAAAAIA" + - "AAACAAIABjxpbml0PgABTAALTFRyYW5zZm9ybTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEv" + - "bGFuZy9TdHJpbmc7AA5UcmFuc2Zvcm0uamF2YQABVgADVkxMABJlbWl0dGVyOiBqYWNrLTQuMTkA" + - "CWdldFJlc3VsdAAFdGFrZTEABXRha2UyABQCAAAHDjwtLQAaAAcOAAACAQEAAQEBAIGABJwCAQG8" + - "AgAADQAAAAAAAAABAAAAAAAAAAEAAAAMAAAAcAAAAAIAAAAEAAAAoAAAAAMAAAADAAAAsAAAAAQA" + - "AAACAAAA1AAAAAUAAAADAAAA5AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA" + - "AAIgAAAMAAAAXAEAAAMgAAACAAAA4QEAAAAgAAABAAAA8AEAAAAQAAABAAAABAIAAA=="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform("Hello", "Goodbye"), - new Transform("start", "end")); - } - - private static void printTransform(Transform t) { - System.out.println("Result is " + t.getResult()); - System.out.println("take1 is " + t.take1); - System.out.println("take2 is " + t.take2); - } - public static void doTest(Transform t1, Transform t2) { - printTransform(t1); - printTransform(t2); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - printTransform(t1); - printTransform(t2); + public static void main(String[] args) throws Exception { + art.Test917.run(); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/917-fields-transformation/src/Transform.java b/test/917-fields-transformation/src/Transform.java deleted file mode 100644 index 6fe6223776..0000000000 --- a/test/917-fields-transformation/src/Transform.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public String take1; - public String take2; - - public Transform(String take1, String take2) { - this.take1 = take1; - this.take2 = take2; - } - - public String getResult() { - return take1; - } -} diff --git a/test/917-fields-transformation/src/art/Redefinition.java b/test/917-fields-transformation/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/917-fields-transformation/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/917-fields-transformation/src/art/Test917.java b/test/917-fields-transformation/src/art/Test917.java new file mode 100644 index 0000000000..245e92e200 --- /dev/null +++ b/test/917-fields-transformation/src/art/Test917.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +public class Test917 { + + static class Transform { + public String take1; + public String take2; + + public Transform(String take1, String take2) { + this.take1 = take1; + this.take2 = take2; + } + + public String getResult() { + return take1; + } + } + + + // base64 encoded class/dex file for + // static class Transform { + // public String take1; + // public String take2; + // + // public Transform(String a, String b) { + // take1 = a; + // take2 = b; + // } + // + // public String getResult() { + // return take2; + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAGwoABQARCQAEABIJAAQAEwcAFQcAGAEABXRha2UxAQASTGphdmEvbGFuZy9TdHJp" + + "bmc7AQAFdGFrZTIBAAY8aW5pdD4BACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9TdHJp" + + "bmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAJZ2V0UmVzdWx0AQAUKClMamF2YS9sYW5n" + + "L1N0cmluZzsBAApTb3VyY2VGaWxlAQAMVGVzdDkxNy5qYXZhDAAJABkMAAYABwwACAAHBwAaAQAV" + + "YXJ0L1Rlc3Q5MTckVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9s" + + "YW5nL09iamVjdAEAAygpVgEAC2FydC9UZXN0OTE3ACAABAAFAAAAAgABAAYABwAAAAEACAAHAAAA" + + "AgABAAkACgABAAsAAAAzAAIAAwAAAA8qtwABKiu1AAIqLLUAA7EAAAABAAwAAAASAAQAAAAJAAQA" + + "CgAJAAsADgAMAAEADQAOAAEACwAAAB0AAQABAAAABSq0AAOwAAAAAQAMAAAABgABAAAADwACAA8A" + + "AAACABAAFwAAAAoAAQAEABQAFgAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBdcPySAAAAAAAAAAAAAAAAAAAAAAAAAACQAwAAcAAAAHhWNBIAAAAAAAAAAMwCAAAS" + + "AAAAcAAAAAcAAAC4AAAAAwAAANQAAAACAAAA+AAAAAMAAAAIAQAAAQAAACABAABQAgAAQAEAAEAB" + + "AABIAQAASwEAAGQBAABzAQAAlwEAALcBAADLAQAA3wEAAO0BAAD4AQAA+wEAAAACAAANAgAAGAIA" + + "AB4CAAAlAgAALAIAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAoAAAABAAAABQAAAAAAAAAKAAAA" + + "BgAAAAAAAAALAAAABgAAADQCAAAAAAUADwAAAAAABQAQAAAAAAACAAAAAAAAAAAADQAAAAQAAQAA" + + "AAAAAAAAAAAAAAAEAAAAAAAAAAgAAAC8AgAAjAIAAAAAAAAGPGluaXQ+AAFMABdMYXJ0L1Rlc3Q5" + + "MTckVHJhbnNmb3JtOwANTGFydC9UZXN0OTE3OwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2lu" + + "Z0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABJMamF2YS9sYW5nL09iamVj" + + "dDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAMVGVzdDkxNy5qYXZhAAlUcmFuc2Zvcm0AAVYAA1ZMTAAL" + + "YWNjZXNzRmxhZ3MACWdldFJlc3VsdAAEbmFtZQAFdGFrZTEABXRha2UyAAV2YWx1ZQAAAgAAAAUA" + + "BQAJAgAABw4BAw8BAg8BAg8ADwAHDgAAAAADAAMAAQAAADwCAAAIAAAAcBACAAAAWwEAAFsCAQAO" + + "AAIAAQAAAAAATAIAAAMAAABUEAEAEQAAAAACAQEAAQEBAIGABNQEAQH0BAAAAgIBERgBAgMCDAQI" + + "DhcJAAIAAACgAgAApgIAALACAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAABIAAABw" + + "AAAAAgAAAAcAAAC4AAAAAwAAAAMAAADUAAAABAAAAAIAAAD4AAAABQAAAAMAAAAIAQAABgAAAAEA" + + "AAAgAQAAAiAAABIAAABAAQAAARAAAAEAAAA0AgAAAyAAAAIAAAA8AgAAASAAAAIAAABUAgAAACAA" + + "AAEAAACMAgAABCAAAAIAAACgAgAAAxAAAAEAAACwAgAABiAAAAEAAAC8AgAAABAAAAEAAADMAgAA"); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform("Hello", "Goodbye"), + new Transform("start", "end")); + } + + private static void printTransform(Transform t) { + System.out.println("Result is " + t.getResult()); + System.out.println("take1 is " + t.take1); + System.out.println("take2 is " + t.take2); + } + public static void doTest(Transform t1, Transform t2) { + printTransform(t1); + printTransform(t2); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + printTransform(t1); + printTransform(t2); + } +} diff --git a/test/919-obsolete-fields/src/Main.java b/test/919-obsolete-fields/src/Main.java index 34ee2a97f5..10eadb271e 100644 --- a/test/919-obsolete-fields/src/Main.java +++ b/test/919-obsolete-fields/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,135 +14,8 @@ * limitations under the License. */ -import java.util.function.Consumer; -import java.util.Base64; - public class Main { - - // What follows is the base64 encoded representation of the following class: - // - // import java.util.function.Consumer; - // - // class Transform { - // private Consumer<String> reporter; - // public Transform(Consumer<String> reporter) { - // this.reporter = reporter; - // } - // - // private void Start() { - // reporter.accept("Hello - private - Transformed"); - // } - // - // private void Finish() { - // reporter.accept("Goodbye - private - Transformed"); - // } - // - // public void sayHi(Runnable r) { - // reporter.accept("pre Start private method call - Transformed"); - // Start(); - // reporter.accept("post Start private method call - Transformed"); - // r.run(); - // reporter.accept("pre Finish private method call - Transformed"); - // Finish(); - // reporter.accept("post Finish private method call - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQANAoADgAfCQANACAIACELACIAIwgAJAgAJQoADQAmCAAnCwAoACkIACoKAA0AKwgA" + - "LAcALQcALgEACHJlcG9ydGVyAQAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsBAAlTaWdu" + - "YXR1cmUBADFMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyPExqYXZhL2xhbmcvU3RyaW5nOz47" + - "AQAGPGluaXQ+AQAgKExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7KVYBAARDb2RlAQAPTGlu" + - "ZU51bWJlclRhYmxlAQA0KExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI8TGphdmEvbGFuZy9T" + - "dHJpbmc7PjspVgEABVN0YXJ0AQADKClWAQAGRmluaXNoAQAFc2F5SGkBABcoTGphdmEvbGFuZy9S" + - "dW5uYWJsZTspVgEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwAEwAZDAAPABABAB1IZWxs" + - "byAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAcALwwAMAAxAQAfR29vZGJ5ZSAtIHByaXZhdGUgLSBU" + - "cmFuc2Zvcm1lZAEAK3ByZSBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQM" + - "ABgAGQEALHBvc3QgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkBwAyDAAz" + - "ABkBACxwcmUgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAwAGgAZAQAt" + - "cG9zdCBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkAQAJVHJhbnNmb3Jt" + - "AQAQamF2YS9sYW5nL09iamVjdAEAG2phdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcgEABmFjY2Vw" + - "dAEAFShMamF2YS9sYW5nL09iamVjdDspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgAgAA0A" + - "DgAAAAEAAgAPABAAAQARAAAAAgASAAQAAQATABQAAgAVAAAAKgACAAIAAAAKKrcAASortQACsQAA" + - "AAEAFgAAAA4AAwAAABUABAAWAAkAFwARAAAAAgAXAAIAGAAZAAEAFQAAACgAAgABAAAADCq0AAIS" + - "A7kABAIAsQAAAAEAFgAAAAoAAgAAABoACwAbAAIAGgAZAAEAFQAAACgAAgABAAAADCq0AAISBbkA" + - "BAIAsQAAAAEAFgAAAAoAAgAAAB4ACwAfAAEAGwAcAAEAFQAAAG8AAgACAAAAOyq0AAISBrkABAIA" + - "KrcAByq0AAISCLkABAIAK7kACQEAKrQAAhIKuQAEAgAqtwALKrQAAhIMuQAEAgCxAAAAAQAWAAAA" + - "IgAIAAAAIgALACMADwAkABoAJQAgACYAKwAnAC8AKAA6ACkAAQAdAAAAAgAe"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAw/b59wCwTlSVDmuhPEezuK3oe0rtT4ujMBQAAcAAAAHhWNBIAAAAAAAAAAAgFAAAd" + - "AAAAcAAAAAYAAADkAAAABAAAAPwAAAABAAAALAEAAAcAAAA0AQAAAQAAAGwBAABABAAAjAEAAJoC" + - "AACdAgAAoAIAAKgCAACsAgAAsgIAALoCAADbAgAA+gIAAAcDAAAmAwAAOgMAAFADAABkAwAAggMA" + - "AKEDAACoAwAAuAMAALsDAAC/AwAAxwMAANsDAAAKBAAAOAQAAGYEAACTBAAAnQQAAKIEAACpBAAA" + - "CAAAAAkAAAAKAAAACwAAAA4AAAARAAAAEQAAAAUAAAAAAAAAEgAAAAUAAACEAgAAEgAAAAUAAACM" + - "AgAAEgAAAAUAAACUAgAAAAAEABkAAAAAAAMAAgAAAAAAAAAFAAAAAAAAAA8AAAAAAAIAGwAAAAIA" + - "AAACAAAAAwAAABoAAAAEAAEAEwAAAAAAAAAAAAAAAgAAAAAAAAAQAAAAZAIAAO8EAAAAAAAAAQAA" + - "ANEEAAABAAAA3wQAAAIAAgABAAAAsAQAAAYAAABwEAQAAABbAQAADgADAAEAAgAAALgEAAAJAAAA" + - "VCAAABsBBgAAAHIgBgAQAA4AAAADAAEAAgAAAL4EAAAJAAAAVCAAABsBBwAAAHIgBgAQAA4AAAAE" + - "AAIAAgAAAMQEAAAqAAAAVCAAABsBGAAAAHIgBgAQAHAQAgACAFQgAAAbARYAAAByIAYAEAByEAUA" + - "AwBUIAAAGwEXAAAAciAGABAAcBABAAIAVCAAABsBFQAAAHIgBgAQAA4AAAAAAAEAAAABAAAAAAAA" + - "AAAAAACMAQAAAAAAAJQBAAABAAAAAgAAAAEAAAADAAAAAQAAAAQAASgAATwABjxpbml0PgACPjsA" + - "BD47KVYABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVsbG8gLSBw" + - "cml2YXRlIC0gVHJhbnNmb3JtZWQAC0xUcmFuc2Zvcm07AB1MZGFsdmlrL2Fubm90YXRpb24vU2ln" + - "bmF0dXJlOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEv" + - "bGFuZy9TdHJpbmc7ABxMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAB1MamF2YS91dGlsL2Z1" + - "bmN0aW9uL0NvbnN1bWVyOwAFU3RhcnQADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAAGYWNjZXB0ABJl" + - "bWl0dGVyOiBqYWNrLTQuMTkALXBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFu" + - "c2Zvcm1lZAAscG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALHBy" + - "ZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkACtwcmUgU3RhcnQgcHJp" + - "dmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkAAhyZXBvcnRlcgADcnVuAAVzYXlIaQAFdmFs" + - "dWUAFQEABw48LQAeAAcOhwAaAAcOhwAiAQAHDoc8hzyHPIcAAgEBHBwEFw0XARcMFwMCAQEcHAUX" + - "ABcNFwEXDBcEAAEDAQACAIGABJwDAQK4AwEC3AMDAYAEABAAAAAAAAAAAQAAAAAAAAABAAAAHQAA" + - "AHAAAAACAAAABgAAAOQAAAADAAAABAAAAPwAAAAEAAAAAQAAACwBAAAFAAAABwAAADQBAAAGAAAA" + - "AQAAAGwBAAADEAAAAgAAAIwBAAABIAAABAAAAJwBAAAGIAAAAQAAAGQCAAABEAAAAwAAAIQCAAAC" + - "IAAAHQAAAJoCAAADIAAABAAAALAEAAAEIAAAAgAAANEEAAAAIAAAAQAAAO8EAAAAEAAAAQAAAAgF" + - "AAA="); - - // A class that we can use to keep track of the output of this test. - private static class TestWatcher implements Consumer<String> { - private StringBuilder sb; - public TestWatcher() { - sb = new StringBuilder(); - } - - @Override - public void accept(String s) { - sb.append(s); - sb.append('\n'); - } - - public String getOutput() { - return sb.toString(); - } - } - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - TestWatcher w = new TestWatcher(); - doTest(new Transform(w), w); + public static void main(String[] args) throws Exception { + art.Test919.run(); } - - private static boolean interpreting = true; - private static boolean retry = false; - - public static void doTest(Transform t, TestWatcher w) { - Runnable do_redefinition = () -> { - w.accept("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }; - // This just prints something out to show we are running the Runnable. - Runnable say_nothing = () -> { w.accept("Not doing anything here"); }; - - // Try and redefine. - t.sayHi(say_nothing); - t.sayHi(do_redefinition); - t.sayHi(say_nothing); - - // Print output of last run. - System.out.print(w.getOutput()); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/919-obsolete-fields/src/Transform.java b/test/919-obsolete-fields/src/Transform.java deleted file mode 100644 index c8e3cbd934..0000000000 --- a/test/919-obsolete-fields/src/Transform.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -import java.util.function.Consumer; - -class Transform { - private Consumer<String> reporter; - public Transform(Consumer<String> reporter) { - this.reporter = reporter; - } - - private void Start() { - reporter.accept("hello - private"); - } - - private void Finish() { - reporter.accept("goodbye - private"); - } - - public void sayHi(Runnable r) { - reporter.accept("Pre Start private method call"); - Start(); - reporter.accept("Post Start private method call"); - r.run(); - reporter.accept("Pre Finish private method call"); - Finish(); - reporter.accept("Post Finish private method call"); - } -} diff --git a/test/919-obsolete-fields/src/art/Redefinition.java b/test/919-obsolete-fields/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/919-obsolete-fields/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/919-obsolete-fields/src/art/Test919.java b/test/919-obsolete-fields/src/art/Test919.java new file mode 100644 index 0000000000..11971ef2e8 --- /dev/null +++ b/test/919-obsolete-fields/src/art/Test919.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.function.Consumer; +import java.util.Base64; + +public class Test919 { + + static class Transform { + private Consumer<String> reporter; + public Transform(Consumer<String> reporter) { + this.reporter = reporter; + } + + private void Start() { + reporter.accept("hello - private"); + } + + private void Finish() { + reporter.accept("goodbye - private"); + } + + public void sayHi(Runnable r) { + reporter.accept("Pre Start private method call"); + Start(); + reporter.accept("Post Start private method call"); + r.run(); + reporter.accept("Pre Finish private method call"); + Finish(); + reporter.accept("Post Finish private method call"); + } + } + + + // What follows is the base64 encoded representation of the following class: + // + // import java.util.function.Consumer; + // + // static class Transform { + // private Consumer<String> reporter; + // public Transform(Consumer<String> reporter) { + // this.reporter = reporter; + // } + // + // private void Start() { + // reporter.accept("Hello - private - Transformed"); + // } + // + // private void Finish() { + // reporter.accept("Goodbye - private - Transformed"); + // } + // + // public void sayHi(Runnable r) { + // reporter.accept("pre Start private method call - Transformed"); + // Start(); + // reporter.accept("post Start private method call - Transformed"); + // r.run(); + // reporter.accept("pre Finish private method call - Transformed"); + // Finish(); + // reporter.accept("post Finish private method call - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAOAoADgAfCQANACAIACELACIAIwgAJAgAJQoADQAmCAAnCwAoACkIACoKAA0AKwgA" + + "LAcALgcAMQEACHJlcG9ydGVyAQAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsBAAlTaWdu" + + "YXR1cmUBADFMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyPExqYXZhL2xhbmcvU3RyaW5nOz47" + + "AQAGPGluaXQ+AQAgKExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7KVYBAARDb2RlAQAPTGlu" + + "ZU51bWJlclRhYmxlAQA0KExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI8TGphdmEvbGFuZy9T" + + "dHJpbmc7PjspVgEABVN0YXJ0AQADKClWAQAGRmluaXNoAQAFc2F5SGkBABcoTGphdmEvbGFuZy9S" + + "dW5uYWJsZTspVgEAClNvdXJjZUZpbGUBAAxUZXN0OTE5LmphdmEMABMAGQwADwAQAQAdSGVsbG8g" + + "LSBwcml2YXRlIC0gVHJhbnNmb3JtZWQHADIMADMANAEAH0dvb2RieWUgLSBwcml2YXRlIC0gVHJh" + + "bnNmb3JtZWQBACtwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAY" + + "ABkBACxwb3N0IFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcANQwANgAZ" + + "AQAscHJlIEZpbmlzaCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQMABoAGQEALXBv" + + "c3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcANwEAFWFydC9UZXN0" + + "OTE5JFRyYW5zZm9ybQEACVRyYW5zZm9ybQEADElubmVyQ2xhc3NlcwEAEGphdmEvbGFuZy9PYmpl" + + "Y3QBABtqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXIBAAZhY2NlcHQBABUoTGphdmEvbGFuZy9P" + + "YmplY3Q7KVYBABJqYXZhL2xhbmcvUnVubmFibGUBAANydW4BAAthcnQvVGVzdDkxOQAgAA0ADgAA" + + "AAEAAgAPABAAAQARAAAAAgASAAQAAQATABQAAgAVAAAAKgACAAIAAAAKKrcAASortQACsQAAAAEA" + + "FgAAAA4AAwAAAAgABAAJAAkACgARAAAAAgAXAAIAGAAZAAEAFQAAACgAAgABAAAADCq0AAISA7kA" + + "BAIAsQAAAAEAFgAAAAoAAgAAAA0ACwAOAAIAGgAZAAEAFQAAACgAAgABAAAADCq0AAISBbkABAIA" + + "sQAAAAEAFgAAAAoAAgAAABEACwASAAEAGwAcAAEAFQAAAG8AAgACAAAAOyq0AAISBrkABAIAKrcA" + + "Byq0AAISCLkABAIAK7kACQEAKrQAAhIKuQAEAgAqtwALKrQAAhIMuQAEAgCxAAAAAQAWAAAAIgAI" + + "AAAAFQALABYADwAXABoAGAAgABkAKwAaAC8AGwA6ABwAAgAdAAAAAgAeADAAAAAKAAEADQAtAC8A" + + "CA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBeEZYBAAAAAAAAAAAAAAAAAAAAAAAAAACMBgAAcAAAAHhWNBIAAAAAAAAAAMgFAAAi" + + "AAAAcAAAAAkAAAD4AAAABAAAABwBAAABAAAATAEAAAcAAABUAQAAAQAAAIwBAADgBAAArAEAAKwB" + + "AACvAQAAsgEAALoBAAC+AQAAxAEAAMwBAADtAQAADAIAACUCAAA0AgAAWAIAAHgCAACXAgAAqwIA" + + "AMECAADVAgAA8wIAABIDAAAZAwAAJwMAADIDAAA1AwAAOQMAAEEDAABOAwAAVAMAAIMDAACxAwAA" + + "3wMAAAwEAAAWBAAAGwQAACIEAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAAEQAAABUAAAAV" + + "AAAACAAAAAAAAAAWAAAACAAAADQEAAAWAAAACAAAADwEAAAWAAAACAAAACwEAAAAAAcAHgAAAAAA" + + "AwACAAAAAAAAAAUAAAAAAAAAEgAAAAAAAgAgAAAABQAAAAIAAAAGAAAAHwAAAAcAAQAXAAAAAAAA" + + "AAAAAAAFAAAAAAAAABMAAACoBQAARAUAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmlu" + + "aXNoAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkAB1IZWxsbyAtIHByaXZhdGUgLSBU" + + "cmFuc2Zvcm1lZAAXTGFydC9UZXN0OTE5JFRyYW5zZm9ybTsADUxhcnQvVGVzdDkxOTsAIkxkYWx2" + + "aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNs" + + "YXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAU" + + "TGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAcTGphdmEvdXRpbC9mdW5j" + + "dGlvbi9Db25zdW1lcgAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsABVN0YXJ0AAxUZXN0" + + "OTE5LmphdmEACVRyYW5zZm9ybQABVgACVkwABmFjY2VwdAALYWNjZXNzRmxhZ3MABG5hbWUALXBv" + + "c3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAscG9zdCBTdGFydCBw" + + "cml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALHByZSBGaW5pc2ggcHJpdmF0ZSBtZXRo" + + "b2QgY2FsbCAtIFRyYW5zZm9ybWVkACtwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRy" + + "YW5zZm9ybWVkAAhyZXBvcnRlcgADcnVuAAVzYXlIaQAFdmFsdWUAAAAAAQAAAAcAAAABAAAABQAA" + + "AAEAAAAGAAAACAEABw4BAw8BAg8AEQAHDgEIDwANAAcOAQgPABUBAAcOAQgPAQMPAQgPAQMPAQgP" + + "AQMPAQgPAAACAAIAAQAAAEQEAAAGAAAAcBAEAAAAWwEAAA4AAwABAAIAAABQBAAACQAAAFQgAAAb" + + "AQYAAAByIAYAEAAOAAAAAwABAAIAAABYBAAACQAAAFQgAAAbAQcAAAByIAYAEAAOAAAABAACAAIA" + + "AABgBAAAKgAAAFQgAAAbAR0AAAByIAYAEABwEAIAAgBUIAAAGwEbAAAAciAGABAAchAFAAMAVCAA" + + "ABsBHAAAAHIgBgAQAHAQAQACAFQgAAAbARoAAAByIAYAEAAOAAABAwEAAgCBgAT8CAECmAkBArwJ" + + "AwHgCQICASEYAQIDAhgECBkXFAIEASEcBBcQFwEXDxcDAgQBIRwFFwAXEBcBFw8XBAAAAAIAAABc" + + "BQAAYgUAAAEAAABrBQAAAQAAAHkFAACMBQAAAQAAAAEAAAAAAAAAAAAAAJgFAAAAAAAAoAUAABAA" + + "AAAAAAAAAQAAAAAAAAABAAAAIgAAAHAAAAACAAAACQAAAPgAAAADAAAABAAAABwBAAAEAAAAAQAA" + + "AEwBAAAFAAAABwAAAFQBAAAGAAAAAQAAAIwBAAACIAAAIgAAAKwBAAABEAAAAwAAACwEAAADIAAA" + + "BAAAAEQEAAABIAAABAAAAHwEAAAAIAAAAQAAAEQFAAAEIAAABAAAAFwFAAADEAAAAwAAAIwFAAAG" + + "IAAAAQAAAKgFAAAAEAAAAQAAAMgFAAA="); + + // A class that we can use to keep track of the output of this test. + private static class TestWatcher implements Consumer<String> { + private StringBuilder sb; + public TestWatcher() { + sb = new StringBuilder(); + } + + @Override + public void accept(String s) { + sb.append(s); + sb.append('\n'); + } + + public String getOutput() { + return sb.toString(); + } + } + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + TestWatcher w = new TestWatcher(); + doTest(new Transform(w), w); + } + + public static void doTest(Transform t, TestWatcher w) { + Runnable do_redefinition = () -> { + w.accept("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }; + // This just prints something out to show we are running the Runnable. + Runnable say_nothing = () -> { w.accept("Not doing anything here"); }; + + // Try and redefine. + t.sayHi(say_nothing); + t.sayHi(do_redefinition); + t.sayHi(say_nothing); + + // Print output of last run. + System.out.print(w.getOutput()); + } +} diff --git a/test/921-hello-failure/src/Main.java b/test/921-hello-failure/src/Main.java index d9a49489f0..cfdcdc250f 100644 --- a/test/921-hello-failure/src/Main.java +++ b/test/921-hello-failure/src/Main.java @@ -14,12 +14,12 @@ * limitations under the License. */ -import java.util.ArrayList; +import art.Redefinition; +import java.util.Arrays; + public class Main { public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - Verification.doTest(new Transform()); NewName.doTest(new Transform()); DifferentAccess.doTest(new Transform()); @@ -37,40 +37,40 @@ public class Main { Unmodifiable.doTest(new Transform[] { new Transform(), }); } - // Transforms the class. This throws an exception if something goes wrong. - public static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile) throws Exception; - - public static void doMultiClassRedefinition(CommonClassDefinition... defs) throws Exception { - ArrayList<Class<?>> classes = new ArrayList<>(); - ArrayList<byte[]> class_files = new ArrayList<>(); - ArrayList<byte[]> dex_files = new ArrayList<>(); + // TODO Replace this shim with a better re-write of this test. + private static Redefinition.CommonClassDefinition mapCCD(CommonClassDefinition d) { + return new Redefinition.CommonClassDefinition(d.target, d.class_file_bytes, d.dex_file_bytes); + } - for (CommonClassDefinition d : defs) { - classes.add(d.target); - class_files.add(d.class_file_bytes); - dex_files.add(d.dex_file_bytes); - } - doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), - class_files.toArray(new byte[0][]), - dex_files.toArray(new byte[0][])); + private static Redefinition.CommonClassDefinition[] toCCDA(CommonClassDefinition[] ds) { + return Arrays.stream(ds).map(Main::mapCCD).toArray(Redefinition.CommonClassDefinition[]::new); } + public static void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile) throws Exception { + Redefinition.doCommonClassRedefinition(target, classfile, dexfile); + } + public static void doMultiClassRedefinition(CommonClassDefinition... defs) throws Exception { + Redefinition.doMultiClassRedefinition(toCCDA(defs)); + } public static void addMultiTransformationResults(CommonClassDefinition... defs) throws Exception { - for (CommonClassDefinition d : defs) { - addCommonTransformationResult(d.target.getCanonicalName(), - d.class_file_bytes, - d.dex_file_bytes); - } + Redefinition.addMultiTransformationResults(toCCDA(defs)); + } + public static void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles) throws Exception { + Redefinition.doCommonMultiClassRedefinition(targets, classfiles, dexfiles); + } + public static void doCommonClassRetransformation(Class<?>... target) throws Exception { + Redefinition.doCommonClassRetransformation(target); + } + public static void enableCommonRetransformation(boolean enable) { + Redefinition.enableCommonRetransformation(enable); + } + public static void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes) { + Redefinition.addCommonTransformationResult(target_name, class_bytes, dex_bytes); } - - public static native void doCommonMultiClassRedefinition(Class<?>[] targets, - byte[][] classfiles, - byte[][] dexfiles) throws Exception; - public static native void doCommonClassRetransformation(Class<?>... target) throws Exception; - public static native void enableCommonRetransformation(boolean enable); - public static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/921-hello-failure/src/art/Redefinition.java b/test/921-hello-failure/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/921-hello-failure/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/924-threads/expected.txt b/test/924-threads/expected.txt index 4c0f4eaa5b..1eb2e1bd52 100644 --- a/test/924-threads/expected.txt +++ b/test/924-threads/expected.txt @@ -1,10 +1,10 @@ currentThread OK -main +TestThread 5 false java.lang.ThreadGroup[name=main,maxpri=10] class dalvik.system.PathClassLoader -main +TestThread 5 false java.lang.ThreadGroup[name=main,maxpri=10] @@ -33,10 +33,11 @@ class dalvik.system.PathClassLoader e1 = ALIVE|WAITING_WITH_TIMEOUT|SLEEPING|WAITING 5 = ALIVE|RUNNABLE 2 = TERMINATED -[Thread[FinalizerDaemon,5,system], Thread[FinalizerWatchdogDaemon,5,system], Thread[HeapTaskDaemon,5,system], Thread[ReferenceQueueDaemon,5,system], Thread[Signal Catcher,5,system], Thread[main,5,main]] +[Thread[FinalizerDaemon,5,system], Thread[FinalizerWatchdogDaemon,5,system], Thread[HeapTaskDaemon,5,system], Thread[ReferenceQueueDaemon,5,system], Thread[TestThread,5,main], Thread[main,5,main]] JVMTI_ERROR_THREAD_NOT_ALIVE JVMTI_ERROR_THREAD_NOT_ALIVE Constructed thread -Thread(EventTestThread): start -Thread(EventTestThread): end +[] +[Thread(EventTestThread): start] +[Thread(EventTestThread): end] Thread joined diff --git a/test/924-threads/src/art/Test924.java b/test/924-threads/src/art/Test924.java index 160bf8ea67..5445939cbc 100644 --- a/test/924-threads/src/art/Test924.java +++ b/test/924-threads/src/art/Test924.java @@ -25,17 +25,35 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; public class Test924 { public static void run() throws Exception { Main.bindAgentJNIForClass(Test924.class); - doTest(); + + // Run the test on its own thread, so we have a known state for the "current" thread. + Thread t = new Thread("TestThread") { + @Override + public void run() { + try { + doTest(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + t.start(); + t.join(); } private static void doTest() throws Exception { Thread t1 = Thread.currentThread(); Thread t2 = getCurrentThread(); + // Need to adjust priority, as on-device this may be unexpected (and we prefer not + // to special-case this.) + t1.setPriority(5); + if (t1 != t2) { throw new RuntimeException("Expected " + t1 + " but got " + t2); } @@ -188,7 +206,32 @@ public class Test924 { } Collections.sort(threadList, THREAD_COMP); - System.out.println(threadList); + + List<Thread> expectedList = new ArrayList<>(); + Set<Thread> threadsFromTraces = Thread.getAllStackTraces().keySet(); + + expectedList.add(findThreadByName(threadsFromTraces, "FinalizerDaemon")); + expectedList.add(findThreadByName(threadsFromTraces, "FinalizerWatchdogDaemon")); + expectedList.add(findThreadByName(threadsFromTraces, "HeapTaskDaemon")); + expectedList.add(findThreadByName(threadsFromTraces, "ReferenceQueueDaemon")); + // We can't get the signal catcher through getAllStackTraces. So ignore it. + // expectedList.add(findThreadByName(threadsFromTraces, "Signal Catcher")); + expectedList.add(findThreadByName(threadsFromTraces, "TestThread")); + expectedList.add(findThreadByName(threadsFromTraces, "main")); + + if (!threadList.containsAll(expectedList)) { + throw new RuntimeException("Expected " + expectedList + " as subset, got " + threadList); + } + System.out.println(expectedList); + } + + private static Thread findThreadByName(Set<Thread> threads, String name) { + for (Thread t : threads) { + if (t.getName().equals(name)) { + return t; + } + } + throw new RuntimeException("Did not find thread " + name + ": " + threads); } private static void doTLSTests() throws Exception { @@ -256,13 +299,35 @@ public class Test924 { private static void doTestEvents() throws Exception { enableThreadEvents(true); - Thread t = new Thread("EventTestThread"); + final CountDownLatch cdl1 = new CountDownLatch(1); + final CountDownLatch cdl2 = new CountDownLatch(1); + + Runnable r = new Runnable() { + @Override + public void run() { + try { + cdl1.countDown(); + cdl2.await(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + Thread t = new Thread(r, "EventTestThread"); System.out.println("Constructed thread"); Thread.yield(); + Thread.sleep(100); + System.out.println(Arrays.toString(getThreadEventMessages())); t.start(); + cdl1.await(); + + System.out.println(Arrays.toString(getThreadEventMessages())); + + cdl2.countDown(); t.join(); + System.out.println(Arrays.toString(getThreadEventMessages())); System.out.println("Thread joined"); @@ -337,4 +402,5 @@ public class Test924 { private static native void setTLS(Thread t, long l); private static native long getTLS(Thread t); private static native void enableThreadEvents(boolean b); + private static native String[] getThreadEventMessages(); } diff --git a/test/924-threads/threads.cc b/test/924-threads/threads.cc index 701ab1def3..e21dcc240e 100644 --- a/test/924-threads/threads.cc +++ b/test/924-threads/threads.cc @@ -16,6 +16,10 @@ #include <stdio.h> +#include <mutex> +#include <string> +#include <vector> + #include "android-base/logging.h" #include "android-base/stringprintf.h" #include "jni.h" @@ -139,17 +143,27 @@ extern "C" JNIEXPORT void JNICALL Java_art_Test924_setTLS( JvmtiErrorToException(env, jvmti_env, result); } +static std::mutex gEventsMutex; +static std::vector<std::string> gEvents; + static void JNICALL ThreadEvent(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread, bool is_start) { jvmtiThreadInfo info; - jvmtiError result = jvmti_env->GetThreadInfo(thread, &info); - if (result != JVMTI_ERROR_NONE) { - printf("Error getting thread info"); - return; + { + std::lock_guard<std::mutex> guard(gEventsMutex); + + jvmtiError result = jvmti_env->GetThreadInfo(thread, &info); + if (result != JVMTI_ERROR_NONE) { + gEvents.push_back("Error getting thread info"); + return; + } + + gEvents.push_back(android::base::StringPrintf("Thread(%s): %s", + info.name, + is_start ? "start" : "end")); } - printf("Thread(%s): %s\n", info.name, is_start ? "start" : "end"); jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(info.name)); jni_env->DeleteLocalRef(info.thread_group); @@ -205,5 +219,18 @@ extern "C" JNIEXPORT void JNICALL Java_art_Test924_enableThreadEvents( JvmtiErrorToException(env, jvmti_env, ret); } +extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test924_getThreadEventMessages( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) { + std::lock_guard<std::mutex> guard(gEventsMutex); + jobjectArray ret = CreateObjectArray(env, + static_cast<jint>(gEvents.size()), + "java/lang/String", + [&](jint i) { + return env->NewStringUTF(gEvents[i].c_str()); + }); + gEvents.clear(); + return ret; +} + } // namespace Test924Threads } // namespace art diff --git a/test/926-multi-obsolescence/src/Main.java b/test/926-multi-obsolescence/src/Main.java index 2440908c07..8e21b8f633 100644 --- a/test/926-multi-obsolescence/src/Main.java +++ b/test/926-multi-obsolescence/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,115 +14,8 @@ * limitations under the License. */ -import java.util.ArrayList; -import java.util.Base64; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static CommonClassDefinition VALID_DEFINITION_T1 = new CommonClassDefinition( - Transform.class, - Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" + - "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"), - Base64.getDecoder().decode( - "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA=")); - // class Transform2 { - // public void sayHi(Runnable r) { - // System.out.println("Hello 2 - Transformed"); - // r.run(); - // System.out.println("Goodbye 2 - Transformed"); - // } - // } - private static CommonClassDefinition VALID_DEFINITION_T2 = new CommonClassDefinition( - Transform2.class, - Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAPVHJhbnNmb3JtMi5qYXZhDAAJAAoHABwMAB0AHgEAFUhlbGxvIDIg" + - "LSBUcmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABdHb29kYnllIDIgLSBUcmFuc2Zvcm1lZAEA" + - "ClRyYW5zZm9ybTIBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEA" + - "FUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAV" + - "KExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAA" + - "AAACAAAACQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsA" + - "AAA7AAIAAgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4A" + - "BQAWAAYAAQAPAAAAAgAQ"), - Base64.getDecoder().decode( - "ZGV4CjAzNQCee5Z6+AuFcjnPjjn7QYgZmKSmFQCO4nxUAwAAcAAAAHhWNBIAAAAAAAAAALQCAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAQAgAARAEAAKIB" + - "AACqAQAAwwEAANoBAADoAQAA/wEAABMCAAApAgAAPQIAAFECAABiAgAAZQIAAGkCAAB9AgAAggIA" + - "AIsCAACQAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAKUCAAAAAAAAAQABAAEAAACXAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACcAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AF0dvb2RieWUgMiAtIFRyYW5zZm9ybWVkABVIZWxs" + - "byAyIC0gVHJhbnNmb3JtZWQADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJM" + - "amF2YS9sYW5nL09iamVjdDsAFExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmlu" + - "ZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwAPVHJhbnNmb3JtMi5qYXZhAAFWAAJWTAASZW1pdHRlcjog" + - "amFjay00LjIwAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICA" + - "BMQCAQHcAgANAAAAAAAAAAEAAAAAAAAAAQAAABEAAABwAAAAAgAAAAcAAAC0AAAAAwAAAAMAAADQ" + - "AAAABAAAAAEAAAD0AAAABQAAAAUAAAD8AAAABgAAAAEAAAAkAQAAASAAAAIAAABEAQAAARAAAAIA" + - "AACUAQAAAiAAABEAAACiAQAAAyAAAAIAAACXAgAAACAAAAEAAAClAgAAABAAAAEAAAC0AgAA")); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform(), new Transform2()); - } - - public static void doTest(final Transform t1, final Transform2 t2) { - t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); }); - t1.sayHi(() -> { - t2.sayHi(() -> { - System.out.println("transforming calling functions"); - doMultiClassRedefinition(VALID_DEFINITION_T1, VALID_DEFINITION_T2); - }); - }); - t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); }); + public static void main(String[] args) throws Exception { + art.Test926.run(); } - - public static void doMultiClassRedefinition(CommonClassDefinition... defs) { - ArrayList<Class<?>> classes = new ArrayList<>(); - ArrayList<byte[]> class_files = new ArrayList<>(); - ArrayList<byte[]> dex_files = new ArrayList<>(); - - for (CommonClassDefinition d : defs) { - classes.add(d.target); - class_files.add(d.class_file_bytes); - dex_files.add(d.dex_file_bytes); - } - doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), - class_files.toArray(new byte[0][]), - dex_files.toArray(new byte[0][])); - } - - public static native void doCommonMultiClassRedefinition(Class<?>[] targets, - byte[][] classfiles, - byte[][] dexfiles); } diff --git a/test/926-multi-obsolescence/src/Transform.java b/test/926-multi-obsolescence/src/Transform.java deleted file mode 100644 index 8cda6cdf53..0000000000 --- a/test/926-multi-obsolescence/src/Transform.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Hello" < "LTransform;" < "hello". - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/926-multi-obsolescence/src/Transform2.java b/test/926-multi-obsolescence/src/Transform2.java deleted file mode 100644 index 4877f8455b..0000000000 --- a/test/926-multi-obsolescence/src/Transform2.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform2 { - public void sayHi(Runnable r) { - System.out.println("hello - 2"); - r.run(); - System.out.println("goodbye - 2"); - } -} diff --git a/test/926-multi-obsolescence/src/art/Redefinition.java b/test/926-multi-obsolescence/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/926-multi-obsolescence/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/926-multi-obsolescence/src/art/Test926.java b/test/926-multi-obsolescence/src/art/Test926.java new file mode 100644 index 0000000000..843d05c3fc --- /dev/null +++ b/test/926-multi-obsolescence/src/art/Test926.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import static art.Redefinition.CommonClassDefinition; +import java.util.ArrayList; +import java.util.Base64; + +public class Test926 { + + static class Transform { + public void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + + static class Transform2 { + public void sayHi(Runnable r) { + System.out.println("hello - 2"); + r.run(); + System.out.println("goodbye - 2"); + } + } + // static class Transform { + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static CommonClassDefinition VALID_DEFINITION_T1 = new CommonClassDefinition( + Transform.class, + Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDkyNi5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5MjYkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTI2ACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAADAABAA0ADgABAAsAAAA7AAIAAgAA" + + "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAA4ACAAPAA4AEAAWABEAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="), + Base64.getDecoder().decode( + "ZGV4CjAzNQB8m+R/AAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5MjYkVHJhbnNmb3JtOwANTGFydC9UZXN0OTI2OwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTI2LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAMAAcOAA4BAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA==")); + // static class Transform2 { + // public void sayHi(Runnable r) { + // System.out.println("Hello 2 - Transformed"); + // r.run(); + // System.out.println("Goodbye 2 - Transformed"); + // } + // } + private static CommonClassDefinition VALID_DEFINITION_T2 = new CommonClassDefinition( + Transform2.class, + Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDkyNi5qYXZhDAAJAAoHAB8MACAAIQEAFUhlbGxvIDIgLSBU" + + "cmFuc2Zvcm1lZAcAIgwAIwAkBwAlDAAmAAoBABdHb29kYnllIDIgLSBUcmFuc2Zvcm1lZAcAJwEA" + + "FmFydC9UZXN0OTI2JFRyYW5zZm9ybTIBAApUcmFuc2Zvcm0yAQAMSW5uZXJDbGFzc2VzAQAQamF2" + + "YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0" + + "cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmlu" + + "ZzspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTI2ACAABwAIAAAAAAAC" + + "AAAACQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7" + + "AAIAAgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAW" + + "AAoAAgAPAAAAAgAQAB0AAAAKAAEABwAaABwACA=="), + Base64.getDecoder().decode( + "ZGV4CjAzNQBCnaUuAAAAAAAAAAAAAAAAAAAAAAAAAABABAAAcAAAAHhWNBIAAAAAAAAAAHwDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADYAgAAaAEAAGgB" + + "AABwAQAAiQEAAKABAAC6AQAAyQEAAO0BAAANAgAAJAIAADgCAABOAgAAYgIAAHYCAACEAgAAkAIA" + + "AJMCAACXAgAApAIAAKoCAACvAgAAuAIAAL0CAADEAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAzAIAAA8AAAAJAAAA1AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAbAMAAEADAAAAAAAABjxpbml0PgAXR29vZGJ5ZSAyIC0gVHJhbnNmb3JtZWQAFUhlbGxv" + + "IDIgLSBUcmFuc2Zvcm1lZAAYTGFydC9UZXN0OTI2JFRyYW5zZm9ybTI7AA1MYXJ0L1Rlc3Q5MjY7" + + "ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24v" + + "SW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABRM" + + "amF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3Rl" + + "bTsADFRlc3Q5MjYuamF2YQAKVHJhbnNmb3JtMgABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANv" + + "dXQAB3ByaW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAABAAAABgAAAAEAAAAHAAAABQAHDgAHAQAH" + + "DgEIDwEDDwEIDwABAAEAAQAAANwCAAAEAAAAcBADAAAADgAEAAIAAgAAAOECAAAUAAAAYgAAABsB" + + "AgAAAG4gAgAQAHIQBAADAGIAAAAbAQEAAABuIAIAEAAOAAAAAQEAgIAE8AUBAYgGAAACAgEWGAEC" + + "AwIQBAgRFw0AAgAAAFADAABWAwAAYAMAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAA" + + "FwAAAHAAAAACAAAACgAAAMwAAAADAAAAAwAAAPQAAAAEAAAAAQAAABgBAAAFAAAABQAAACABAAAG" + + "AAAAAQAAAEgBAAACIAAAFwAAAGgBAAABEAAAAgAAAMwCAAADIAAAAgAAANwCAAABIAAAAgAAAPAC" + + "AAAAIAAAAQAAAEADAAAEIAAAAgAAAFADAAADEAAAAQAAAGADAAAGIAAAAQAAAGwDAAAAEAAAAQAA" + + "AHwDAAA=")); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform(), new Transform2()); + } + + public static void doTest(final Transform t1, final Transform2 t2) throws Exception { + t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); }); + t1.sayHi(() -> { + t2.sayHi(() -> { + System.out.println("transforming calling functions"); + Redefinition.doMultiClassRedefinition(VALID_DEFINITION_T1, VALID_DEFINITION_T2); + }); + }); + t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); }); + } +} diff --git a/test/930-hello-retransform/src/Main.java b/test/930-hello-retransform/src/Main.java index da59c7440b..38c1d363b6 100644 --- a/test/930-hello-retransform/src/Main.java +++ b/test/930-hello-retransform/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,57 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test930.run(); } - - public static void doTest(Transform t) { - t.sayHi(); - addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); - t.sayHi(); - } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/930-hello-retransform/src/Transform.java b/test/930-hello-retransform/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/930-hello-retransform/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/930-hello-retransform/src/art/Redefinition.java b/test/930-hello-retransform/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/930-hello-retransform/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/930-hello-retransform/src/art/Test930.java b/test/930-hello-retransform/src/art/Test930.java new file mode 100644 index 0000000000..6c0fc16dad --- /dev/null +++ b/test/930-hello-retransform/src/art/Test930.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +public class Test930 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); + } + } + + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTMwLmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5MzAkVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTMwACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBsgu9qAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTMwJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkzMDsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTMwLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(); + Redefinition.addCommonTransformationResult("art/Test930$Transform", CLASS_BYTES, DEX_BYTES); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); + t.sayHi(); + } +} diff --git a/test/932-transform-saves/src/Main.java b/test/932-transform-saves/src/Main.java index 14e5da0d91..fba40f6828 100644 --- a/test/932-transform-saves/src/Main.java +++ b/test/932-transform-saves/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,103 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("hello"); - * } - * } - */ - private static final byte[] CLASS_BYTES_A = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" + - "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" + - "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAgAAUABgAA" + - "AAAAAgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" + - "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN"); - private static final byte[] DEX_BYTES_A = Base64.getDecoder().decode( - "ZGV4CjAzNQC6XWInnnDd1H4NdQ3P3inH8eCVmQI6W7LMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" + - "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" + - "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" + - "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" + - "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjIABWhlbGxvAANvdXQA" + - "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCAgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA="); - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] CLASS_BYTES_B = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="); - private static final byte[] DEX_BYTES_B = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test932.run(); } - - public static void doTest(Transform t) { - // TODO We currently need to do this transform call since we don't have any way to make the - // original-dex-file a single-class dex-file letting us restore it easily. We should use the - // manipulation library that is being made when we store the original dex file. - // TODO REMOVE this theoretically does nothing but it ensures the original-dex-file we have set - // is one we can return to unaltered. - doCommonClassRedefinition(Transform.class, CLASS_BYTES_A, DEX_BYTES_A); - t.sayHi(); - - // Now turn it into DEX_BYTES_B so it says 'Goodbye' - addCommonTransformationResult("Transform", CLASS_BYTES_B, DEX_BYTES_B); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); - t.sayHi(); - - // Now turn it back to normal by removing the load-hook and transforming again. - enableCommonRetransformation(false); - doCommonClassRetransformation(Transform.class); - t.sayHi(); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_bytes, - byte[] dex_bytes); - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/932-transform-saves/src/Transform.java b/test/932-transform-saves/src/Transform.java deleted file mode 100644 index 83f7aa4b4d..0000000000 --- a/test/932-transform-saves/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("foobar"); - } -} diff --git a/test/932-transform-saves/src/art/Redefinition.java b/test/932-transform-saves/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/932-transform-saves/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/932-transform-saves/src/art/Test932.java b/test/932-transform-saves/src/art/Test932.java new file mode 100644 index 0000000000..3a622322aa --- /dev/null +++ b/test/932-transform-saves/src/art/Test932.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +public class Test932 { + + // This class is never used so just have it print out a bogus value so we can detect if something + // goes very wrong. + static class Transform { + public void sayHi() { + System.out.println("foobar"); + } + } + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("hello"); + * } + * } + */ + private static final byte[] CLASS_BYTES_A = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTMyLmphdmEMAAcA" + + "CAcAGQwAGgAbAQAFaGVsbG8HABwMAB0AHgcAHwEAFWFydC9UZXN0OTMyJFRyYW5zZm9ybQEACVRy" + + "YW5zZm9ybQEADElubmVyQ2xhc3NlcwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lz" + + "dGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEA" + + "B3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAthcnQvVGVzdDkzMgAgAAUABgAAAAAA" + + "AgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAAAUAAQALAAgAAQAJAAAA" + + "JQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAABwAIAAgAAgAMAAAAAgANABcAAAAKAAEA" + + "BQAUABYACA=="); + private static final byte[] DEX_BYTES_A = Base64.getDecoder().decode( + "ZGV4CjAzNQAngjnzAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAZQEAAHQBAACYAQAAuAEAAM8BAADjAQAA9wEAAAsCAAAZAgAAJAIAACcCAAArAgAAOAIA" + + "AD8CAABFAgAASgIAAFMCAABaAgAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAALAAAA" + + "CwAAAAgAAAAAAAAADAAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAJAAAA5AIAALgCAAAAAAAABjxpbml0PgAXTGFydC9UZXN0" + + "OTMyJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkzMjsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3Np" + + "bmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRT" + + "dHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFu" + + "Zy9TeXN0ZW07AAxUZXN0OTMyLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAAVo" + + "ZWxsbwAEbmFtZQADb3V0AAdwcmludGxuAAVzYXlIaQAFdmFsdWUAAAAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQ4A" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg0ECA8XCgACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES_B = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTMyLmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5MzIkVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTMyACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"); + private static final byte[] DEX_BYTES_B = Base64.getDecoder().decode( + "ZGV4CjAzNQByglN3AAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTMyJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkzMjsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTMyLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + // TODO We currently need to do this transform call since we don't have any way to make the + // original-dex-file a single-class dex-file letting us restore it easily. We should use the + // manipulation library that is being made when we store the original dex file. + // TODO REMOVE this theoretically does nothing but it ensures the original-dex-file we have set + // is one we can return to unaltered. + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES_A, DEX_BYTES_A); + t.sayHi(); + + // Now turn it into DEX_BYTES_B so it says 'Goodbye' + Redefinition.addCommonTransformationResult("art/Test932$Transform", CLASS_BYTES_B, DEX_BYTES_B); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); + t.sayHi(); + + // Now turn it back to normal by removing the load-hook and transforming again. + Redefinition.enableCommonRetransformation(false); + Redefinition.doCommonClassRetransformation(Transform.class); + t.sayHi(); + } +} diff --git a/test/934-load-transform/src/Main.java b/test/934-load-transform/src/Main.java index 606ce78a5b..69c839fdb2 100644 --- a/test/934-load-transform/src/Main.java +++ b/test/934-load-transform/src/Main.java @@ -14,6 +14,10 @@ * limitations under the License. */ +import static art.Redefinition.addCommonTransformationResult; +import static art.Redefinition.enableCommonRetransformation; +import static art.Redefinition.setPopRetransformations; + import java.lang.reflect.*; import java.util.Base64; @@ -86,11 +90,4 @@ class Main { e.printStackTrace(); } } - - private static native void setPopRetransformations(boolean should_pop); - // Transforms the class - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/934-load-transform/src/art/Redefinition.java b/test/934-load-transform/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/934-load-transform/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/935-non-retransformable/src/Main.java b/test/935-non-retransformable/src/Main.java index df92561784..f240224977 100644 --- a/test/935-non-retransformable/src/Main.java +++ b/test/935-non-retransformable/src/Main.java @@ -17,6 +17,8 @@ import java.lang.reflect.*; import java.util.Base64; +import art.Redefinition; + class Main { public static String TEST_NAME = "935-non-retransformable"; @@ -74,10 +76,9 @@ class Main { } public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - setPopRetransformations(false); - addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES); - enableCommonRetransformation(true); + Redefinition.setPopRetransformations(false); + Redefinition.addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES); + Redefinition.enableCommonRetransformation(true); try { /* this is the "alternate" DEX/Jar file */ ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION")); @@ -89,23 +90,14 @@ class Main { run_test.invoke(null); // Remove the original transformation. It has been used by now. - popTransformationFor("Transform"); + Redefinition.popTransformationFor("Transform"); // Make sure we don't get called for transformation again. - addCommonTransformationResult("Transform", new byte[0], new byte[0]); - doCommonClassRetransformation(new_loader.loadClass("Transform")); + Redefinition.addCommonTransformationResult("Transform", new byte[0], new byte[0]); + Redefinition.doCommonClassRetransformation(new_loader.loadClass("Transform")); run_test.invoke(null); } catch (Exception e) { System.out.println(e.toString()); e.printStackTrace(); } } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... classes); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); - private static native void setPopRetransformations(boolean should_pop); - private static native void popTransformationFor(String target_name); } diff --git a/test/935-non-retransformable/src/art/Redefinition.java b/test/935-non-retransformable/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/935-non-retransformable/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/937-hello-retransform-package/src/Main.java b/test/937-hello-retransform-package/src/Main.java index 866f75d5e6..eef56c2c34 100644 --- a/test/937-hello-retransform-package/src/Main.java +++ b/test/937-hello-retransform-package/src/Main.java @@ -17,6 +17,8 @@ import java.util.Base64; import testing.*; +import art.Redefinition; + public class Main { /** @@ -53,22 +55,14 @@ public class Main { "YgEAAAMgAAACAAAAGwIAAAAgAAABAAAAJgIAAAAQAAABAAAANAIAAA=="); public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); doTest(new Transform()); } public static void doTest(Transform t) { t.sayHi(); - addCommonTransformationResult("testing/Transform", CLASS_BYTES, DEX_BYTES); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); + Redefinition.addCommonTransformationResult("testing/Transform", CLASS_BYTES, DEX_BYTES); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); t.sayHi(); } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/937-hello-retransform-package/src/art/Redefinition.java b/test/937-hello-retransform-package/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/937-hello-retransform-package/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/938-load-transform-bcp/src/Main.java b/test/938-load-transform-bcp/src/Main.java index 21b841f06a..e560942729 100644 --- a/test/938-load-transform-bcp/src/Main.java +++ b/test/938-load-transform-bcp/src/Main.java @@ -14,6 +14,7 @@ * limitations under the License. */ +import static art.Redefinition.*; import java.lang.reflect.*; import java.util.Base64; @@ -114,11 +115,4 @@ class Main { e.printStackTrace(); } } - - private static native void setPopRetransformations(boolean should_pop); - // Transforms the class - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/938-load-transform-bcp/src/art/Redefinition.java b/test/938-load-transform-bcp/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/938-load-transform-bcp/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/939-hello-transformation-bcp/src/Main.java b/test/939-hello-transformation-bcp/src/Main.java index 0e1f845ab9..7bda667357 100644 --- a/test/939-hello-transformation-bcp/src/Main.java +++ b/test/939-hello-transformation-bcp/src/Main.java @@ -14,6 +14,7 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; import java.util.Base64; import java.util.OptionalLong; public class Main { @@ -110,7 +111,6 @@ public class Main { "AABHBgAABCAAAAIAAACVBgAAACAAAAEAAACtBgAAABAAAAEAAAD4BgAA"); public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); // OptionalLong is a class that is unlikely to be used by the time this test starts and is not // likely to be changed in any meaningful way in the future. OptionalLong ol = OptionalLong.of(0xDEADBEEF); @@ -119,9 +119,4 @@ public class Main { doCommonClassRedefinition(OptionalLong.class, CLASS_BYTES, DEX_BYTES); System.out.println("ol.toString() -> '" + ol.toString() + "'"); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/939-hello-transformation-bcp/src/art/Redefinition.java b/test/939-hello-transformation-bcp/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/939-hello-transformation-bcp/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/940-recursive-obsolete/src/Main.java b/test/940-recursive-obsolete/src/Main.java index 724f82de27..0b0211c2c3 100644 --- a/test/940-recursive-obsolete/src/Main.java +++ b/test/940-recursive-obsolete/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,77 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - - // class Transform { - // public void sayHi(int recur, Runnable r) { - // System.out.println("Hello" + recur + " - transformed"); - // if (recur == 1) { - // r.run(); - // sayHi(recur - 1, r); - // } else if (recur != 0) { - // sayHi(recur - 1, r); - // } - // System.out.println("Goodbye" + recur + " - transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQANwoADwAZCQAaABsHABwKAAMAGQgAHQoAAwAeCgADAB8IACAKAAMAIQoAIgAjCwAk" + - "ACUKAA4AJggAJwcAKAcAKQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + - "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADVN0YWNrTWFwVGFibGUBAApTb3Vy" + - "Y2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMABAAEQcAKgwAKwAsAQAXamF2YS9sYW5nL1N0cmluZ0J1" + - "aWxkZXIBAAVIZWxsbwwALQAuDAAtAC8BAA4gLSB0cmFuc2Zvcm1lZAwAMAAxBwAyDAAzADQHADUM" + - "ADYAEQwAFAAVAQAHR29vZGJ5ZQEACVRyYW5zZm9ybQEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZh" + - "L2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQAGYXBwZW5kAQAtKExq" + - "YXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAcKEkpTGphdmEvbGFu" + - "Zy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsBABNqYXZh" + - "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAEmphdmEv" + - "bGFuZy9SdW5uYWJsZQEAA3J1bgAgAA4ADwAAAAAAAgAAABAAEQABABIAAAAdAAEAAQAAAAUqtwAB" + - "sQAAAAEAEwAAAAYAAQAAAAEAAQAUABUAAQASAAAAnQADAAMAAABfsgACuwADWbcABBIFtgAGG7YA" + - "BxIItgAGtgAJtgAKGwSgABQsuQALAQAqGwRkLLYADKcADxuZAAsqGwRkLLYADLIAArsAA1m3AAQS" + - "DbYABhu2AAcSCLYABrYACbYACrEAAAACABMAAAAiAAgAAAADAB4ABAAjAAUAKQAGADQABwA4AAgA" + - "QAAKAF4ACwAWAAAABAACNAsAAQAXAAAAAgAY"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQA3pkIgnymz2/eri+mp2dyZo3jolQmaRPKEBAAAcAAAAHhWNBIAAAAAAAAAAOQDAAAa" + - "AAAAcAAAAAkAAADYAAAABgAAAPwAAAABAAAARAEAAAkAAABMAQAAAQAAAJQBAADQAgAAtAEAAJwC" + - "AACsAgAAtAIAAL0CAADEAgAAxwIAAMoCAADOAgAA0gIAAN8CAAD2AgAACgMAACADAAA0AwAATwMA" + - "AGMDAABzAwAAdgMAAHsDAAB/AwAAhwMAAJsDAACgAwAAqQMAAK4DAAC1AwAABAAAAAgAAAAJAAAA" + - "CgAAAAsAAAAMAAAADQAAAA4AAAAQAAAABQAAAAUAAAAAAAAABgAAAAYAAACEAgAABwAAAAYAAACM" + - "AgAAEAAAAAgAAAAAAAAAEQAAAAgAAACUAgAAEgAAAAgAAACMAgAABwACABUAAAABAAMAAQAAAAEA" + - "BAAYAAAAAgAFABYAAAADAAMAAQAAAAQAAwAXAAAABgADAAEAAAAGAAEAEwAAAAYAAgATAAAABgAA" + - "ABkAAAABAAAAAAAAAAMAAAAAAAAADwAAAAAAAADWAwAAAAAAAAEAAQABAAAAvwMAAAQAAABwEAMA" + - "AAAOAAYAAwADAAAAxAMAAFQAAABiAAAAIgEGAHAQBQABABsCAwAAAG4gBwAhAAwBbiAGAEEADAEb" + - "AgAAAABuIAcAIQAMAW4QCAABAAwBbiACABAAEhAzBCsAchAEAAUA2AAE/24wAQADBWIAAAAiAQYA" + - "cBAFAAEAGwICAAAAbiAHACEADAFuIAYAQQAMARsCAAAAAG4gBwAhAAwBbhAIAAEADAFuIAIAEAAO" + - "ADgE3//YAAT/bjABAAMFKNgBAAAAAAAAAAEAAAAFAAAAAgAAAAAABAAOIC0gdHJhbnNmb3JtZWQA" + - "Bjxpbml0PgAHR29vZGJ5ZQAFSGVsbG8AAUkAAUwAAkxJAAJMTAALTFRyYW5zZm9ybTsAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxl" + - "OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABJMamF2YS9s" + - "YW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAANWSUwAAlZMAAZhcHBlbmQAEmVtaXR0ZXI6" + - "IGphY2stNC4yNAADb3V0AAdwcmludGxuAANydW4ABXNheUhpAAh0b1N0cmluZwABAAcOAAMCAAAH" + - "DgEgDzw8XQEgDxktAAAAAQEAgIAEtAMBAcwDDQAAAAAAAAABAAAAAAAAAAEAAAAaAAAAcAAAAAIA" + - "AAAJAAAA2AAAAAMAAAAGAAAA/AAAAAQAAAABAAAARAEAAAUAAAAJAAAATAEAAAYAAAABAAAAlAEA" + - "AAEgAAACAAAAtAEAAAEQAAADAAAAhAIAAAIgAAAaAAAAnAIAAAMgAAACAAAAvwMAAAAgAAABAAAA" + - "1gMAAAAQAAABAAAA5AMAAA=="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test940.run(); } - - public static void doTest(Transform t) { - t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); - t.sayHi(2, () -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/940-recursive-obsolete/src/Transform.java b/test/940-recursive-obsolete/src/Transform.java deleted file mode 100644 index 97522cddf6..0000000000 --- a/test/940-recursive-obsolete/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(int recur, Runnable r) { - System.out.println("hello" + recur); - if (recur == 1) { - r.run(); - sayHi(recur - 1, r); - } else if (recur != 0) { - sayHi(recur - 1, r); - } - System.out.println("goodbye" + recur); - } -} diff --git a/test/940-recursive-obsolete/src/art/Redefinition.java b/test/940-recursive-obsolete/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/940-recursive-obsolete/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/940-recursive-obsolete/src/art/Test940.java b/test/940-recursive-obsolete/src/art/Test940.java new file mode 100644 index 0000000000..d67d7726da --- /dev/null +++ b/test/940-recursive-obsolete/src/art/Test940.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test940 { + + static class Transform { + public void sayHi(int recur, Runnable r) { + System.out.println("hello" + recur); + if (recur == 1) { + r.run(); + sayHi(recur - 1, r); + } else if (recur != 0) { + sayHi(recur - 1, r); + } + System.out.println("goodbye" + recur); + } + } + + + // static class Transform { + // public void sayHi(int recur, Runnable r) { + // System.out.println("Hello" + recur + " - transformed"); + // if (recur == 1) { + // r.run(); + // sayHi(recur - 1, r); + // } else if (recur != 0) { + // sayHi(recur - 1, r); + // } + // System.out.println("Goodbye" + recur + " - transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAOwoADwAZCQAaABsHABwKAAMAGQgAHQoAAwAeCgADAB8IACAKAAMAIQoAIgAjCwAk" + + "ACUKAA4AJggAJwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + + "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADVN0YWNrTWFwVGFibGUBAApTb3Vy" + + "Y2VGaWxlAQAMVGVzdDk0MC5qYXZhDAAQABEHAC0MAC4ALwEAF2phdmEvbGFuZy9TdHJpbmdCdWls" + + "ZGVyAQAFSGVsbG8MADAAMQwAMAAyAQAOIC0gdHJhbnNmb3JtZWQMADMANAcANQwANgA3BwA4DAA5" + + "ABEMABQAFQEAB0dvb2RieWUHADoBABVhcnQvVGVzdDk0MCRUcmFuc2Zvcm0BAAlUcmFuc2Zvcm0B" + + "AAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291" + + "dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzsp" + + "TGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChJKUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsB" + + "AAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQATamF2YS9pby9QcmludFN0cmVhbQEA" + + "B3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABJqYXZhL2xhbmcvUnVubmFibGUBAANy" + + "dW4BAAthcnQvVGVzdDk0MAAgAA4ADwAAAAAAAgAAABAAEQABABIAAAAdAAEAAQAAAAUqtwABsQAA" + + "AAEAEwAAAAYAAQAAAAUAAQAUABUAAQASAAAAnQADAAMAAABfsgACuwADWbcABBIFtgAGG7YABxII" + + "tgAGtgAJtgAKGwSgABQsuQALAQAqGwRkLLYADKcADxuZAAsqGwRkLLYADLIAArsAA1m3AAQSDbYA" + + "Bhu2AAcSCLYABrYACbYACrEAAAACABMAAAAiAAgAAAAHAB4ACAAjAAkAKQAKADQACwA4AAwAQAAO" + + "AF4ADwAWAAAABAACNAsAAgAXAAAAAgAYACsAAAAKAAEADgAoACoACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQDQv3jgAAAAAAAAAAAAAAAAAAAAAAAAAAB8BQAAcAAAAHhWNBIAAAAAAAAAALgEAAAg" + + "AAAAcAAAAAwAAADwAAAABgAAACABAAABAAAAaAEAAAkAAABwAQAAAQAAALgBAACkAwAA2AEAANgB" + + "AADoAQAA8AEAAPkBAAAAAgAAAwIAAAYCAAAKAgAADgIAACcCAAA2AgAAWgIAAHoCAACRAgAApQIA" + + "ALsCAADPAgAA6gIAAP4CAAAMAwAAFwMAABoDAAAfAwAAIwMAADADAAA4AwAAPgMAAEMDAABMAwAA" + + "UQMAAFgDAABiAwAABAAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAAU" + + "AAAABQAAAAgAAAAAAAAABgAAAAkAAAB8AwAABwAAAAkAAAB0AwAAFAAAAAsAAAAAAAAAFQAAAAsA" + + "AABsAwAAFgAAAAsAAAB0AwAACgAFABoAAAABAAMAAQAAAAEABAAdAAAABQAFABsAAAAGAAMAAQAA" + + "AAcAAwAcAAAACQADAAEAAAAJAAEAGAAAAAkAAgAYAAAACQAAAB4AAAABAAAAAAAAAAYAAAAAAAAA" + + "EgAAAKgEAAB8BAAAAAAAAA4gLSB0cmFuc2Zvcm1lZAAGPGluaXQ+AAdHb29kYnllAAVIZWxsbwAB" + + "SQABTAACTEkAAkxMABdMYXJ0L1Rlc3Q5NDAkVHJhbnNmb3JtOwANTGFydC9UZXN0OTQwOwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAZTGphdmEvbGFuZy9TdHJpbmdCdWls" + + "ZGVyOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQwLmphdmEACVRyYW5zZm9ybQABVgADVklM" + + "AAJWTAALYWNjZXNzRmxhZ3MABmFwcGVuZAAEbmFtZQADb3V0AAdwcmludGxuAANydW4ABXNheUhp" + + "AAh0b1N0cmluZwAFdmFsdWUAAAAAAgAAAAAABwABAAAACAAAAAEAAAAAAAAABQAHDgAHAgAABw4B" + + "IA8BAw8BAw8BBRIBIA8BAQoBAg8AAAAAAQABAAEAAACEAwAABAAAAHAQAwAAAA4ABgADAAMAAACJ" + + "AwAAVQAAAGIAAAAiAQkAcBAFAAEAGwIDAAAAbiAHACEADAFuIAYAQQAMARsCAAAAAG4gBwAhAAwB" + + "bhAIAAEADAFuIAIAEAASEDMEKwByEAQABQDYAAT/bjABAAMFYgAAACIBCQBwEAUAAQAbAgIAAABu" + + "IAcAIQAMAW4gBgBBAAwBGwIAAAAAbiAHACEADAFuEAgAAQAMAW4gAgAQAA4AOATf/9gABP9uMAEA" + + "AwUpANj/AAAAAAEBAICABKgHAQHABwAAAgMBHxgCAgQCFwQIGRcTAAIAAACMBAAAkgQAAJwEAAAA" + + "AAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAACAAAABwAAAAAgAAAAwAAADwAAAAAwAAAAYA" + + "AAAgAQAABAAAAAEAAABoAQAABQAAAAkAAABwAQAABgAAAAEAAAC4AQAAAiAAACAAAADYAQAAARAA" + + "AAMAAABsAwAAAyAAAAIAAACEAwAAASAAAAIAAACoAwAAACAAAAEAAAB8BAAABCAAAAIAAACMBAAA" + + "AxAAAAEAAACcBAAABiAAAAEAAACoBAAAABAAAAEAAAC4BAAA"); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + t.sayHi(2, () -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/941-recurive-obsolete-jit/src/Main.java b/test/941-recurive-obsolete-jit/src/Main.java index d88bb9b722..1c391a4db5 100644 --- a/test/941-recurive-obsolete-jit/src/Main.java +++ b/test/941-recurive-obsolete-jit/src/Main.java @@ -14,6 +14,8 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; + import java.util.Base64; import java.util.function.Consumer; import java.lang.reflect.Method; @@ -148,9 +150,4 @@ public class Main { private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable); private static native void ensureJitCompiled(Class c, String name); - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/941-recurive-obsolete-jit/src/art/Redefinition.java b/test/941-recurive-obsolete-jit/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/941-recurive-obsolete-jit/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/942-private-recursive/src/Main.java b/test/942-private-recursive/src/Main.java index cac75c02f8..8a1f7c6e04 100644 --- a/test/942-private-recursive/src/Main.java +++ b/test/942-private-recursive/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,82 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - - // class Transform { - // public void sayHi(int recur, Runnable r) { - // privateSayHi(recur, r); - // } - // private void privateSayHi(int recur, Runnable r) { - // System.out.println("Hello" + recur + " - transformed"); - // if (recur == 1) { - // r.run(); - // privateSayHi(recur - 1, r); - // } else if (recur != 0) { - // privateSayHi(recur - 1, r); - // } - // System.out.println("Goodbye" + recur + " - transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAOAoADwAaCgAOABsJABwAHQcAHgoABAAaCAAfCgAEACAKAAQAIQgAIgoABAAjCgAk" + - "ACULACYAJwgAKAcAKQcAKgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + - "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADHByaXZhdGVTYXlIaQEADVN0YWNr" + - "TWFwVGFibGUBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMABAAEQwAFgAVBwArDAAsAC0B" + - "ABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEABUhlbGxvDAAuAC8MAC4AMAEADiAtIHRyYW5zZm9y" + - "bWVkDAAxADIHADMMADQANQcANgwANwARAQAHR29vZGJ5ZQEACVRyYW5zZm9ybQEAEGphdmEvbGFu" + - "Zy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07" + - "AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7" + - "AQAcKEkpTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5n" + - "L1N0cmluZzsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0" + - "cmluZzspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgAgAA4ADwAAAAAAAwAAABAAEQABABIA" + - "AAAdAAEAAQAAAAUqtwABsQAAAAEAEwAAAAYAAQAAAAEAAQAUABUAAQASAAAAIwADAAMAAAAHKhss" + - "twACsQAAAAEAEwAAAAoAAgAAAAMABgAEAAIAFgAVAAEAEgAAAJ0AAwADAAAAX7IAA7sABFm3AAUS" + - "BrYABxu2AAgSCbYAB7YACrYACxsEoAAULLkADAEAKhsEZCy3AAKnAA8bmQALKhsEZCy3AAKyAAO7" + - "AARZtwAFEg22AAcbtgAIEgm2AAe2AAq2AAuxAAAAAgATAAAAIgAIAAAABgAeAAcAIwAIACkACQA0" + - "AAoAOAALAEAADQBeAA4AFwAAAAQAAjQLAAEAGAAAAAIAGQ=="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQBQqwVIiZvIuS8j1HDurKbXZEV62Mnug5PEBAAAcAAAAHhWNBIAAAAAAAAAACQEAAAb" + - "AAAAcAAAAAkAAADcAAAABgAAAAABAAABAAAASAEAAAoAAABQAQAAAQAAAKABAAAEAwAAwAEAAMAC" + - "AADQAgAA2AIAAOECAADoAgAA6wIAAO4CAADyAgAA9gIAAAMDAAAaAwAALgMAAEQDAABYAwAAcwMA" + - "AIcDAACXAwAAmgMAAJ8DAACjAwAAqwMAAL8DAADEAwAAzQMAANsDAADgAwAA5wMAAAQAAAAIAAAA" + - "CQAAAAoAAAALAAAADAAAAA0AAAAOAAAAEAAAAAUAAAAFAAAAAAAAAAYAAAAGAAAAqAIAAAcAAAAG" + - "AAAAsAIAABAAAAAIAAAAAAAAABEAAAAIAAAAuAIAABIAAAAIAAAAsAIAAAcAAgAVAAAAAQADAAEA" + - "AAABAAQAFwAAAAEABAAZAAAAAgAFABYAAAADAAMAAQAAAAQAAwAYAAAABgADAAEAAAAGAAEAEwAA" + - "AAYAAgATAAAABgAAABoAAAABAAAAAAAAAAMAAAAAAAAADwAAAAAAAAAQBAAAAAAAAAEAAQABAAAA" + - "8QMAAAQAAABwEAQAAAAOAAYAAwADAAAA9gMAAFQAAABiAAAAIgEGAHAQBgABABsCAwAAAG4gCAAh" + - "AAwBbiAHAEEADAEbAgAAAABuIAgAIQAMAW4QCQABAAwBbiADABAAEhAzBCsAchAFAAUA2AAE/3Aw" + - "AQADBWIAAAAiAQYAcBAGAAEAGwICAAAAbiAIACEADAFuIAcAQQAMARsCAAAAAG4gCAAhAAwBbhAJ" + - "AAEADAFuIAMAEAAOADgE3//YAAT/cDABAAMFKNgDAAMAAwAAAAgEAAAEAAAAcDABABACDgABAAAA" + - "AAAAAAEAAAAFAAAAAgAAAAAABAAOIC0gdHJhbnNmb3JtZWQABjxpbml0PgAHR29vZGJ5ZQAFSGVs" + - "bG8AAUkAAUwAAkxJAAJMTAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGph" + - "dmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7" + - "ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABJMamF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9y" + - "bS5qYXZhAAFWAANWSUwAAlZMAAZhcHBlbmQAEmVtaXR0ZXI6IGphY2stNC4yNAADb3V0AAdwcmlu" + - "dGxuAAxwcml2YXRlU2F5SGkAA3J1bgAFc2F5SGkACHRvU3RyaW5nAAEABw4ABgIAAAcOASAPPDxd" + - "ASAPGS0AAwIAAAcOPAAAAAIBAICABMADAQLYAwIBkAUAAA0AAAAAAAAAAQAAAAAAAAABAAAAGwAA" + - "AHAAAAACAAAACQAAANwAAAADAAAABgAAAAABAAAEAAAAAQAAAEgBAAAFAAAACgAAAFABAAAGAAAA" + - "AQAAAKABAAABIAAAAwAAAMABAAABEAAAAwAAAKgCAAACIAAAGwAAAMACAAADIAAAAwAAAPEDAAAA" + - "IAAAAQAAABAEAAAAEAAAAQAAACQEAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test942.run(); } - - public static void doTest(Transform t) { - t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); - t.sayHi(2, () -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/942-private-recursive/src/art/Redefinition.java b/test/942-private-recursive/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/942-private-recursive/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/942-private-recursive/src/art/Test942.java b/test/942-private-recursive/src/art/Test942.java new file mode 100644 index 0000000000..cccc2fd9e0 --- /dev/null +++ b/test/942-private-recursive/src/art/Test942.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test942 { + + static class Transform { + private void privateSayHi(int recur, Runnable r) { + System.out.println("hello" + recur); + if (recur == 1) { + r.run(); + privateSayHi(recur - 1, r); + } else if (recur != 0) { + privateSayHi(recur - 1, r); + } + System.out.println("goodbye" + recur); + } + + public void sayHi(int recur, Runnable r) { + privateSayHi(recur, r); + } + } + + + // static class Transform { + // public void sayHi(int recur, Runnable r) { + // privateSayHi(recur, r); + // } + // private void privateSayHi(int recur, Runnable r) { + // System.out.println("Hello" + recur + " - transformed"); + // if (recur == 1) { + // r.run(); + // privateSayHi(recur - 1, r); + // } else if (recur != 0) { + // privateSayHi(recur - 1, r); + // } + // System.out.println("Goodbye" + recur + " - transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAPAoADwAaCgAOABsJABwAHQcAHgoABAAaCAAfCgAEACAKAAQAIQgAIgoABAAjCgAk" + + "ACULACYAJwgAKAcAKgcALQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + + "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADHByaXZhdGVTYXlIaQEADVN0YWNr" + + "TWFwVGFibGUBAApTb3VyY2VGaWxlAQAMVGVzdDk0Mi5qYXZhDAAQABEMABYAFQcALgwALwAwAQAX" + + "amF2YS9sYW5nL1N0cmluZ0J1aWxkZXIBAAVIZWxsbwwAMQAyDAAxADMBAA4gLSB0cmFuc2Zvcm1l" + + "ZAwANAA1BwA2DAA3ADgHADkMADoAEQEAB0dvb2RieWUHADsBABVhcnQvVGVzdDk0MiRUcmFuc2Zv" + + "cm0BAAlUcmFuc2Zvcm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9s" + + "YW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEABmFwcGVuZAEALShMamF2" + + "YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChJKUxqYXZhL2xhbmcv" + + "U3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQATamF2YS9p" + + "by9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABJqYXZhL2xh" + + "bmcvUnVubmFibGUBAANydW4BAAthcnQvVGVzdDk0MgAgAA4ADwAAAAAAAwAAABAAEQABABIAAAAd" + + "AAEAAQAAAAUqtwABsQAAAAEAEwAAAAYAAQAAAAUAAQAUABUAAQASAAAAIwADAAMAAAAHKhsstwAC" + + "sQAAAAEAEwAAAAoAAgAAAAcABgAIAAIAFgAVAAEAEgAAAJ0AAwADAAAAX7IAA7sABFm3AAUSBrYA" + + "Bxu2AAgSCbYAB7YACrYACxsEoAAULLkADAEAKhsEZCy3AAKnAA8bmQALKhsEZCy3AAKyAAO7AARZ" + + "twAFEg22AAcbtgAIEgm2AAe2AAq2AAuxAAAAAgATAAAAIgAIAAAACgAeAAsAIwAMACkADQA0AA4A" + + "OAAPAEAAEQBeABIAFwAAAAQAAjQLAAIAGAAAAAIAGQAsAAAACgABAA4AKQArAAg="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQDiy6hGAAAAAAAAAAAAAAAAAAAAAAAAAAC4BQAAcAAAAHhWNBIAAAAAAAAAAPQEAAAh" + + "AAAAcAAAAAwAAAD0AAAABgAAACQBAAABAAAAbAEAAAoAAAB0AQAAAQAAAMQBAADUAwAA5AEAAOQB" + + "AAD0AQAA/AEAAAUCAAAMAgAADwIAABICAAAWAgAAGgIAADMCAABCAgAAZgIAAIYCAACdAgAAsQIA" + + "AMcCAADbAgAA9gIAAAoDAAAYAwAAIwMAACYDAAArAwAALwMAADwDAABEAwAASgMAAE8DAABYAwAA" + + "ZgMAAGsDAAByAwAAfAMAAAQAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAAR" + + "AAAAFAAAAAUAAAAIAAAAAAAAAAYAAAAJAAAAlAMAAAcAAAAJAAAAjAMAABQAAAALAAAAAAAAABUA" + + "AAALAAAAhAMAABYAAAALAAAAjAMAAAoABQAaAAAAAQADAAEAAAABAAQAHAAAAAEABAAeAAAABQAF" + + "ABsAAAAGAAMAAQAAAAcAAwAdAAAACQADAAEAAAAJAAEAGAAAAAkAAgAYAAAACQAAAB8AAAABAAAA" + + "AAAAAAYAAAAAAAAAEgAAAOQEAAC0BAAAAAAAAA4gLSB0cmFuc2Zvcm1lZAAGPGluaXQ+AAdHb29k" + + "YnllAAVIZWxsbwABSQABTAACTEkAAkxMABdMYXJ0L1Rlc3Q5NDIkVHJhbnNmb3JtOwANTGFydC9U" + + "ZXN0OTQyOwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5v" + + "dGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2Jq" + + "ZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAZTGphdmEvbGFu" + + "Zy9TdHJpbmdCdWlsZGVyOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQyLmphdmEACVRyYW5z" + + "Zm9ybQABVgADVklMAAJWTAALYWNjZXNzRmxhZ3MABmFwcGVuZAAEbmFtZQADb3V0AAdwcmludGxu" + + "AAxwcml2YXRlU2F5SGkAA3J1bgAFc2F5SGkACHRvU3RyaW5nAAV2YWx1ZQAAAgAAAAAABwABAAAA" + + "CAAAAAEAAAAAAAAABQAHDgAKAgAABw4BIA8BAw8BAw8BBRIBIA8BAQoBAg8ABwIAAAcOAQMPAAAB" + + "AAEAAQAAAJwDAAAEAAAAcBAEAAAADgAGAAMAAwAAAKEDAABVAAAAYgAAACIBCQBwEAYAAQAbAgMA" + + "AABuIAgAIQAMAW4gBwBBAAwBGwIAAAAAbiAIACEADAFuEAkAAQAMAW4gAwAQABIQMwQrAHIQBQAF" + + "ANgABP9wMAEAAwViAAAAIgEJAHAQBgABABsCAgAAAG4gCAAhAAwBbiAHAEEADAEbAgAAAABuIAgA" + + "IQAMAW4QCQABAAwBbiADABAADgA4BN//2AAE/3AwAQADBSkA2P8AAAMAAwADAAAAvQMAAAQAAABw" + + "MAEAEAIOAAAAAgEAgIAEyAcBAuAHAgGcCQAAAgMBIBgCAgQCFwQIGRcTAAIAAADIBAAAzgQAANgE" + + "AAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAACEAAABwAAAAAgAAAAwAAAD0AAAAAwAA" + + "AAYAAAAkAQAABAAAAAEAAABsAQAABQAAAAoAAAB0AQAABgAAAAEAAADEAQAAAiAAACEAAADkAQAA" + + "ARAAAAMAAACEAwAAAyAAAAMAAACcAwAAASAAAAMAAADIAwAAACAAAAEAAAC0BAAABCAAAAIAAADI" + + "BAAAAxAAAAEAAADYBAAABiAAAAEAAADkBAAAABAAAAEAAAD0BAAA"); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + t.sayHi(2, () -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/943-private-recursive-jit/src/Main.java b/test/943-private-recursive-jit/src/Main.java index f380c062d1..01760ad0c1 100644 --- a/test/943-private-recursive-jit/src/Main.java +++ b/test/943-private-recursive-jit/src/Main.java @@ -14,6 +14,8 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; + import java.util.Base64; import java.util.function.Consumer; import java.lang.reflect.Method; @@ -164,9 +166,4 @@ public class Main { private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable); private static native void ensureJitCompiled(Class c, String name); - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/943-private-recursive-jit/src/art/Redefinition.java b/test/943-private-recursive-jit/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/943-private-recursive-jit/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/944-transform-classloaders/classloader.cc b/test/944-transform-classloaders/classloader.cc deleted file mode 100644 index 698e023771..0000000000 --- a/test/944-transform-classloaders/classloader.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -#include "android-base/macros.h" -#include "jni.h" -#include "jvmti.h" -#include "mirror/class-inl.h" -#include "scoped_local_ref.h" - -// Test infrastructure -#include "test_env.h" - -namespace art { -namespace Test944TransformClassloaders { - -extern "C" JNIEXPORT jlong JNICALL Java_Main_getDexFilePointer(JNIEnv* env, jclass, jclass klass) { - if (Runtime::Current() == nullptr) { - env->ThrowNew(env->FindClass("java/lang/Exception"), - "We do not seem to be running in ART! Unable to get dex file."); - return 0; - } - ScopedObjectAccess soa(env); - // This sequence of casts must be the same as those done in - // runtime/native/dalvik_system_DexFile.cc in order to ensure that we get the same results. - return static_cast<jlong>(reinterpret_cast<uintptr_t>( - &soa.Decode<mirror::Class>(klass)->GetDexFile())); -} - -} // namespace Test944TransformClassloaders -} // namespace art diff --git a/test/944-transform-classloaders/src/Main.java b/test/944-transform-classloaders/src/Main.java index b558660cfd..3d76d237ea 100644 --- a/test/944-transform-classloaders/src/Main.java +++ b/test/944-transform-classloaders/src/Main.java @@ -14,254 +14,8 @@ * limitations under the License. */ -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Base64; -import java.lang.reflect.*; public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static CommonClassDefinition TRANSFORM_DEFINITION = new CommonClassDefinition( - Transform.class, - Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="), - Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=")); - - /** - * base64 encoded class/dex file for - * class Transform2 { - * public void sayHi() { - * System.out.println("Goodbye2"); - * } - * } - */ - private static CommonClassDefinition TRANSFORM2_DEFINITION = new CommonClassDefinition( - Transform2.class, - Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA9UcmFuc2Zvcm0yLmphdmEM" + - "AAcACAcAFgwAFwAYAQAIR29vZGJ5ZTIHABkMABoAGwEAClRyYW5zZm9ybTIBABBqYXZhL2xhbmcv" + - "T2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEA" + - "E2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAA" + - "BQAGAAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAQABAAsA" + - "CAABAAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAADAAgABAABAAwAAAACAA0="), - Base64.getDecoder().decode( - "ZGV4CjAzNQABX6vL8OT7aGLjbzFBEfCM9Aaz+zzGzVnQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + - "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" + - "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTIADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJp" + - "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + - "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjQA" + - "A291dAAHcHJpbnRsbgAFc2F5SGkAAQAHDgADAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" + - "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + - "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + - "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA")); - public static void main(String[] args) throws Exception { - doTest(); - System.out.println("Passed"); - } - - private static void checkIsInstance(Class<?> klass, Object o) throws Exception { - if (!klass.isInstance(o)) { - throw new Exception(klass + " is not the class of " + o); - } - } - - private static boolean arrayContains(long[] arr, long value) { - if (arr == null) { - return false; - } - for (int i = 0; i < arr.length; i++) { - if (arr[i] == value) { - return true; - } - } - return false; + art.Test944.run(); } - - /** - * Checks that we can find the dex-file for the given class in its classloader. - * - * Throws if it fails. - */ - private static void checkDexFileInClassLoader(Class<?> klass) throws Exception { - // If all the android BCP classes were availible when compiling this test and access checks - // weren't a thing this function would be written as follows: - // - // long dexFilePtr = getDexFilePointer(klass); - // dalvik.system.BaseDexClassLoader loader = - // (dalvik.system.BaseDexClassLoader)klass.getClassLoader(); - // dalvik.system.DexPathList pathListValue = loader.pathList; - // dalvik.system.DexPathList.Element[] elementArrayValue = pathListValue.dexElements; - // int array_length = elementArrayValue.length; - // for (int i = 0; i < array_length; i++) { - // dalvik.system.DexPathList.Element curElement = elementArrayValue[i]; - // dalvik.system.DexFile curDexFile = curElement.dexFile; - // if (curDexFile == null) { - // continue; - // } - // long[] curCookie = (long[])curDexFile.mCookie; - // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; - // if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { - // return; - // } - // } - // throw new Exception( - // "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); - - // Get all the fields and classes we need by reflection. - Class<?> baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader"); - Field pathListField = baseDexClassLoaderClass.getDeclaredField("pathList"); - - Class<?> dexPathListClass = Class.forName("dalvik.system.DexPathList"); - Field elementArrayField = dexPathListClass.getDeclaredField("dexElements"); - - Class<?> dexPathListElementClass = Class.forName("dalvik.system.DexPathList$Element"); - Field dexFileField = dexPathListElementClass.getDeclaredField("dexFile"); - - Class<?> dexFileClass = Class.forName("dalvik.system.DexFile"); - Field dexFileCookieField = dexFileClass.getDeclaredField("mCookie"); - Field dexFileInternalCookieField = dexFileClass.getDeclaredField("mInternalCookie"); - - // Make all the fields accessible - AccessibleObject.setAccessible(new AccessibleObject[] { pathListField, - elementArrayField, - dexFileField, - dexFileCookieField, - dexFileInternalCookieField }, true); - - long dexFilePtr = getDexFilePointer(klass); - - ClassLoader loader = klass.getClassLoader(); - checkIsInstance(baseDexClassLoaderClass, loader); - // DexPathList pathListValue = ((BaseDexClassLoader) loader).pathList; - Object pathListValue = pathListField.get(loader); - - checkIsInstance(dexPathListClass, pathListValue); - - // DexPathList.Element[] elementArrayValue = pathListValue.dexElements; - Object elementArrayValue = elementArrayField.get(pathListValue); - if (!elementArrayValue.getClass().isArray() || - elementArrayValue.getClass().getComponentType() != dexPathListElementClass) { - throw new Exception("elementArrayValue is not an " + dexPathListElementClass + " array!"); - } - // int array_length = elementArrayValue.length; - int array_length = Array.getLength(elementArrayValue); - for (int i = 0; i < array_length; i++) { - // DexPathList.Element curElement = elementArrayValue[i]; - Object curElement = Array.get(elementArrayValue, i); - checkIsInstance(dexPathListElementClass, curElement); - - // DexFile curDexFile = curElement.dexFile; - Object curDexFile = dexFileField.get(curElement); - if (curDexFile == null) { - continue; - } - checkIsInstance(dexFileClass, curDexFile); - - // long[] curCookie = (long[])curDexFile.mCookie; - long[] curCookie = (long[])dexFileCookieField.get(curDexFile); - // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; - long[] curInternalCookie = (long[])dexFileInternalCookieField.get(curDexFile); - - if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { - return; - } - } - throw new Exception( - "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); - } - - private static void doTest() throws Exception { - art.Main.bindAgentJNIForClass(Main.class); - - Transform t = new Transform(); - Transform2 t2 = new Transform2(); - - long initial_t1_dex = getDexFilePointer(Transform.class); - long initial_t2_dex = getDexFilePointer(Transform2.class); - if (initial_t2_dex != initial_t1_dex) { - throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + - "have different initial dex files!"); - } - checkDexFileInClassLoader(Transform.class); - checkDexFileInClassLoader(Transform2.class); - - // Make sure they are loaded - t.sayHi(); - t2.sayHi(); - // Redefine both of the classes. - doMultiClassRedefinition(TRANSFORM_DEFINITION, TRANSFORM2_DEFINITION); - // Make sure we actually transformed them! - t.sayHi(); - t2.sayHi(); - - long final_t1_dex = getDexFilePointer(Transform.class); - long final_t2_dex = getDexFilePointer(Transform2.class); - if (final_t2_dex == final_t1_dex) { - throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + - "have the same initial dex files!"); - } else if (final_t1_dex == initial_t1_dex) { - throw new Exception("The class " + Transform.class + " did not get a new dex file!"); - } else if (final_t2_dex == initial_t2_dex) { - throw new Exception("The class " + Transform2.class + " did not get a new dex file!"); - } - // Check to make sure the new dex files are in the class loader. - checkDexFileInClassLoader(Transform.class); - checkDexFileInClassLoader(Transform2.class); - } - - private static void doMultiClassRedefinition(CommonClassDefinition... defs) { - ArrayList<Class<?>> classes = new ArrayList<>(); - ArrayList<byte[]> class_files = new ArrayList<>(); - ArrayList<byte[]> dex_files = new ArrayList<>(); - - for (CommonClassDefinition d : defs) { - classes.add(d.target); - class_files.add(d.class_file_bytes); - dex_files.add(d.dex_file_bytes); - } - doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), - class_files.toArray(new byte[0][]), - dex_files.toArray(new byte[0][])); - } - - // Gets the 'long' (really a native pointer) that is stored in the ClassLoader representing the - // DexFile a class is loaded from. This is converted from the DexFile* in the same way it is done - // in runtime/native/dalvik_system_DexFile.cc - private static native long getDexFilePointer(Class<?> target); - // Transforms the classes - private static native void doCommonMultiClassRedefinition(Class<?>[] targets, - byte[][] classfiles, - byte[][] dexfiles); } diff --git a/test/944-transform-classloaders/src/Transform.java b/test/944-transform-classloaders/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/944-transform-classloaders/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/944-transform-classloaders/src/Transform2.java b/test/944-transform-classloaders/src/Transform2.java deleted file mode 100644 index eb22842184..0000000000 --- a/test/944-transform-classloaders/src/Transform2.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform2 { - public void sayHi() { - System.out.println("hello2"); - } -} diff --git a/test/944-transform-classloaders/src/art/Redefinition.java b/test/944-transform-classloaders/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/944-transform-classloaders/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/944-transform-classloaders/src/art/Test944.java b/test/944-transform-classloaders/src/art/Test944.java new file mode 100644 index 0000000000..fe1c024ec4 --- /dev/null +++ b/test/944-transform-classloaders/src/art/Test944.java @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import static art.Redefinition.CommonClassDefinition; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Base64; +import java.lang.reflect.*; +public class Test944 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); + } + } + + static class Transform2 { + public void sayHi() { + System.out.println("hello2"); + } + } + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static CommonClassDefinition TRANSFORM_DEFINITION = new CommonClassDefinition( + Transform.class, + Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTQ0LmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5NDQkVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTQ0ACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAACgABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAMAAgADQACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"), + Base64.getDecoder().decode( + "ZGV4CjAzNQCFgsuWAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTQ0JFRyYW5zZm9ybTsADUxhcnQvVGVzdDk0NDsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQ0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAKAAcOAAwA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA==")); + + /** + * base64 encoded class/dex file for + * static class Transform2 { + * public void sayHi() { + * System.out.println("Goodbye2"); + * } + * } + */ + private static CommonClassDefinition TRANSFORM2_DEFINITION = new CommonClassDefinition( + Transform2.class, + Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTQ0LmphdmEMAAcA" + + "CAcAGQwAGgAbAQAIR29vZGJ5ZTIHABwMAB0AHgcAHwEAFmFydC9UZXN0OTQ0JFRyYW5zZm9ybTIB" + + "AApUcmFuc2Zvcm0yAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFu" + + "Zy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3Ry" + + "ZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTQ0ACAABQAG" + + "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAAB" + + "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAA" + + "AAoAAQAFABQAFgAI"), + Base64.getDecoder().decode( + "ZGV4CjAzNQAUg8BCAAAAAAAAAAAAAAAAAAAAAAAAAAC8AwAAcAAAAHhWNBIAAAAAAAAAAPgCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB4AgAARAEAAEQB" + + "AABMAQAAVgEAAHABAAB/AQAAowEAAMMBAADaAQAA7gEAAAICAAAWAgAAJAIAADACAAAzAgAANwIA" + + "AEQCAABKAgAATwIAAFgCAABfAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABoAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA6AIAALwCAAAAAAAABjxpbml0PgAIR29vZGJ5ZTIA" + + "GExhcnQvVGVzdDk0NCRUcmFuc2Zvcm0yOwANTGFydC9UZXN0OTQ0OwAiTGRhbHZpay9hbm5vdGF0" + + "aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2" + + "YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7" + + "ABJMamF2YS9sYW5nL1N5c3RlbTsADFRlc3Q5NDQuamF2YQAKVHJhbnNmb3JtMgABVgACVkwAC2Fj" + + "Y2Vzc0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAAEAAAAGAAAABQAH" + + "DgAHAAcOAQgPAAAAAAEAAQABAAAAcAIAAAQAAABwEAMAAAAOAAMAAQACAAAAdQIAAAkAAABiAAAA" + + "GwEBAAAAbiACABAADgAAAAAAAQEAgIAEgAUBAZgFAAACAgETGAECAwIOBAgPFwsAAgAAAMwCAADS" + + "AgAA3AIAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAAFAAAAHAAAAACAAAACQAAAMAA" + + "AAADAAAAAgAAAOQAAAAEAAAAAQAAAPwAAAAFAAAABAAAAAQBAAAGAAAAAQAAACQBAAACIAAAFAAA" + + "AEQBAAABEAAAAQAAAGgCAAADIAAAAgAAAHACAAABIAAAAgAAAIACAAAAIAAAAQAAALwCAAAEIAAA" + + "AgAAAMwCAAADEAAAAQAAANwCAAAGIAAAAQAAAOgCAAAAEAAAAQAAAPgCAAA=")); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(); + System.out.println("Passed"); + } + + private static void checkIsInstance(Class<?> klass, Object o) throws Exception { + if (!klass.isInstance(o)) { + throw new Exception(klass + " is not the class of " + o); + } + } + + private static boolean arrayContains(long[] arr, long value) { + if (arr == null) { + return false; + } + for (int i = 0; i < arr.length; i++) { + if (arr[i] == value) { + return true; + } + } + return false; + } + + /** + * Checks that we can find the dex-file for the given class in its classloader. + * + * Throws if it fails. + */ + private static void checkDexFileInClassLoader(Class<?> klass) throws Exception { + // If all the android BCP classes were availible when compiling this test and access checks + // weren't a thing this function would be written as follows: + // + // long dexFilePtr = getDexFilePointer(klass); + // dalvik.system.BaseDexClassLoader loader = + // (dalvik.system.BaseDexClassLoader)klass.getClassLoader(); + // dalvik.system.DexPathList pathListValue = loader.pathList; + // dalvik.system.DexPathList.Element[] elementArrayValue = pathListValue.dexElements; + // int array_length = elementArrayValue.length; + // for (int i = 0; i < array_length; i++) { + // dalvik.system.DexPathList.Element curElement = elementArrayValue[i]; + // dalvik.system.DexFile curDexFile = curElement.dexFile; + // if (curDexFile == null) { + // continue; + // } + // long[] curCookie = (long[])curDexFile.mCookie; + // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; + // if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { + // return; + // } + // } + // throw new Exception( + // "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); + + // Get all the fields and classes we need by reflection. + Class<?> baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader"); + Field pathListField = baseDexClassLoaderClass.getDeclaredField("pathList"); + + Class<?> dexPathListClass = Class.forName("dalvik.system.DexPathList"); + Field elementArrayField = dexPathListClass.getDeclaredField("dexElements"); + + Class<?> dexPathListElementClass = Class.forName("dalvik.system.DexPathList$Element"); + Field dexFileField = dexPathListElementClass.getDeclaredField("dexFile"); + + Class<?> dexFileClass = Class.forName("dalvik.system.DexFile"); + Field dexFileCookieField = dexFileClass.getDeclaredField("mCookie"); + Field dexFileInternalCookieField = dexFileClass.getDeclaredField("mInternalCookie"); + + // Make all the fields accessible + AccessibleObject.setAccessible(new AccessibleObject[] { pathListField, + elementArrayField, + dexFileField, + dexFileCookieField, + dexFileInternalCookieField }, true); + + long dexFilePtr = getDexFilePointer(klass); + + ClassLoader loader = klass.getClassLoader(); + checkIsInstance(baseDexClassLoaderClass, loader); + // DexPathList pathListValue = ((BaseDexClassLoader) loader).pathList; + Object pathListValue = pathListField.get(loader); + + checkIsInstance(dexPathListClass, pathListValue); + + // DexPathList.Element[] elementArrayValue = pathListValue.dexElements; + Object elementArrayValue = elementArrayField.get(pathListValue); + if (!elementArrayValue.getClass().isArray() || + elementArrayValue.getClass().getComponentType() != dexPathListElementClass) { + throw new Exception("elementArrayValue is not an " + dexPathListElementClass + " array!"); + } + // int array_length = elementArrayValue.length; + int array_length = Array.getLength(elementArrayValue); + for (int i = 0; i < array_length; i++) { + // DexPathList.Element curElement = elementArrayValue[i]; + Object curElement = Array.get(elementArrayValue, i); + checkIsInstance(dexPathListElementClass, curElement); + + // DexFile curDexFile = curElement.dexFile; + Object curDexFile = dexFileField.get(curElement); + if (curDexFile == null) { + continue; + } + checkIsInstance(dexFileClass, curDexFile); + + // long[] curCookie = (long[])curDexFile.mCookie; + long[] curCookie = (long[])dexFileCookieField.get(curDexFile); + // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; + long[] curInternalCookie = (long[])dexFileInternalCookieField.get(curDexFile); + + if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { + return; + } + } + throw new Exception( + "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); + } + + private static void doTest() throws Exception { + Transform t = new Transform(); + Transform2 t2 = new Transform2(); + + long initial_t1_dex = getDexFilePointer(Transform.class); + long initial_t2_dex = getDexFilePointer(Transform2.class); + if (initial_t2_dex != initial_t1_dex) { + throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + + "have different initial dex files!"); + } + checkDexFileInClassLoader(Transform.class); + checkDexFileInClassLoader(Transform2.class); + + // Make sure they are loaded + t.sayHi(); + t2.sayHi(); + // Redefine both of the classes. + Redefinition.doMultiClassRedefinition(TRANSFORM_DEFINITION, TRANSFORM2_DEFINITION); + // Make sure we actually transformed them! + t.sayHi(); + t2.sayHi(); + + long final_t1_dex = getDexFilePointer(Transform.class); + long final_t2_dex = getDexFilePointer(Transform2.class); + if (final_t2_dex == final_t1_dex) { + throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + + "have the same initial dex files!"); + } else if (final_t1_dex == initial_t1_dex) { + throw new Exception("The class " + Transform.class + " did not get a new dex file!"); + } else if (final_t2_dex == initial_t2_dex) { + throw new Exception("The class " + Transform2.class + " did not get a new dex file!"); + } + // Check to make sure the new dex files are in the class loader. + checkDexFileInClassLoader(Transform.class); + checkDexFileInClassLoader(Transform2.class); + } + + // Gets the 'long' (really a native pointer) that is stored in the ClassLoader representing the + // DexFile a class is loaded from. This is plucked out of the internal DexCache object associated + // with the class. + private static long getDexFilePointer(Class<?> target) throws Exception { + // If all the android BCP classes were available when compiling this test and access checks + // weren't a thing this function would be written as follows: + // + // java.lang.DexCache dexCacheObject = target.dexCache; + // if (dexCacheObject == null) { + // return 0; + // } + // return dexCacheObject.dexFile; + Field dexCacheField = Class.class.getDeclaredField("dexCache"); + + Class<?> dexCacheClass = Class.forName("java.lang.DexCache"); + Field dexFileField = dexCacheClass.getDeclaredField("dexFile"); + + AccessibleObject.setAccessible(new AccessibleObject[] { dexCacheField, dexFileField }, true); + + Object dexCacheObject = dexCacheField.get(target); + if (dexCacheObject == null) { + return 0; + } + checkIsInstance(dexCacheClass, dexCacheObject); + return dexFileField.getLong(dexCacheObject); + } +} diff --git a/test/945-obsolete-native/obsolete_native.cc b/test/945-obsolete-native/obsolete_native.cc index ee653a4a12..e3090f5906 100644 --- a/test/945-obsolete-native/obsolete_native.cc +++ b/test/945-obsolete-native/obsolete_native.cc @@ -19,31 +19,20 @@ #include <stdio.h> #include "android-base/stringprintf.h" - -#include "android-base/stringprintf.h" -#include "base/logging.h" -#include "base/macros.h" #include "jni.h" #include "jvmti.h" -#include "scoped_local_ref.h" // Test infrastructure #include "jni_binder.h" #include "test_env.h" +#include "scoped_local_ref.h" namespace art { namespace Test945ObsoleteNative { -extern "C" JNIEXPORT void JNICALL Java_Main_bindTest945ObsoleteNative( - JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { - BindFunctions(jvmti_env, env, "Transform"); -} - -extern "C" JNIEXPORT void JNICALL Java_Transform_doExecute(JNIEnv* env, - jclass klass ATTRIBUTE_UNUSED, - jobject runnable) { +extern "C" JNIEXPORT void JNICALL Java_art_Test945_00024Transform_doExecute( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject runnable) { jclass runnable_klass = env->FindClass("java/lang/Runnable"); - DCHECK(runnable_klass != nullptr); jmethodID run_method = env->GetMethodID(runnable_klass, "run", "()V"); env->CallVoidMethod(runnable, run_method); } diff --git a/test/945-obsolete-native/src/Main.java b/test/945-obsolete-native/src/Main.java index a7901cd2bb..c94bc2206c 100644 --- a/test/945-obsolete-native/src/Main.java +++ b/test/945-obsolete-native/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,65 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // doExecute(r); - // System.out.println("Goodbye - Transformed"); - // } - // - // private static native void doExecute(Runnable r); - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAIgoACAASCQATABQIABUKABYAFwoABwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAAlkb0V4ZWN1dGUBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAe" + - "AQATSGVsbG8gLSBUcmFuc2Zvcm1lZAcAHwwAIAAhDAAPAA4BABVHb29kYnllIC0gVHJhbnNmb3Jt" + - "ZWQBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291" + - "dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxu" + - "AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABwAIAAAAAAADAAAACQAKAAEACwAAAB0AAQABAAAA" + - "BSq3AAGxAAAAAQAMAAAABgABAAAAEQABAA0ADgABAAsAAAA5AAIAAgAAABWyAAISA7YABCu4AAWy" + - "AAISBrYABLEAAAABAAwAAAASAAQAAAATAAgAFAAMABUAFAAWAQoADwAOAAAAAQAQAAAAAgAR"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQB1fZcJR/opPuXacK8mIla5shH0LSg72qJYAwAAcAAAAHhWNBIAAAAAAAAAALgCAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAUAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAABuAgAAggIA" + - "AIcCAACQAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQAOAAAAAAAAAAAAAAAAAAEADAAAAAAAAQAQAAAAAQACAA8AAAAC" + - "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAKUCAAAAAAAAAQABAAEAAACXAgAABAAAAHAQ" + - "BAAAAA4ABAACAAIAAACcAgAAFAAAAGIAAAAbAQIAAABuIAMAEABxEAEAAwBiAAAAGwEBAAAAbiAD" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAAJZG9FeGVjdXRlABJlbWl0" + - "dGVyOiBqYWNrLTQuMjUAA291dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAQAHDoc8hwAAAAIBAICA" + - "BMQCAYoCAAIB3AIADQAAAAAAAAABAAAAAAAAAAEAAAARAAAAcAAAAAIAAAAHAAAAtAAAAAMAAAAD" + - "AAAA0AAAAAQAAAABAAAA9AAAAAUAAAAFAAAA/AAAAAYAAAABAAAAJAEAAAEgAAACAAAARAEAAAEQ" + - "AAACAAAAlAEAAAIgAAARAAAAogEAAAMgAAACAAAAlwIAAAAgAAABAAAApQIAAAAQAAABAAAAuAIA" + - "AA=="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - bindTest945ObsoleteNative(); - doTest(new Transform()); - } - - public static void doTest(Transform t) { - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - t.sayHi(() -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - }); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); + public static void main(String[] args) throws Exception { + art.Test945.run(); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); - - private static native void bindTest945ObsoleteNative(); } diff --git a/test/945-obsolete-native/src/Transform.java b/test/945-obsolete-native/src/Transform.java deleted file mode 100644 index 2b7cc1b3a1..0000000000 --- a/test/945-obsolete-native/src/Transform.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - System.out.println("hello"); - doExecute(r); - System.out.println("goodbye"); - } - - private static native void doExecute(Runnable r); -} diff --git a/test/945-obsolete-native/src/art/Redefinition.java b/test/945-obsolete-native/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/945-obsolete-native/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/945-obsolete-native/src/art/Test945.java b/test/945-obsolete-native/src/art/Test945.java new file mode 100644 index 0000000000..6cf31f6d05 --- /dev/null +++ b/test/945-obsolete-native/src/art/Test945.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test945 { + + static class Transform { + static { + art.Main.bindAgentJNIForClass(Transform.class); + } + + public void sayHi(Runnable r) { + System.out.println("hello"); + doExecute(r); + System.out.println("goodbye"); + } + + private static native void doExecute(Runnable r); + } + + // static class Transform { + // static { } + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // doExecute(r); + // System.out.println("Goodbye - Transformed"); + // } + // + // private static native void doExecute(Runnable r); + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAJwoACAATCQAUABUIABYKABcAGAoABwAZCAAaBwAcBwAfAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAAlkb0V4ZWN1dGUBAAg8Y2xpbml0PgEAClNvdXJjZUZpbGUBAAxUZXN0OTQ1LmphdmEMAAkA" + + "CgcAIAwAIQAiAQATSGVsbG8gLSBUcmFuc2Zvcm1lZAcAIwwAJAAlDAAPAA4BABVHb29kYnllIC0g" + + "VHJhbnNmb3JtZWQHACYBABVhcnQvVGVzdDk0NSRUcmFuc2Zvcm0BAAlUcmFuc2Zvcm0BAAxJbm5l" + + "ckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxq" + + "YXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExq" + + "YXZhL2xhbmcvU3RyaW5nOylWAQALYXJ0L1Rlc3Q5NDUAIAAHAAgAAAAAAAQAAAAJAAoAAQALAAAA" + + "HQABAAEAAAAFKrcAAbEAAAABAAwAAAAGAAEAAAAFAAEADQAOAAEACwAAADkAAgACAAAAFbIAAhID" + + "tgAEK7gABbIAAhIGtgAEsQAAAAEADAAAABIABAAAAAgACAAJAAwACgAUAAsBCgAPAA4AAAAIABAA" + + "CgABAAsAAAAZAAAAAAAAAAGxAAAAAQAMAAAABgABAAAABgACABEAAAACABIAHgAAAAoAAQAHABsA" + + "HQAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAFqcJFAAAAAAAAAAAAAAAAAAAAAAAAAAB8BAAAcAAAAHhWNBIAAAAAAAAAALgDAAAY" + + "AAAAcAAAAAoAAADQAAAAAwAAAPgAAAABAAAAHAEAAAYAAAAkAQAAAQAAAFQBAAAIAwAAdAEAAHQB" + + "AAB+AQAAhgEAAJ0BAACyAQAAywEAANoBAAD+AQAAHgIAADUCAABJAgAAXwIAAHMCAACHAgAAlQIA" + + "AKACAACjAgAApwIAALQCAAC/AgAAxQIAAMoCAADTAgAA2gIAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADAAAAA8AAAAPAAAACQAAAAAAAAAQAAAACQAAAOQCAAAQAAAACQAAAOwCAAAI" + + "AAQAFAAAAAAAAAAAAAAAAAAAAAEAAAAAAAEAEgAAAAAAAQAWAAAABAACABUAAAAFAAAAAQAAAAAA" + + "AAAAAAAABQAAAAAAAAANAAAAqAMAAHQDAAAAAAAACDxjbGluaXQ+AAY8aW5pdD4AFUdvb2RieWUg" + + "LSBUcmFuc2Zvcm1lZAATSGVsbG8gLSBUcmFuc2Zvcm1lZAAXTGFydC9UZXN0OTQ1JFRyYW5zZm9y" + + "bTsADUxhcnQvVGVzdDk0NTsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxk" + + "YWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2" + + "YS9sYW5nL09iamVjdDsAFExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsA" + + "EkxqYXZhL2xhbmcvU3lzdGVtOwAMVGVzdDk0NS5qYXZhAAlUcmFuc2Zvcm0AAVYAAlZMAAthY2Nl" + + "c3NGbGFncwAJZG9FeGVjdXRlAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAAAB" + + "AAAABgAAAAEAAAAHAAAABQAHDgAFAAcOAAgBAAcOAQgPAQMPAQgPAAAAAAAAAAAAAAAA9AIAAAEA" + + "AAAOAAAAAQABAAEAAAD5AgAABAAAAHAQBQAAAA4ABAACAAIAAAD+AgAAFAAAAGIAAAAbAQMAAABu" + + "IAQAEABxEAIAAwBiAAAAGwECAAAAbiAEABAADgAAAAMBAIiABJAGAYCABKQGAYoCAAMBvAYCAgEX" + + "GAECAwIRBAgTFw4AAgAAAIwDAACSAwAAnAMAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAAB" + + "AAAAGAAAAHAAAAACAAAACgAAANAAAAADAAAAAwAAAPgAAAAEAAAAAQAAABwBAAAFAAAABgAAACQB" + + "AAAGAAAAAQAAAFQBAAACIAAAGAAAAHQBAAABEAAAAgAAAOQCAAADIAAAAwAAAPQCAAABIAAAAwAA" + + "ABADAAAAIAAAAQAAAHQDAAAEIAAAAgAAAIwDAAADEAAAAQAAAJwDAAAGIAAAAQAAAKgDAAAAEAAA" + + "AQAAALgDAAA="); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/946-obsolete-throw/expected.txt b/test/946-obsolete-throw/expected.txt index 71d5182100..edf796eb96 100644 --- a/test/946-obsolete-throw/expected.txt +++ b/test/946-obsolete-throw/expected.txt @@ -5,10 +5,11 @@ hello transforming calling function Received error : java.lang.Error: Throwing exception into an obsolete method! java.lang.Error: Throwing exception into an obsolete method! - at Main$DoRedefinitionClass.run(Main.java:65) - at Transform.sayHi(Transform.java:27) - at Main.doTest(Main.java:72) - at Main.main(Main.java:57) + at art.Test946$DoRedefinitionClass.run(Test946.java:81) + at art.Test946$Transform.sayHi(Test946.java:26) + at art.Test946.doTest(Test946.java:88) + at art.Test946.run(Test946.java:73) + at Main.main(Main.java:19) Hello - Transformed Not doing anything here Goodbye - Transformed diff --git a/test/946-obsolete-throw/src/Main.java b/test/946-obsolete-throw/src/Main.java index 077ad72acd..0b1f78dc4a 100644 --- a/test/946-obsolete-throw/src/Main.java +++ b/test/946-obsolete-throw/src/Main.java @@ -14,71 +14,8 @@ * limitations under the License. */ -import java.util.Base64; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" + - "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); - } - - static class DoRedefinitionClass implements Runnable { - @Override - public void run() { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - throw new Error("Throwing exception into an obsolete method!"); - } + public static void main(String[] args) throws Exception { + art.Test946.run(); } - - public static void doTest(Transform t) { - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - try { - t.sayHi(new DoRedefinitionClass()); - } catch (Throwable e) { - System.out.println("Received error : " + e); - e.printStackTrace(System.out); - } - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/946-obsolete-throw/src/Transform.java b/test/946-obsolete-throw/src/Transform.java deleted file mode 100644 index 4f43086d32..0000000000 --- a/test/946-obsolete-throw/src/Transform.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Hello" < "LTransform;" < "hello". - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/946-obsolete-throw/src/art/Redefinition.java b/test/946-obsolete-throw/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/946-obsolete-throw/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/946-obsolete-throw/src/art/Test946.java b/test/946-obsolete-throw/src/art/Test946.java new file mode 100644 index 0000000000..9f0e57c333 --- /dev/null +++ b/test/946-obsolete-throw/src/art/Test946.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test946 { + + static class Transform { + public void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + + // static class Transform { + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk0Ni5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5NDYkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTQ2ACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7AAIAAgAA" + + "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQB0mzt6AAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5NDYkVHJhbnNmb3JtOwANTGFydC9UZXN0OTQ2OwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTQ2LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA=="); + + public static void run() { + doTest(new Transform()); + } + + static class DoRedefinitionClass implements Runnable { + @Override + public void run() { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + throw new Error("Throwing exception into an obsolete method!"); + } + } + + public static void doTest(Transform t) { + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + try { + t.sayHi(new DoRedefinitionClass()); + } catch (Throwable e) { + System.out.println("Received error : " + e); + e.printStackTrace(System.out); + } + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/947-reflect-method/src/Main.java b/test/947-reflect-method/src/Main.java index da746ac4db..bc3f4b2cf4 100644 --- a/test/947-reflect-method/src/Main.java +++ b/test/947-reflect-method/src/Main.java @@ -14,60 +14,8 @@ * limitations under the License. */ -import java.util.Base64; -import java.lang.reflect.Method; - public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + - "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); + public static void main(String[] args) throws Exception { + art.Test947.run(); } - - public static void doTest(Transform t) { - try { - Method say_hi_method = t.getClass().getDeclaredMethod("sayHi"); - say_hi_method.invoke(t); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - say_hi_method.invoke(t); - } catch (Exception e) { - e.printStackTrace(); - } - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/947-reflect-method/src/Transform.java b/test/947-reflect-method/src/Transform.java deleted file mode 100644 index b8fe34aef3..0000000000 --- a/test/947-reflect-method/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/947-reflect-method/src/art/Redefinition.java b/test/947-reflect-method/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/947-reflect-method/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/947-reflect-method/src/art/Test947.java b/test/947-reflect-method/src/art/Test947.java new file mode 100644 index 0000000000..8cb515e492 --- /dev/null +++ b/test/947-reflect-method/src/art/Test947.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +import java.lang.reflect.Method; + +public class Test947 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); + } + } + + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTQ3LmphdmEMAAcA" + + "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5NDckVHJhbnNmb3JtAQAJ" + + "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" + + "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" + + "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTQ3ACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAABAAkA" + + "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAAAAoA" + + "AQAFABQAFgAI"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCEgoKcAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTQ3JFRyYW5zZm9ybTsADUxhcnQvVGVzdDk0NzsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQ3LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + public static void run() { + doTest(new Transform()); + } + + public static void doTest(Transform t) { + try { + Method say_hi_method = t.getClass().getDeclaredMethod("sayHi"); + say_hi_method.invoke(t); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + say_hi_method.invoke(t); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/948-change-annotations/src/Main.java b/test/948-change-annotations/src/Main.java index a290396ebf..5d3406dacc 100644 --- a/test/948-change-annotations/src/Main.java +++ b/test/948-change-annotations/src/Main.java @@ -14,6 +14,7 @@ * limitations under the License. */ +import art.Redefinition; import java.util.Arrays; import java.util.Base64; import java.util.Comparator; @@ -85,7 +86,9 @@ public class Main { } // Transforms the class - public static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); + public static void doCommonClassRedefinition(Class<?> target, + byte[] class_file, + byte[] dex_file) { + Redefinition.doCommonClassRedefinition(target, class_file, dex_file); + } } diff --git a/test/948-change-annotations/src/art/Redefinition.java b/test/948-change-annotations/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/948-change-annotations/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/949-in-memory-transform/src/Main.java b/test/949-in-memory-transform/src/Main.java index 1a6b224a37..b49a93f67b 100644 --- a/test/949-in-memory-transform/src/Main.java +++ b/test/949-in-memory-transform/src/Main.java @@ -14,112 +14,8 @@ * limitations under the License. */ -import java.util.Base64; -import java.lang.reflect.*; -import java.nio.ByteBuffer; - public class Main { - /** - * base64 encoded class/dex file for - * public class Transform { - * public void sayHi() { - * System.out.println("hello"); - * } - * } - */ - private static final byte[] INITIAL_CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" + - "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" + - "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAA" + - "AAAAAgABAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" + - "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN"); - private static final byte[] INITIAL_DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAJX3mZphwHJCT1qdTz/GS+jXOR+O/9e3fMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" + - "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" + - "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" + - "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" + - "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUABWhlbGxvAANvdXQA" + - "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCBgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA="); - - - /** - * base64 encoded class/dex file for - * public class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] TRANSFORMED_CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + - "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + - "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + - "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + - "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAG" + - "AAAAAAACAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + - "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAaAAgAGwABAAwAAAACAA0="); - private static final byte[] TRANSFORMED_DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAPXh6T3l1FObhHsKf1U2vi+0GmAvElxBLMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgAaAAcOhwAAAAEBAIGABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - public static void main(String[] args) throws Exception { - art.Main.bindAgentJNIForClass(Main.class); - ClassLoader loader; - try { - // Art uses this classloader to do in-memory dex files. There is no support for defineClass - loader = (ClassLoader)Class.forName("dalvik.system.InMemoryDexClassLoader") - .getConstructor(ByteBuffer.class, ClassLoader.class) - .newInstance(ByteBuffer.wrap(INITIAL_DEX_BYTES), - ClassLoader.getSystemClassLoader()); - } catch (ClassNotFoundException e) { - // Seem to be on RI. Just make a new ClassLoader that calls defineClass. - loader = new ClassLoader() { - public Class<?> findClass(String name) throws ClassNotFoundException { - if (name.equals("Transform")) { - return defineClass(name, INITIAL_CLASS_BYTES, 0, INITIAL_CLASS_BYTES.length); - } else { - throw new ClassNotFoundException("Couldn't find class: " + name); - } - } - }; - } - doTest(loader); + art.Test949.run(); } - - public static void doTest(ClassLoader loader) throws Exception { - // Get the class - Class<?> transform_class = loader.loadClass("Transform"); - Method say_hi_method = transform_class.getMethod("sayHi"); - Object t = transform_class.newInstance(); - - // Run the actual test. - say_hi_method.invoke(t); - doCommonClassRedefinition(transform_class, TRANSFORMED_CLASS_BYTES, TRANSFORMED_DEX_BYTES); - say_hi_method.invoke(t); - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/949-in-memory-transform/src/art/Redefinition.java b/test/949-in-memory-transform/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/949-in-memory-transform/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/949-in-memory-transform/src/art/Test949.java b/test/949-in-memory-transform/src/art/Test949.java new file mode 100644 index 0000000000..cd733b9f2d --- /dev/null +++ b/test/949-in-memory-transform/src/art/Test949.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import static art.Redefinition.doCommonClassRedefinition; + +import java.util.Base64; +import java.lang.reflect.*; +import java.nio.ByteBuffer; + +public class Test949 { + /** + * base64 encoded class/dex file for + * public class Transform { + * public void sayHi() { + * System.out.println("hello"); + * } + * } + */ + private static final byte[] INITIAL_CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + + "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" + + "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" + + "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAA" + + "AAAAAgABAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" + + "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN"); + private static final byte[] INITIAL_DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAJX3mZphwHJCT1qdTz/GS+jXOR+O/9e3fMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + + "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" + + "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" + + "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" + + "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" + + "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUABWhlbGxvAANvdXQA" + + "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCBgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" + + "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + + "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + + "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA="); + + + /** + * base64 encoded class/dex file for + * public class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] TRANSFORMED_CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + + "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + + "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + + "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAG" + + "AAAAAAACAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + + "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAaAAgAGwABAAwAAAACAA0="); + private static final byte[] TRANSFORMED_DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAPXh6T3l1FObhHsKf1U2vi+0GmAvElxBLMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + + "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + + "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + + "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + + "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + + "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUAA291" + + "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgAaAAcOhwAAAAEBAIGABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + + "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + + "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + + "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); + + public static void run() throws Exception { + ClassLoader loader; + try { + // Art uses this classloader to do in-memory dex files. There is no support for defineClass + loader = (ClassLoader)Class.forName("dalvik.system.InMemoryDexClassLoader") + .getConstructor(ByteBuffer.class, ClassLoader.class) + .newInstance(ByteBuffer.wrap(INITIAL_DEX_BYTES), + ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException e) { + // Seem to be on RI. Just make a new ClassLoader that calls defineClass. + loader = new ClassLoader() { + public Class<?> findClass(String name) throws ClassNotFoundException { + if (name.equals("Transform")) { + return defineClass(name, INITIAL_CLASS_BYTES, 0, INITIAL_CLASS_BYTES.length); + } else { + throw new ClassNotFoundException("Couldn't find class: " + name); + } + } + }; + } + doTest(loader); + } + + public static void doTest(ClassLoader loader) throws Exception { + // Get the class + Class<?> transform_class = loader.loadClass("Transform"); + Method say_hi_method = transform_class.getMethod("sayHi"); + Object t = transform_class.newInstance(); + + // Run the actual test. + say_hi_method.invoke(t); + doCommonClassRedefinition(transform_class, TRANSFORMED_CLASS_BYTES, TRANSFORMED_DEX_BYTES); + say_hi_method.invoke(t); + } +} diff --git a/test/950-redefine-intrinsic/src/Main.java b/test/950-redefine-intrinsic/src/Main.java index 2578d6e278..369a8f417e 100644 --- a/test/950-redefine-intrinsic/src/Main.java +++ b/test/950-redefine-intrinsic/src/Main.java @@ -14,6 +14,7 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; import java.util.Base64; import java.util.Random; import java.util.function.*; @@ -464,9 +465,4 @@ public class Main { } System.out.println("Finished!"); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/950-redefine-intrinsic/src/art/Redefinition.java b/test/950-redefine-intrinsic/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/950-redefine-intrinsic/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/951-threaded-obsolete/src/Main.java b/test/951-threaded-obsolete/src/Main.java index a82090e736..d245aa9ec8 100644 --- a/test/951-threaded-obsolete/src/Main.java +++ b/test/951-threaded-obsolete/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,84 +14,8 @@ * limitations under the License. */ -import java.util.Base64; -import java.util.concurrent.Semaphore; - public class Main { - // class Transform { - // public void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" + - "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - // Semaphores to let each thread know where the other is. We could use barriers but semaphores - // mean we don't need to have the worker thread be waiting around. - final Semaphore sem_redefine_start = new Semaphore(0); - final Semaphore sem_redefine_end = new Semaphore(0); - // Create a thread to do the actual redefinition. We will just communicate through an - // atomic-integer. - new Thread(() -> { - try { - // Wait for the other thread to ask for redefinition. - sem_redefine_start.acquire(); - // Do the redefinition. - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - // Allow the other thread to wake up if it is waiting. - sem_redefine_end.release(); - } catch (InterruptedException e) { - throw new Error("unable to do redefinition", e); - } - }).start(); - - Transform t = new Transform(); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); - t.sayHi(() -> { - try { - System.out.println("transforming calling function"); - // Wake up the waiting thread. - sem_redefine_start.release(); - // Wait for the other thread to finish with redefinition. - sem_redefine_end.acquire(); - } catch (InterruptedException e) { - throw new Error("unable to do redefinition", e); - } - }); - t.sayHi(() -> { System.out.println("Not doing anything here"); }); + public static void main(String[] args) throws Exception { + art.Test951.run(); } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); } diff --git a/test/951-threaded-obsolete/src/Transform.java b/test/951-threaded-obsolete/src/Transform.java deleted file mode 100644 index 8cda6cdf53..0000000000 --- a/test/951-threaded-obsolete/src/Transform.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi(Runnable r) { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Hello" < "LTransform;" < "hello". - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/951-threaded-obsolete/src/art/Redefinition.java b/test/951-threaded-obsolete/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/951-threaded-obsolete/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/951-threaded-obsolete/src/art/Test951.java b/test/951-threaded-obsolete/src/art/Test951.java new file mode 100644 index 0000000000..3628f4f9db --- /dev/null +++ b/test/951-threaded-obsolete/src/art/Test951.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; +import java.util.concurrent.Semaphore; + +public class Test951 { + + static class Transform { + public void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + + // static class Transform { + // public void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk1MS5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5NTEkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTUxACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7AAIAAgAA" + + "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBom/JeAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5NTEkVHJhbnNmb3JtOwANTGFydC9UZXN0OTUxOwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTUxLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA=="); + + public static void run() { + // Semaphores to let each thread know where the other is. We could use barriers but semaphores + // mean we don't need to have the worker thread be waiting around. + final Semaphore sem_redefine_start = new Semaphore(0); + final Semaphore sem_redefine_end = new Semaphore(0); + // Create a thread to do the actual redefinition. We will just communicate through an + // atomic-integer. + new Thread(() -> { + try { + // Wait for the other thread to ask for redefinition. + sem_redefine_start.acquire(); + // Do the redefinition. + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + // Allow the other thread to wake up if it is waiting. + sem_redefine_end.release(); + } catch (InterruptedException e) { + throw new Error("unable to do redefinition", e); + } + }).start(); + + Transform t = new Transform(); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + try { + System.out.println("transforming calling function"); + // Wake up the waiting thread. + sem_redefine_start.release(); + // Wait for the other thread to finish with redefinition. + sem_redefine_end.acquire(); + } catch (InterruptedException e) { + throw new Error("unable to do redefinition", e); + } + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/959-invoke-polymorphic-accessors/src/Main.java b/test/959-invoke-polymorphic-accessors/src/Main.java index b7ecf8e818..59db8076b2 100644 --- a/test/959-invoke-polymorphic-accessors/src/Main.java +++ b/test/959-invoke-polymorphic-accessors/src/Main.java @@ -794,6 +794,7 @@ public class Main { ValueHolder valueHolder = new ValueHolder(); MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle h0 = lookup.findSetter(ValueHolder.class, "m_f", float.class); + MethodHandle s0 = lookup.findSetter(ValueHolder.class, "m_s", short.class); h0.invoke(valueHolder, 0.22f); h0.invoke(valueHolder, new Float(1.11f)); Number floatNumber = getFloatAsNumber(); @@ -807,6 +808,11 @@ public class Main { unreachable(); } catch (NullPointerException e) {} + // Test that type conversion checks work on small field types. + short temp = (short)s0.invoke(valueHolder, new Byte((byte)45)); + assertTrue(temp == 0); + assertTrue(valueHolder.m_s == 45); + h0.invoke(valueHolder, (byte)1); h0.invoke(valueHolder, (short)2); h0.invoke(valueHolder, 3); @@ -848,6 +854,7 @@ public class Main { private static void testStaticSetter() throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandle s0 = lookup.findStaticSetter(ValueHolder.class, "s_s", short.class); MethodHandle h0 = lookup.findStaticSetter(ValueHolder.class, "s_f", float.class); h0.invoke(0.22f); h0.invoke(new Float(1.11f)); @@ -860,6 +867,11 @@ public class Main { unreachable(); } catch (NullPointerException e) {} + // Test that type conversion checks work on small field types. + short temp = (short)s0.invoke(new Byte((byte)45)); + assertTrue(temp == 0); + assertTrue(ValueHolder.s_s == 45); + h0.invoke((byte)1); h0.invoke((short)2); h0.invoke(3); diff --git a/test/980-redefine-object/check b/test/980-redefine-object/check index 987066fe15..07b21b3176 100755 --- a/test/980-redefine-object/check +++ b/test/980-redefine-object/check @@ -17,4 +17,4 @@ # The number of paused background threads (and therefore InterruptedExceptions) # can change so we will just delete their lines from the log. -sed "/Object allocated of type 'Ljava\/lang\/InterruptedException;'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null +sed "/Object allocated of type 'java\.lang\.InterruptedException'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null diff --git a/test/980-redefine-object/expected.txt b/test/980-redefine-object/expected.txt index 6e9bce027a..4c294bc870 100644 --- a/test/980-redefine-object/expected.txt +++ b/test/980-redefine-object/expected.txt @@ -2,51 +2,31 @@ Allocating an j.l.Object before redefining Object class Allocating a Transform before redefining Object class Redefining the Object class to add a hook into the <init> method -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' Allocating an j.l.Object after redefining Object class -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Object' Allocating a Transform after redefining Object class -Object allocated of type 'LTransform;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'Transform' Allocating an int[] after redefining Object class -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' Allocating an array list -Object allocated of type 'Ljava/util/ArrayList;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.util.ArrayList' Adding a bunch of stuff to the array list -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'LTransform;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.lang.Object' +Object allocated of type 'Transform' Allocating a linked list -Object allocated of type 'Ljava/util/LinkedList;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.util.LinkedList' Adding a bunch of stuff to the linked list -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'LTransform;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'Transform' +Object allocated of type 'java.util.LinkedList$Node' Throwing from down 4 stack frames -Object allocated of type 'Ljava/lang/Exception;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Exception' Exception caught. -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' Finishing test! diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc deleted file mode 100644 index 1faf1a16a7..0000000000 --- a/test/980-redefine-object/redefine_object.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -#include <inttypes.h> -#include <iostream> - -#include "android-base/stringprintf.h" -#include "base/logging.h" -#include "base/macros.h" -#include "jni.h" -#include "jvmti.h" -#include "scoped_utf_chars.h" - -// Test infrastructure -#include "jni_binder.h" -#include "jvmti_helper.h" -#include "test_env.h" - -namespace art { -namespace Test980RedefineObjects { - -extern "C" JNIEXPORT void JNICALL Java_Main_bindFunctionsForClass( - JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass target) { - BindFunctionsOnClass(jvmti_env, env, target); -} - -extern "C" JNIEXPORT void JNICALL Java_art_test_TestWatcher_NotifyConstructed( - JNIEnv* env, jclass TestWatcherClass ATTRIBUTE_UNUSED, jobject constructed) { - char* sig = nullptr; - char* generic_sig = nullptr; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetClassSignature(env->GetObjectClass(constructed), - &sig, - &generic_sig))) { - // Exception. - return; - } - std::cout << "Object allocated of type '" << sig << "'" << std::endl; - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig)); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(generic_sig)); -} - -} // namespace Test980RedefineObjects -} // namespace art diff --git a/test/980-redefine-object/src-ex/TestWatcher.java b/test/980-redefine-object/src-ex/TestWatcher.java index d15e68871c..c38e07bfe9 100644 --- a/test/980-redefine-object/src-ex/TestWatcher.java +++ b/test/980-redefine-object/src-ex/TestWatcher.java @@ -16,10 +16,60 @@ package art.test; +import java.util.concurrent.locks.ReentrantLock; + public class TestWatcher { - // NB This function is native since it is called in the Object.<init> method and so cannot cause - // any java allocations at all. The normal System.out.print* functions will cause allocations to - // occur so we cannot use them. This means the easiest way to report the object as being created - // is to go into native code and do it there. - public static native void NotifyConstructed(Object o); + // Lock to synchronize access to the static state of this class. + private static final ReentrantLock lock = new ReentrantLock(); + private static volatile boolean criticalFailure = false; + private static boolean reportingEnabled = true; + private static boolean doingReport = false; + + private static void MonitorEnter() { + lock.lock(); + } + + private static void MonitorExit() { + // Need to do this manually since we need to notify critical failure but would deadlock if + // waited for the unlock. + if (!lock.isHeldByCurrentThread()) { + NotifyCriticalFailure(); + throw new IllegalMonitorStateException("Locking error!"); + } else { + lock.unlock(); + } + } + + // Stops reporting. Must be paired with an EnableReporting call. + public static void DisableReporting() { + MonitorEnter(); + reportingEnabled = false; + } + + // Stops reporting. Must be paired with a DisableReporting call. + public static void EnableReporting() { + reportingEnabled = true; + MonitorExit(); + } + + public static void NotifyCriticalFailure() { + criticalFailure = true; + } + + public static void NotifyConstructed(Object o) { + if (criticalFailure) { + // Something went very wrong. We are probably trying to report it so don't get in the way. + return; + } + MonitorEnter(); + // We could enter an infinite loop if println allocates (which it does) so we disable + // reporting while we are doing a report. Since we are synchronized we won't miss any + // allocations. + if (reportingEnabled && !doingReport) { + doingReport = true; + System.out.println("Object allocated of type '" + o.getClass().getName() + "'"); + doingReport = false; + } + MonitorExit(); + } } diff --git a/test/980-redefine-object/src/Main.java b/test/980-redefine-object/src/Main.java index a50215e1ad..63c0cab95e 100644 --- a/test/980-redefine-object/src/Main.java +++ b/test/980-redefine-object/src/Main.java @@ -14,6 +14,9 @@ * limitations under the License. */ +import static art.Redefinition.doCommonClassRedefinition; + +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Base64; import java.util.LinkedList; @@ -287,6 +290,31 @@ public class Main { private static final String LISTENER_LOCATION = System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar"; + private static Method doEnableReporting; + private static Method doDisableReporting; + + private static void DisableReporting() { + if (doDisableReporting == null) { + return; + } + try { + doDisableReporting.invoke(null); + } catch (Exception e) { + throw new Error("Unable to disable reporting!"); + } + } + + private static void EnableReporting() { + if (doEnableReporting == null) { + return; + } + try { + doEnableReporting.invoke(null); + } catch (Exception e) { + throw new Error("Unable to enable reporting!"); + } + } + public static void main(String[] args) { art.Main.bindAgentJNIForClass(Main.class); doTest(); @@ -298,8 +326,8 @@ public class Main { addToBootClassLoader(LISTENER_LOCATION); // Load TestWatcher from the bootclassloader and make sure it is initialized. Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null); - // Bind the native functions of testwatcher_class. - bindFunctionsForClass(testwatcher_class); + doEnableReporting = testwatcher_class.getDeclaredMethod("EnableReporting"); + doDisableReporting = testwatcher_class.getDeclaredMethod("DisableReporting"); } catch (Exception e) { throw new Error("Exception while making testwatcher", e); } @@ -308,9 +336,9 @@ public class Main { // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called. private static void safePrintln(Object o) { - System.out.flush(); - System.out.print("\t" + o + "\n"); - System.out.flush(); + DisableReporting(); + System.out.println("\t" + o); + EnableReporting(); } private static void throwFrom(int depth) throws Exception { @@ -381,11 +409,4 @@ public class Main { } private static native void addToBootClassLoader(String s); - - private static native void bindFunctionsForClass(Class<?> target); - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); } diff --git a/test/980-redefine-object/src/art/Redefinition.java b/test/980-redefine-object/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/980-redefine-object/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/981-dedup-original-dex/src/Main.java b/test/981-dedup-original-dex/src/Main.java index 288f7ce4e0..f90c15ce8a 100644 --- a/test/981-dedup-original-dex/src/Main.java +++ b/test/981-dedup-original-dex/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,190 +14,8 @@ * limitations under the License. */ -import java.lang.reflect.Field; -import java.util.Base64; -import java.nio.ByteBuffer; - -import dalvik.system.ClassExt; -import dalvik.system.InMemoryDexClassLoader; - public class Main { - - /** - * base64 encoded class/dex file for - * class Transform { - * public void sayHi() { - * System.out.println("Goodbye"); - * } - * } - */ - private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode( - "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + - "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + - "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + - "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + - "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + - "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + - "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + - "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + - "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); - - /** - * base64 encoded class/dex file for - * class Transform2 { - * public void sayHi() { - * System.out.println("Goodbye2"); - * } - * } - */ - private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode( - "ZGV4CjAzNQAjXDED2iflQ3NXbPtBRVjQVMqoDU9nDz/QAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + - "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" + - "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTIADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJp" + - "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + - "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" + - "A291dAAHcHJpbnRsbgAFc2F5SGkAAQAHDgADAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" + - "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + - "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + - "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA"); - - - /** - * base64 encoded class/dex file for - * class Transform3 { - * public void sayHi() { - * System.out.println("hello3"); - * } - * } - */ - private static final byte[] DEX_BYTES_3_INITIAL = Base64.getDecoder().decode( - "ZGV4CjAzNQC2W2fBsAeLNAwWYlG8FVigzfsV7nBWITzQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + - "AABqAQAAeAEAAI8BAACjAQAAtwEAAMsBAADcAQAA3wEAAOMBAAD3AQAA/wEAAAQCAAANAgAAAQAA" + - "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAB8CAAAA" + - "AAAAAQABAAEAAAAUAgAABAAAAHAQAwAAAA4AAwABAAIAAAAZAgAACQAAAGIAAAAbAQoAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAMTFRyYW5zZm9ybTM7ABVMamF2YS9pby9QcmludFN0cmVhbTsA" + - "EkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3Rl" + - "bTsAD1RyYW5zZm9ybTMuamF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2stNC4zMAAGaGVsbG8zAANv" + - "dXQAB3ByaW50bG4ABXNheUhpAAIABw4ABAAHDocAAAABAQCAgASgAgEBuAIAAAANAAAAAAAAAAEA" + - "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + - "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + - "AyAAAAIAAAAUAgAAACAAAAEAAAAfAgAAABAAAAEAAAAwAgAA"); - - /** - * base64 encoded class/dex file for - * class Transform3 { - * public void sayHi() { - * System.out.println("Goodbye3"); - * } - * } - */ - private static final byte[] DEX_BYTES_3_FINAL = Base64.getDecoder().decode( - "ZGV4CjAzNQBAXE5GthgMydaFBuinf+ZBfXcBYIw2UlXQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + - "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + - "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" + - "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + - "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" + - "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" + - "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTMADExUcmFuc2Zvcm0zOwAVTGphdmEvaW8vUHJp" + - "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + - "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0zLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" + - "A291dAAHcHJpbnRsbgAFc2F5SGkAAgAHDgAEAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" + - "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + - "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + - "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA"); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - try { - doTest(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static void assertSame(Object a, Object b) throws Exception { - if (a != b) { - throw new AssertionError("'" + (a != null ? a.toString() : "null") + "' is not the same as " + - "'" + (b != null ? b.toString() : "null") + "'"); - } - } - - private static Object getObjectField(Object o, String name) throws Exception { - return getObjectField(o, o.getClass(), name); - } - - private static Object getObjectField(Object o, Class<?> type, String name) throws Exception { - Field f = type.getDeclaredField(name); - f.setAccessible(true); - return f.get(o); - } - - private static Object getOriginalDexFile(Class<?> k) throws Exception { - ClassExt ext_data_object = (ClassExt) getObjectField(k, "extData"); - if (ext_data_object == null) { - return null; - } - - return getObjectField(ext_data_object, "originalDexFile"); + public static void main(String[] args) throws Exception { + art.Test981.run(); } - - public static void doTest() throws Exception { - // Make sure both of these are loaded prior to transformations being added so they have the same - // original dex files. - Transform t1 = new Transform(); - Transform2 t2 = new Transform2(); - - assertSame(null, getOriginalDexFile(t1.getClass())); - assertSame(null, getOriginalDexFile(t2.getClass())); - assertSame(null, getOriginalDexFile(Main.class)); - - addCommonTransformationResult("Transform", new byte[0], DEX_BYTES_1); - addCommonTransformationResult("Transform2", new byte[0], DEX_BYTES_2); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class, Transform2.class); - - assertSame(getOriginalDexFile(t1.getClass()), getOriginalDexFile(t2.getClass())); - assertSame(null, getOriginalDexFile(Main.class)); - // Make sure that the original dex file is a DexCache object. - assertSame(getOriginalDexFile(t1.getClass()).getClass(), Class.forName("java.lang.DexCache")); - - // Check that we end up with a byte[] if we do a direct RedefineClasses - enableCommonRetransformation(false); - doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES_1); - assertSame((new byte[0]).getClass(), getOriginalDexFile(t1.getClass()).getClass()); - - // Check we don't have anything if we don't have any originalDexFile if the onload - // transformation doesn't do anything. - enableCommonRetransformation(true); - Class<?> transform3Class = new InMemoryDexClassLoader( - ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Main.class.getClassLoader()).loadClass("Transform3"); - assertSame(null, getOriginalDexFile(transform3Class)); - - // Check that we end up with a java.lang.Long pointer if we do an 'on-load' redefinition. - addCommonTransformationResult("Transform3", new byte[0], DEX_BYTES_3_FINAL); - enableCommonRetransformation(true); - Class<?> transform3ClassTransformed = new InMemoryDexClassLoader( - ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Main.class.getClassLoader()).loadClass("Transform3"); - assertSame(Long.class, getOriginalDexFile(transform3ClassTransformed).getClass()); - } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void doCommonClassRedefinition(Class<?> target, - byte[] class_file, - byte[] dex_file); - private static native void enableCommonRetransformation(boolean enable); - private static native void addCommonTransformationResult(String target_name, - byte[] class_bytes, - byte[] dex_bytes); } diff --git a/test/981-dedup-original-dex/src/Transform.java b/test/981-dedup-original-dex/src/Transform.java deleted file mode 100644 index 3c97907ddc..0000000000 --- a/test/981-dedup-original-dex/src/Transform.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - System.out.println("hello"); - } -} diff --git a/test/981-dedup-original-dex/src/Transform2.java b/test/981-dedup-original-dex/src/Transform2.java deleted file mode 100644 index eb22842184..0000000000 --- a/test/981-dedup-original-dex/src/Transform2.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform2 { - public void sayHi() { - System.out.println("hello2"); - } -} diff --git a/test/981-dedup-original-dex/src/art/Redefinition.java b/test/981-dedup-original-dex/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/981-dedup-original-dex/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/981-dedup-original-dex/src/art/Test981.java b/test/981-dedup-original-dex/src/art/Test981.java new file mode 100644 index 0000000000..3a97268ef9 --- /dev/null +++ b/test/981-dedup-original-dex/src/art/Test981.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.lang.reflect.Field; +import java.util.Base64; +import java.nio.ByteBuffer; + +import dalvik.system.ClassExt; +import dalvik.system.InMemoryDexClassLoader; + +public class Test981 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); + } + } + + static class Transform2 { + public void sayHi() { + System.out.println("hello2"); + } + } + + /** + * base64 encoded class/dex file for + * static class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode( + "ZGV4CjAzNQB+giqQAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" + + "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" + + "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" + + "TGFydC9UZXN0OTgxJFRyYW5zZm9ybTsADUxhcnQvVGVzdDk4MTsAIkxkYWx2aWsvYW5ub3RhdGlv" + + "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" + + "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" + + "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTgxLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" + + "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" + + "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" + + "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" + + "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" + + "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" + + "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" + + "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="); + + /** + * base64 encoded class/dex file for + * static class Transform2 { + * public void sayHi() { + * System.out.println("Goodbye2"); + * } + * } + */ + private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode( + "ZGV4CjAzNQAhg+RVAAAAAAAAAAAAAAAAAAAAAAAAAAC8AwAAcAAAAHhWNBIAAAAAAAAAAPgCAAAU" + + "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB4AgAARAEAAEQB" + + "AABMAQAAVgEAAHABAAB/AQAAowEAAMMBAADaAQAA7gEAAAICAAAWAgAAJAIAADACAAAzAgAANwIA" + + "AEQCAABKAgAATwIAAFgCAABfAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + + "DAAAAAgAAAAAAAAADQAAAAgAAABoAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + + "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA6AIAALwCAAAAAAAABjxpbml0PgAIR29vZGJ5ZTIA" + + "GExhcnQvVGVzdDk4MSRUcmFuc2Zvcm0yOwANTGFydC9UZXN0OTgxOwAiTGRhbHZpay9hbm5vdGF0" + + "aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2" + + "YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7" + + "ABJMamF2YS9sYW5nL1N5c3RlbTsADFRlc3Q5ODEuamF2YQAKVHJhbnNmb3JtMgABVgACVkwAC2Fj" + + "Y2Vzc0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAAEAAAAGAAAACgAH" + + "DgAMAAcOAQgPAAAAAAEAAQABAAAAcAIAAAQAAABwEAMAAAAOAAMAAQACAAAAdQIAAAkAAABiAAAA" + + "GwEBAAAAbiACABAADgAAAAAAAQEAgIAEgAUBAZgFAAACAgETGAECAwIOBAgPFwsAAgAAAMwCAADS" + + "AgAA3AIAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAAFAAAAHAAAAACAAAACQAAAMAA" + + "AAADAAAAAgAAAOQAAAAEAAAAAQAAAPwAAAAFAAAABAAAAAQBAAAGAAAAAQAAACQBAAACIAAAFAAA" + + "AEQBAAABEAAAAQAAAGgCAAADIAAAAgAAAHACAAABIAAAAgAAAIACAAAAIAAAAQAAALwCAAAEIAAA" + + "AgAAAMwCAAADEAAAAQAAANwCAAAGIAAAAQAAAOgCAAAAEAAAAQAAAPgCAAA="); + + /** + * base64 encoded class/dex file for + * class Transform3 { + * public void sayHi() { + * System.out.println("hello3"); + * } + * } + */ + private static final byte[] DEX_BYTES_3_INITIAL = Base64.getDecoder().decode( + "ZGV4CjAzNQC2W2fBsAeLNAwWYlG8FVigzfsV7nBWITzQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + + "AABqAQAAeAEAAI8BAACjAQAAtwEAAMsBAADcAQAA3wEAAOMBAAD3AQAA/wEAAAQCAAANAgAAAQAA" + + "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAB8CAAAA" + + "AAAAAQABAAEAAAAUAgAABAAAAHAQAwAAAA4AAwABAAIAAAAZAgAACQAAAGIAAAAbAQoAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgAMTFRyYW5zZm9ybTM7ABVMamF2YS9pby9QcmludFN0cmVhbTsA" + + "EkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3Rl" + + "bTsAD1RyYW5zZm9ybTMuamF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2stNC4zMAAGaGVsbG8zAANv" + + "dXQAB3ByaW50bG4ABXNheUhpAAIABw4ABAAHDocAAAABAQCAgASgAgEBuAIAAAANAAAAAAAAAAEA" + + "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + + "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + + "AyAAAAIAAAAUAgAAACAAAAEAAAAfAgAAABAAAAEAAAAwAgAA"); + + /** + * base64 encoded class/dex file for + * class Transform3 { + * public void sayHi() { + * System.out.println("Goodbye3"); + * } + * } + */ + private static final byte[] DEX_BYTES_3_FINAL = Base64.getDecoder().decode( + "ZGV4CjAzNQBAXE5GthgMydaFBuinf+ZBfXcBYIw2UlXQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + + "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" + + "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" + + "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTMADExUcmFuc2Zvcm0zOwAVTGphdmEvaW8vUHJp" + + "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + + "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0zLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" + + "A291dAAHcHJpbnRsbgAFc2F5SGkAAgAHDgAEAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" + + "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + + "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + + "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA"); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM); + doTest(); + } + + private static void assertSame(Object a, Object b) throws Exception { + if (a != b) { + throw new AssertionError("'" + (a != null ? a.toString() : "null") + "' is not the same as " + + "'" + (b != null ? b.toString() : "null") + "'"); + } + } + + private static Object getObjectField(Object o, String name) throws Exception { + return getObjectField(o, o.getClass(), name); + } + + private static Object getObjectField(Object o, Class<?> type, String name) throws Exception { + Field f = type.getDeclaredField(name); + f.setAccessible(true); + return f.get(o); + } + + private static Object getOriginalDexFile(Class<?> k) throws Exception { + ClassExt ext_data_object = (ClassExt) getObjectField(k, "extData"); + if (ext_data_object == null) { + return null; + } + + return getObjectField(ext_data_object, "originalDexFile"); + } + + public static void doTest() throws Exception { + // Make sure both of these are loaded prior to transformations being added so they have the same + // original dex files. + Transform t1 = new Transform(); + Transform2 t2 = new Transform2(); + + assertSame(null, getOriginalDexFile(t1.getClass())); + assertSame(null, getOriginalDexFile(t2.getClass())); + assertSame(null, getOriginalDexFile(Test981.class)); + + Redefinition.addCommonTransformationResult("art/Test981$Transform", new byte[0], DEX_BYTES_1); + Redefinition.addCommonTransformationResult("art/Test981$Transform2", new byte[0], DEX_BYTES_2); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class, Transform2.class); + + assertSame(getOriginalDexFile(t1.getClass()), getOriginalDexFile(t2.getClass())); + assertSame(null, getOriginalDexFile(Test981.class)); + // Make sure that the original dex file is a DexCache object. + assertSame(getOriginalDexFile(t1.getClass()).getClass(), Class.forName("java.lang.DexCache")); + + // Check that we end up with a byte[] if we do a direct RedefineClasses + Redefinition.enableCommonRetransformation(false); + Redefinition.doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES_1); + assertSame((new byte[0]).getClass(), getOriginalDexFile(t1.getClass()).getClass()); + + // Check we don't have anything if we don't have any originalDexFile if the onload + // transformation doesn't do anything. + Redefinition.enableCommonRetransformation(true); + Class<?> transform3Class = new InMemoryDexClassLoader( + ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Test981.class.getClassLoader()).loadClass("Transform3"); + assertSame(null, getOriginalDexFile(transform3Class)); + + // Check that we end up with a java.lang.Long pointer if we do an 'on-load' redefinition. + Redefinition.addCommonTransformationResult("Transform3", new byte[0], DEX_BYTES_3_FINAL); + Redefinition.enableCommonRetransformation(true); + Class<?> transform3ClassTransformed = new InMemoryDexClassLoader( + ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Test981.class.getClassLoader()).loadClass("Transform3"); + assertSame(Long.class, getOriginalDexFile(transform3ClassTransformed).getClass()); + } +} diff --git a/test/982-ok-no-retransform/src/Main.java b/test/982-ok-no-retransform/src/Main.java index 33e50d77ba..bd73e81da6 100644 --- a/test/982-ok-no-retransform/src/Main.java +++ b/test/982-ok-no-retransform/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,22 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(new Transform()); - } - - public static void doTest(Transform t) { - t.sayHi(); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); - t.sayHi(); + public static void main(String[] args) throws Exception { + art.Test982.run(); } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); } diff --git a/test/982-ok-no-retransform/src/Transform.java b/test/982-ok-no-retransform/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/982-ok-no-retransform/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/982-ok-no-retransform/src/art/Redefinition.java b/test/982-ok-no-retransform/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/982-ok-no-retransform/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/942-private-recursive/src/Transform.java b/test/982-ok-no-retransform/src/art/Test982.java index 7714326066..080d47facc 100644 --- a/test/942-private-recursive/src/Transform.java +++ b/test/982-ok-no-retransform/src/art/Test982.java @@ -14,19 +14,26 @@ * limitations under the License. */ -class Transform { - private void privateSayHi(int recur, Runnable r) { - System.out.println("hello" + recur); - if (recur == 1) { - r.run(); - privateSayHi(recur - 1, r); - } else if (recur != 0) { - privateSayHi(recur - 1, r); +package art; + +import java.util.Base64; +public class Test982 { + + static class Transform { + public void sayHi() { + System.out.println("hello"); } - System.out.println("goodbye" + recur); } - public void sayHi(int recur, Runnable r) { - privateSayHi(recur, r); + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); + t.sayHi(); } } diff --git a/test/983-source-transform-verify/expected.txt b/test/983-source-transform-verify/expected.txt index 0a94212ad2..abcdf3a868 100644 --- a/test/983-source-transform-verify/expected.txt +++ b/test/983-source-transform-verify/expected.txt @@ -1,2 +1,2 @@ -Dex file hook for Transform +Dex file hook for art/Test983$Transform Dex file hook for java/lang/Object diff --git a/test/983-source-transform-verify/src/Main.java b/test/983-source-transform-verify/src/Main.java index ad081a2006..e1d20f6678 100644 --- a/test/983-source-transform-verify/src/Main.java +++ b/test/983-source-transform-verify/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,23 +14,8 @@ * limitations under the License. */ -import java.util.Base64; public class Main { - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(); - } - - public static void doTest() { - Transform abc = new Transform(); - enableCommonRetransformation(true); - doCommonClassRetransformation(Transform.class); - doCommonClassRetransformation(Object.class); - enableCommonRetransformation(false); + public static void main(String[] args) throws Exception { + art.Test983.run(); } - - // Transforms the class - private static native void doCommonClassRetransformation(Class<?>... target); - private static native void enableCommonRetransformation(boolean enable); } diff --git a/test/983-source-transform-verify/src/Transform.java b/test/983-source-transform-verify/src/Transform.java deleted file mode 100644 index 8e8af355da..0000000000 --- a/test/983-source-transform-verify/src/Transform.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - public void sayHi() { - // Use lower 'h' to make sure the string will have a different string id - // than the transformation (the transformation code is the same except - // the actual printed String, which was making the test inacurately passing - // in JIT mode when loading the string from the dex cache, as the string ids - // of the two different strings were the same). - // We know the string ids will be different because lexicographically: - // "Goodbye" < "LTransform;" < "hello". - System.out.println("hello"); - } -} diff --git a/test/983-source-transform-verify/src/art/Redefinition.java b/test/983-source-transform-verify/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/983-source-transform-verify/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/915-obsolete-2/src/Transform.java b/test/983-source-transform-verify/src/art/Test983.java index e914e29479..b81e7f4df3 100644 --- a/test/915-obsolete-2/src/Transform.java +++ b/test/983-source-transform-verify/src/art/Test983.java @@ -14,22 +14,25 @@ * limitations under the License. */ -class Transform { - private void Start() { - System.out.println("hello - private"); +package art; + +import java.util.Base64; +public class Test983 { + static class Transform { + public void sayHi() { + System.out.println("hello"); + } } - private void Finish() { - System.out.println("goodbye - private"); + public static void run() { + doTest(); } - public void sayHi(Runnable r) { - System.out.println("Pre Start private method call"); - Start(); - System.out.println("Post Start private method call"); - r.run(); - System.out.println("Pre Finish private method call"); - Finish(); - System.out.println("Post Finish private method call"); + public static void doTest() { + Transform abc = new Transform(); + Redefinition.enableCommonRetransformation(true); + Redefinition.doCommonClassRetransformation(Transform.class); + Redefinition.doCommonClassRetransformation(Object.class); + Redefinition.enableCommonRetransformation(false); } } diff --git a/test/984-obsolete-invoke/obsolete_invoke.cc b/test/984-obsolete-invoke/obsolete_invoke.cc index 27e36ba509..ab2499aa62 100644 --- a/test/984-obsolete-invoke/obsolete_invoke.cc +++ b/test/984-obsolete-invoke/obsolete_invoke.cc @@ -17,20 +17,20 @@ #include "android-base/macros.h" #include "jni.h" #include "jvmti.h" -#include "mirror/class-inl.h" -#include "scoped_local_ref.h" // Test infrastructure #include "test_env.h" #include "jvmti_helper.h" +#include "scoped_local_ref.h" namespace art { namespace Test984ObsoleteInvoke { static constexpr size_t kNumFrames = 30; -extern "C" JNIEXPORT jobject JNICALL Java_Main_getFirstObsoleteMethod984(JNIEnv* env, jclass) { +extern "C" JNIEXPORT jobject JNICALL Java_art_Test984_getFirstObsoleteMethod984(JNIEnv* env, + jclass) { jthread cur; jint frame_count; jvmtiFrameInfo frames[kNumFrames]; diff --git a/test/984-obsolete-invoke/src/Main.java b/test/984-obsolete-invoke/src/Main.java index 418d64d906..04a368dcd4 100644 --- a/test/984-obsolete-invoke/src/Main.java +++ b/test/984-obsolete-invoke/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,96 +14,8 @@ * limitations under the License. */ -import java.lang.reflect.Method; -import java.util.Base64; - public class Main { - // class Transform { - // public static void sayHi(Runnable r) { - // System.out.println("Hello - Transformed"); - // r.run(); - // System.out.println("Goodbye - Transformed"); - // } - // } - private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( - "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" + - "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + - "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" + - "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" + - "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" + - "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" + - "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" + - "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQAJAA0ADgABAAsAAAA7AAIA" + - "AQAAABeyAAISA7YABCq5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" + - "AQAPAAAAAgAQ"); - private static final byte[] DEX_BYTES = Base64.getDecoder().decode( - "ZGV4CjAzNQCMekj2NPwzrEp/v+2yzzSg8xZvBtU1bC1QAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" + - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" + - "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" + - "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" + - "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" + - "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" + - "AwAAAA4AAwABAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAgBiAAAAGwEBAAAAbiAC" + - "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" + - "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" + - "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" + - "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" + - "LjMxAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAIAAICABMQCAQnc" + - "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" + - "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" + - "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA="); - - public static void main(String[] args) { - art.Main.bindAgentJNIForClass(Main.class); - doTest(); + public static void main(String[] args) throws Exception { + art.Test984.run(); } - - // The Method that holds an obsolete method pointer. We will fill it in by getting a jmethodID - // from a stack with an obsolete method in it. There should be no other ways to obtain an obsolete - // jmethodID in ART without unsafe casts. - public static Method obsolete_method = null; - - public static void doTest() { - // Capture the obsolete method. - // - // NB The obsolete method must be direct so that we will not look in the receiver type to get - // the actual method. - Transform.sayHi(() -> { - System.out.println("transforming calling function"); - doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); - System.out.println("Retrieving obsolete method from current stack"); - // This should get the obsolete sayHi method (as the only obsolete method on the current - // threads stack). - Main.obsolete_method = getFirstObsoleteMethod984(); - }); - - // Prove we did actually redefine something. - System.out.println("Invoking redefined version of method."); - Transform.sayHi(() -> { System.out.println("Not doing anything here"); }); - - System.out.println("invoking obsolete method"); - try { - obsolete_method.invoke(null, (Runnable)() -> { - throw new Error("Unexpected code running from invoke of obsolete method!"); - }); - throw new Error("Running obsolete method did not throw exception"); - } catch (Throwable e) { - if (e instanceof InternalError || e.getCause() instanceof InternalError) { - System.out.println("Caught expected error from attempting to invoke an obsolete method."); - } else { - System.out.println("Unexpected error type for calling obsolete method! Expected either " - + "an InternalError or something that is caused by an InternalError."); - throw new Error("Unexpected error caught: ", e); - } - } - } - - // Transforms the class - private static native void doCommonClassRedefinition(Class<?> target, - byte[] classfile, - byte[] dexfile); - - // Gets the first obsolete method on the current threads stack (NB only looks through the first 30 - // stack frames). - private static native Method getFirstObsoleteMethod984(); } diff --git a/test/984-obsolete-invoke/src/Transform.java b/test/984-obsolete-invoke/src/Transform.java deleted file mode 100644 index 536de84c46..0000000000 --- a/test/984-obsolete-invoke/src/Transform.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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. - */ - -class Transform { - // This method must be 'static' so that when we try to invoke it through a j.l.r.Method we will - // simply use the jmethodID directly and not do any lookup in any receiver object. - public static void sayHi(Runnable r) { - System.out.println("hello"); - r.run(); - System.out.println("goodbye"); - } -} diff --git a/test/984-obsolete-invoke/src/art/Redefinition.java b/test/984-obsolete-invoke/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/984-obsolete-invoke/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/984-obsolete-invoke/src/art/Test984.java b/test/984-obsolete-invoke/src/art/Test984.java new file mode 100644 index 0000000000..3fe66f68bf --- /dev/null +++ b/test/984-obsolete-invoke/src/art/Test984.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 art; + +import java.lang.reflect.Method; +import java.util.Base64; + +public class Test984 { + + static class Transform { + // This method must be 'static' so that when we try to invoke it through a j.l.r.Method we will + // simply use the jmethodID directly and not do any lookup in any receiver object. + public static void sayHi(Runnable r) { + System.out.println("hello"); + r.run(); + System.out.println("goodbye"); + } + } + // static class Transform { + // public static void sayHi(Runnable r) { + // System.out.println("Hello - Transformed"); + // r.run(); + // System.out.println("Goodbye - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + + "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + + "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk4NC5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + + "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + + "L1Rlc3Q5ODQkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + + "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + + "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + + "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTg0ACAABwAIAAAAAAACAAAACQAK" + + "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQAJAA0ADgABAAsAAAA7AAIAAQAA" + + "ABeyAAISA7YABCq5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" + + "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQB/mxSMAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + + "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + + "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + + "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + + "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + + "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + + "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5ODQkVHJhbnNmb3JtOwANTGFydC9UZXN0OTg0OwAiTGRh" + + "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + + "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + + "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + + "ZXN0OTg0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + + "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" + + "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAMAAQACAAAA3QIAABQAAABiAAAAGwECAAAA" + + "biACABAAchAEAAIAYgAAABsBAQAAAG4gAgAQAA4AAAACAACAgATsBQEJhAYAAAICARYYAQIDAhAE" + + "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + + "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + + "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + + "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + + "AA=="); + + public static void run() { + art.Main.bindAgentJNIForClass(Test984.class); + doTest(); + } + + // The Method that holds an obsolete method pointer. We will fill it in by getting a jmethodID + // from a stack with an obsolete method in it. There should be no other ways to obtain an obsolete + // jmethodID in ART without unsafe casts. + public static Method obsolete_method = null; + + public static void doTest() { + // Capture the obsolete method. + // + // NB The obsolete method must be direct so that we will not look in the receiver type to get + // the actual method. + Transform.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + System.out.println("Retrieving obsolete method from current stack"); + // This should get the obsolete sayHi method (as the only obsolete method on the current + // threads stack). + Test984.obsolete_method = getFirstObsoleteMethod984(); + }); + + // Prove we did actually redefine something. + System.out.println("Invoking redefined version of method."); + Transform.sayHi(() -> { System.out.println("Not doing anything here"); }); + + System.out.println("invoking obsolete method"); + try { + obsolete_method.invoke(null, (Runnable)() -> { + throw new Error("Unexpected code running from invoke of obsolete method!"); + }); + throw new Error("Running obsolete method did not throw exception"); + } catch (Throwable e) { + if (e instanceof InternalError || e.getCause() instanceof InternalError) { + System.out.println("Caught expected error from attempting to invoke an obsolete method."); + } else { + System.out.println("Unexpected error type for calling obsolete method! Expected either " + + "an InternalError or something that is caused by an InternalError."); + throw new Error("Unexpected error caught: ", e); + } + } + } + + // Gets the first obsolete method on the current threads stack (NB only looks through the first 30 + // stack frames). + private static native Method getFirstObsoleteMethod984(); +} diff --git a/test/985-re-obsolete/expected.txt b/test/985-re-obsolete/expected.txt new file mode 100644 index 0000000000..5159a00f43 --- /dev/null +++ b/test/985-re-obsolete/expected.txt @@ -0,0 +1,35 @@ +Pre Start private method call +hello - private +Post Start private method call +Not doing anything here +Pre Finish private method call +goodbye - private +Post Finish private method call +Pre Start private method call +hello - private +Post Start private method call +transforming calling function +Pre Finish private method call +Goodbye - private - Transformed +Post Finish private method call +Pre Start private method call - Transformed +Hello - private - Transformed +Post Start private method call - Transformed +Not doing anything here +Pre Finish private method call - Transformed +Goodbye - private - Transformed +Post Finish private method call - Transformed +Pre Start private method call - Transformed +Hello - private - Transformed +Post Start private method call - Transformed +transforming calling function +Pre Finish private method call - Transformed +second - Goodbye - private - Transformed +Post Finish private method call - Transformed +second - Pre Start private method call - Transformed +second - Hello - private - Transformed +second - Post Start private method call - Transformed +Not doing anything here +second - Pre Finish private method call - Transformed +second - Goodbye - private - Transformed +second - Post Finish private method call - Transformed diff --git a/test/985-re-obsolete/info.txt b/test/985-re-obsolete/info.txt new file mode 100644 index 0000000000..c8eafdc723 --- /dev/null +++ b/test/985-re-obsolete/info.txt @@ -0,0 +1,4 @@ +Tests basic obsolete method support + +Regression test for b/37475600 which was caused by incorrectly checking for +differences in the obsolete methods map. diff --git a/test/985-re-obsolete/run b/test/985-re-obsolete/run new file mode 100755 index 0000000000..e92b873956 --- /dev/null +++ b/test/985-re-obsolete/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2017 The Android Open Source Project +# +# 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. + +./default-run "$@" --jvmti diff --git a/test/912-classes/src-ex/A.java b/test/985-re-obsolete/src/Main.java index 2c43cfbd79..d78d591f47 100644 --- a/test/912-classes/src-ex/A.java +++ b/test/985-re-obsolete/src/Main.java @@ -14,5 +14,8 @@ * limitations under the License. */ -public class A { +public class Main { + public static void main(String[] args) throws Exception { + art.Test985.run(); + } } diff --git a/test/926-multi-obsolescence/src/CommonClassDefinition.java b/test/985-re-obsolete/src/art/Main.java index 62602a02e9..8b01920638 100644 --- a/test/926-multi-obsolescence/src/CommonClassDefinition.java +++ b/test/985-re-obsolete/src/art/Main.java @@ -14,14 +14,15 @@ * limitations under the License. */ -class CommonClassDefinition { - public final Class<?> target; - public final byte[] class_file_bytes; - public final byte[] dex_file_bytes; +package art; - CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { - this.target = target; - this.class_file_bytes = class_file_bytes; - this.dex_file_bytes = dex_file_bytes; - } +// Binder class so the agent's C code has something that can be bound and exposed to tests. +// In a package to separate cleanly and work around CTS reference issues (though this class +// should be replaced in the CTS version). +public class Main { + // Load the given class with the given classloader, and bind all native methods to corresponding + // C methods in the agent. Will abort if any of the steps fail. + public static native void bindAgentJNI(String className, ClassLoader classLoader); + // Same as above, giving the class directly. + public static native void bindAgentJNIForClass(Class<?> klass); } diff --git a/test/985-re-obsolete/src/art/Redefinition.java b/test/985-re-obsolete/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/985-re-obsolete/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/985-re-obsolete/src/art/Test985.java b/test/985-re-obsolete/src/art/Test985.java new file mode 100644 index 0000000000..405abd5d14 --- /dev/null +++ b/test/985-re-obsolete/src/art/Test985.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.Base64; + +public class Test985 { + + static class Transform { + private void Start() { + System.out.println("hello - private"); + } + + private void Finish() { + System.out.println("goodbye - private"); + } + + public void sayHi(Runnable r) { + System.out.println("Pre Start private method call"); + Start(); + System.out.println("Post Start private method call"); + r.run(); + System.out.println("Pre Finish private method call"); + Finish(); + System.out.println("Post Finish private method call"); + } + } + + // static class Transform { + // private void Start() { + // System.out.println("Hello - private - Transformed"); + // } + // + // private void Finish() { + // System.out.println("Goodbye - private - Transformed"); + // } + // + // public void sayHi(Runnable r) { + // System.out.println("Pre Start private method call - Transformed"); + // Start(); + // System.out.println("Post Start private method call - Transformed"); + // r.run(); + // System.out.println("Pre Finish private method call - Transformed"); + // Finish(); + // System.out.println("Post Finish private method call - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES_1 = Base64.getDecoder().decode( + "yv66vgAAADQANgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" + + "JwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" + + "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAM" + + "VGVzdDk4NS5qYXZhDAAPABAHAC0MAC4ALwEAHUhlbGxvIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVk" + + "BwAwDAAxADIBAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkAQArUHJlIFN0YXJ0IHBy" + + "aXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAwAEwAQAQAsUG9zdCBTdGFydCBwcml2YXRl" + + "IG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQHADMMADQAEAEALFByZSBGaW5pc2ggcHJpdmF0ZSBt" + + "ZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAUABABAC1Qb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhv" + + "ZCBjYWxsIC0gVHJhbnNmb3JtZWQHADUBABVhcnQvVGVzdDk4NSRUcmFuc2Zvcm0BAAlUcmFuc2Zv" + + "cm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEA" + + "A291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmlu" + + "dGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuAQAL" + + "YXJ0L1Rlc3Q5ODUAIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAABABIA" + + "AAAGAAEAAAAEAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAAAAYA" + + "CAAHAAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAkACAAKAAEA" + + "FQAWAAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQqtwAL" + + "sgACEgy2AASxAAAAAQASAAAAIgAIAAAADAAIAA0ADAAOABQADwAaABAAIgARACYAEgAuABMAAgAX" + + "AAAAAgAYACsAAAAKAAEADQAoACoACA=="); + private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode( + "ZGV4CjAzNQAh+CJbAAAAAAAAAAAAAAAAAAAAAAAAAADUBQAAcAAAAHhWNBIAAAAAAAAAABAFAAAd" + + "AAAAcAAAAAoAAADkAAAAAwAAAAwBAAABAAAAMAEAAAcAAAA4AQAAAQAAAHABAABEBAAAkAEAAJAB" + + "AACYAQAAoAEAAMEBAADgAQAA+QEAAAgCAAAsAgAATAIAAGMCAAB3AgAAjQIAAKECAAC1AgAA5AIA" + + "ABIDAABAAwAAbQMAAHQDAACCAwAAjQMAAJADAACUAwAAoQMAAKcDAACsAwAAtQMAALoDAADBAwAA" + + "BAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAAFAAAABQAAAAJAAAAAAAAABUAAAAJ" + + "AAAA0AMAABUAAAAJAAAAyAMAAAgABAAYAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAARAAAAAAABABsA" + + "AAAEAAIAGQAAAAUAAAAAAAAABgAAABoAAAAAAAAAAAAAAAUAAAAAAAAAEgAAAAAFAADMBAAAAAAA" + + "AAY8aW5pdD4ABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVsbG8g" + + "LSBwcml2YXRlIC0gVHJhbnNmb3JtZWQAF0xhcnQvVGVzdDk4NSRUcmFuc2Zvcm07AA1MYXJ0L1Rl" + + "c3Q5ODU7ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90" + + "YXRpb24vSW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmpl" + + "Y3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5n" + + "L1N5c3RlbTsALVBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAs" + + "UG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALFByZSBGaW5pc2gg" + + "cHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkACtQcmUgU3RhcnQgcHJpdmF0ZSBtZXRo" + + "b2QgY2FsbCAtIFRyYW5zZm9ybWVkAAVTdGFydAAMVGVzdDk4NS5qYXZhAAlUcmFuc2Zvcm0AAVYA" + + "AlZMAAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxuAANydW4ABXNheUhpAAV2YWx1ZQAB" + + "AAAABwAAAAEAAAAGAAAABAAHDgAJAAcOAQgPAAYABw4BCA8ADAEABw4BCA8BAw8BCA8BAw8BCA8B" + + "Aw8BCA8AAQABAAEAAADYAwAABAAAAHAQBQAAAA4AAwABAAIAAADdAwAACQAAAGIAAAAbAQIAAABu" + + "IAQAEAAOAAAAAwABAAIAAADlAwAACQAAAGIAAAAbAQMAAABuIAQAEAAOAAAABAACAAIAAADtAwAA" + + "KgAAAGIAAAAbARAAAABuIAQAEABwEAIAAgBiAAAAGwEOAAAAbiAEABAAchAGAAMAYgAAABsBDwAA" + + "AG4gBAAQAHAQAQACAGIAAAAbAQ0AAABuIAQAEAAOAAAAAwEAgIAEiAgBAqAIAQLECAMB6AgAAAIC" + + "ARwYAQIDAhYECBcXEwACAAAA5AQAAOoEAAD0BAAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAA" + + "AAEAAAAdAAAAcAAAAAIAAAAKAAAA5AAAAAMAAAADAAAADAEAAAQAAAABAAAAMAEAAAUAAAAHAAAA" + + "OAEAAAYAAAABAAAAcAEAAAIgAAAdAAAAkAEAAAEQAAACAAAAyAMAAAMgAAAEAAAA2AMAAAEgAAAE" + + "AAAACAQAAAAgAAABAAAAzAQAAAQgAAACAAAA5AQAAAMQAAABAAAA9AQAAAYgAAABAAAAAAUAAAAQ" + + "AAABAAAAEAUAAA=="); + + // static class Transform { + // private void Start() { + // System.out.println("second - Hello - private - Transformed"); + // } + // + // private void Finish() { + // System.out.println("second - Goodbye - private - Transformed"); + // } + // + // public void sayHi(Runnable r) { + // System.out.println("second - Pre Start private method call - Transformed"); + // Start(); + // System.out.println("second - Post Start private method call - Transformed"); + // r.run(); + // System.out.println("second - Pre Finish private method call - Transformed"); + // Finish(); + // System.out.println("second - Post Finish private method call - Transformed"); + // } + // } + private static final byte[] CLASS_BYTES_2 = Base64.getDecoder().decode( + "yv66vgAAADQANgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" + + "JwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" + + "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAM" + + "VGVzdDk4NS5qYXZhDAAPABAHAC0MAC4ALwEAJnNlY29uZCAtIEhlbGxvIC0gcHJpdmF0ZSAtIFRy" + + "YW5zZm9ybWVkBwAwDAAxADIBAChzZWNvbmQgLSBHb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9y" + + "bWVkAQA0c2Vjb25kIC0gUHJlIFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1l" + + "ZAwAEwAQAQA1c2Vjb25kIC0gUG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNm" + + "b3JtZWQHADMMADQAEAEANXNlY29uZCAtIFByZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAt" + + "IFRyYW5zZm9ybWVkDAAUABABADZzZWNvbmQgLSBQb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhvZCBj" + + "YWxsIC0gVHJhbnNmb3JtZWQHADUBABVhcnQvVGVzdDk4NSRUcmFuc2Zvcm0BAAlUcmFuc2Zvcm0B" + + "AAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291" + + "dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxu" + + "AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuAQALYXJ0" + + "L1Rlc3Q5ODUAIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAABABIAAAAG" + + "AAEAAAAEAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAAAAYACAAH" + + "AAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAkACAAKAAEAFQAW" + + "AAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQqtwALsgAC" + + "Egy2AASxAAAAAQASAAAAIgAIAAAADAAIAA0ADAAOABQADwAaABAAIgARACYAEgAuABMAAgAXAAAA" + + "AgAYACsAAAAKAAEADQAoACoACA=="); + private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode( + "ZGV4CjAzNQBw/x+UAAAAAAAAAAAAAAAAAAAAAAAAAAAMBgAAcAAAAHhWNBIAAAAAAAAAAEgFAAAd" + + "AAAAcAAAAAoAAADkAAAAAwAAAAwBAAABAAAAMAEAAAcAAAA4AQAAAQAAAHABAAB8BAAAkAEAAJAB" + + "AACYAQAAoAEAALkBAADIAQAA7AEAAAwCAAAjAgAANwIAAE0CAABhAgAAdQIAAHwCAACKAgAAlQIA" + + "AJgCAACcAgAAqQIAAK8CAAC0AgAAvQIAAMICAADJAgAA8wIAABsDAABTAwAAigMAAMEDAAD3AwAA" + + "AgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJ" + + "AAAACAQAAA8AAAAJAAAAAAQAAAgABAASAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAALAAAAAAABABUA" + + "AAAEAAIAEwAAAAUAAAAAAAAABgAAABQAAAAAAAAAAAAAAAUAAAAAAAAADAAAADgFAAAEBQAAAAAA" + + "AAY8aW5pdD4ABkZpbmlzaAAXTGFydC9UZXN0OTg1JFRyYW5zZm9ybTsADUxhcnQvVGVzdDk4NTsA" + + "IkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9J" + + "bm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAFExq" + + "YXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" + + "OwAFU3RhcnQADFRlc3Q5ODUuamF2YQAJVHJhbnNmb3JtAAFWAAJWTAALYWNjZXNzRmxhZ3MABG5h" + + "bWUAA291dAAHcHJpbnRsbgADcnVuAAVzYXlIaQAoc2Vjb25kIC0gR29vZGJ5ZSAtIHByaXZhdGUg" + + "LSBUcmFuc2Zvcm1lZAAmc2Vjb25kIC0gSGVsbG8gLSBwcml2YXRlIC0gVHJhbnNmb3JtZWQANnNl" + + "Y29uZCAtIFBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAA1c2Vj" + + "b25kIC0gUG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQANXNlY29u" + + "ZCAtIFByZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkADRzZWNvbmQg" + + "LSBQcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkAAV2YWx1ZQAAAAEA" + + "AAAHAAAAAQAAAAYAAAAEAAcOAAkABw4BCA8ABgAHDgEIDwAMAQAHDgEIDwEDDwEIDwEDDwEIDwED" + + "DwEIDwABAAEAAQAAABAEAAAEAAAAcBAFAAAADgADAAEAAgAAABUEAAAJAAAAYgAAABsBFgAAAG4g" + + "BAAQAA4AAAADAAEAAgAAAB0EAAAJAAAAYgAAABsBFwAAAG4gBAAQAA4AAAAEAAIAAgAAACUEAAAq" + + "AAAAYgAAABsBGwAAAG4gBAAQAHAQAgACAGIAAAAbARkAAABuIAQAEAByEAYAAwBiAAAAGwEaAAAA" + + "biAEABAAcBABAAIAYgAAABsBGAAAAG4gBAAQAA4AAAADAQCAgATACAEC2AgBAvwIAwGgCQAAAgIB" + + "HBgBAgMCEAQIERcNAAIAAAAcBQAAIgUAACwFAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAA" + + "AQAAAB0AAABwAAAAAgAAAAoAAADkAAAAAwAAAAMAAAAMAQAABAAAAAEAAAAwAQAABQAAAAcAAAA4" + + "AQAABgAAAAEAAABwAQAAAiAAAB0AAACQAQAAARAAAAIAAAAABAAAAyAAAAQAAAAQBAAAASAAAAQA" + + "AABABAAAACAAAAEAAAAEBQAABCAAAAIAAAAcBQAAAxAAAAEAAAAsBQAABiAAAAEAAAA4BQAAABAA" + + "AAEAAABIBQAA"); + + public static void run() { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES_1, DEX_BYTES_1); + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + t.sayHi(() -> { + System.out.println("transforming calling function"); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES_2, DEX_BYTES_2); + }); + t.sayHi(() -> { System.out.println("Not doing anything here"); }); + } +} diff --git a/test/986-native-method-bind/expected.txt b/test/986-native-method-bind/expected.txt new file mode 100644 index 0000000000..189217d761 --- /dev/null +++ b/test/986-native-method-bind/expected.txt @@ -0,0 +1,8 @@ +private static native void art.Test986$Transform.sayHi() = Java_art_Test986_00024Transform_sayHi -> Java_art_Test986_00024Transform_sayHi +Hello +private static native void art.Test986$Transform.sayHi() = Java_art_Test986_00024Transform_sayHi -> NoReallySayGoodbye +Bye +public static native void art.Main.bindAgentJNI(java.lang.String,java.lang.ClassLoader) = Java_art_Main_bindAgentJNI -> Java_art_Main_bindAgentJNI +public static native void art.Main.bindAgentJNIForClass(java.lang.Class) = Java_art_Main_bindAgentJNIForClass -> Java_art_Main_bindAgentJNIForClass +private static native void art.Test986.setNativeBindNotify(boolean) = Java_art_Test986_setNativeBindNotify -> Java_art_Test986_setNativeBindNotify +private static native void art.Test986.setupNativeBindNotify() = Java_art_Test986_setupNativeBindNotify -> Java_art_Test986_setupNativeBindNotify diff --git a/test/986-native-method-bind/info.txt b/test/986-native-method-bind/info.txt new file mode 100644 index 0000000000..1939936ca9 --- /dev/null +++ b/test/986-native-method-bind/info.txt @@ -0,0 +1 @@ +Tests native-method-bind callback and native method replacement. diff --git a/test/986-native-method-bind/native_bind.cc b/test/986-native-method-bind/native_bind.cc new file mode 100644 index 0000000000..4f93f87dfe --- /dev/null +++ b/test/986-native-method-bind/native_bind.cc @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ + +#include <inttypes.h> +#include <memory> +#include <stdio.h> +#include <dlfcn.h> + +#include "android-base/stringprintf.h" +#include "jni.h" +#include "jvmti.h" + +// Test infrastructure +#include "jni_binder.h" +#include "jvmti_helper.h" +#include "test_env.h" +#include "scoped_local_ref.h" + +namespace art { +namespace Test986NativeBind { + +static void doUpPrintCall(JNIEnv* env, const char* function) { + ScopedLocalRef<jclass> klass(env, env->FindClass("art/Test986")); + jmethodID targetMethod = env->GetStaticMethodID(klass.get(), function, "()V"); + env->CallStaticVoidMethod(klass.get(), targetMethod); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { + doUpPrintCall(env, "doSayHi"); +} + +extern "C" JNIEXPORT void JNICALL NoReallySayGoodbye(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { + doUpPrintCall(env, "doSayBye"); +} + +static void doJvmtiMethodBind(jvmtiEnv* jvmtienv ATTRIBUTE_UNUSED, + JNIEnv* env, + jthread thread ATTRIBUTE_UNUSED, + jmethodID m, + void* address, + /*out*/void** out_address) { + ScopedLocalRef<jclass> method_class(env, env->FindClass("java/lang/reflect/Method")); + ScopedLocalRef<jobject> method_obj(env, env->ToReflectedMethod(method_class.get(), m, false)); + Dl_info addr_info; + if (dladdr(address, &addr_info) == 0 || addr_info.dli_sname == nullptr) { + ScopedLocalRef<jclass> exception_class(env, env->FindClass("java/lang/Exception")); + env->ThrowNew(exception_class.get(), "dladdr failure!"); + return; + } + ScopedLocalRef<jstring> sym_name(env, env->NewStringUTF(addr_info.dli_sname)); + ScopedLocalRef<jclass> klass(env, env->FindClass("art/Test986")); + jmethodID upcallMethod = env->GetStaticMethodID( + klass.get(), + "doNativeMethodBind", + "(Ljava/lang/reflect/Method;Ljava/lang/String;)Ljava/lang/String;"); + if (env->ExceptionCheck()) { + return; + } + ScopedLocalRef<jstring> new_symbol(env, + reinterpret_cast<jstring>( + env->CallStaticObjectMethod(klass.get(), + upcallMethod, + method_obj.get(), + sym_name.get()))); + const char* new_symbol_chars = env->GetStringUTFChars(new_symbol.get(), nullptr); + if (strcmp(new_symbol_chars, addr_info.dli_sname) != 0) { + *out_address = dlsym(RTLD_DEFAULT, new_symbol_chars); + if (*out_address == nullptr) { + ScopedLocalRef<jclass> exception_class(env, env->FindClass("java/lang/Exception")); + env->ThrowNew(exception_class.get(), "dlsym failure!"); + return; + } + } + env->ReleaseStringUTFChars(new_symbol.get(), new_symbol_chars); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test986_setupNativeBindNotify( + JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) { + jvmtiEventCallbacks cb; + memset(&cb, 0, sizeof(cb)); + cb.NativeMethodBind = doJvmtiMethodBind; + jvmti_env->SetEventCallbacks(&cb, sizeof(cb)); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test986_setNativeBindNotify( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jboolean enable) { + jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE, + JVMTI_EVENT_NATIVE_METHOD_BIND, + nullptr); + if (res != JVMTI_ERROR_NONE) { + JvmtiErrorToException(env, jvmti_env, res); + } +} + +} // namespace Test986NativeBind +} // namespace art diff --git a/test/986-native-method-bind/run b/test/986-native-method-bind/run new file mode 100755 index 0000000000..e92b873956 --- /dev/null +++ b/test/986-native-method-bind/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2017 The Android Open Source Project +# +# 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. + +./default-run "$@" --jvmti diff --git a/test/912-classes/src-ex/C.java b/test/986-native-method-bind/src/Main.java index 97f8021486..fac9d8e2a9 100644 --- a/test/912-classes/src-ex/C.java +++ b/test/986-native-method-bind/src/Main.java @@ -14,5 +14,8 @@ * limitations under the License. */ -public class C extends A { +public class Main { + public static void main(String[] args) throws Exception { + art.Test986.run(); + } } diff --git a/test/944-transform-classloaders/src/CommonClassDefinition.java b/test/986-native-method-bind/src/art/Main.java index 62602a02e9..8b01920638 100644 --- a/test/944-transform-classloaders/src/CommonClassDefinition.java +++ b/test/986-native-method-bind/src/art/Main.java @@ -14,14 +14,15 @@ * limitations under the License. */ -class CommonClassDefinition { - public final Class<?> target; - public final byte[] class_file_bytes; - public final byte[] dex_file_bytes; +package art; - CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { - this.target = target; - this.class_file_bytes = class_file_bytes; - this.dex_file_bytes = dex_file_bytes; - } +// Binder class so the agent's C code has something that can be bound and exposed to tests. +// In a package to separate cleanly and work around CTS reference issues (though this class +// should be replaced in the CTS version). +public class Main { + // Load the given class with the given classloader, and bind all native methods to corresponding + // C methods in the agent. Will abort if any of the steps fail. + public static native void bindAgentJNI(String className, ClassLoader classLoader); + // Same as above, giving the class directly. + public static native void bindAgentJNIForClass(Class<?> klass); } diff --git a/test/986-native-method-bind/src/art/Redefinition.java b/test/986-native-method-bind/src/art/Redefinition.java new file mode 100644 index 0000000000..0350ab42ad --- /dev/null +++ b/test/986-native-method-bind/src/art/Redefinition.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + // Bind native functions. + static { + Main.bindAgentJNIForClass(Redefinition.class); + } + + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/986-native-method-bind/src/art/Test986.java b/test/986-native-method-bind/src/art/Test986.java new file mode 100644 index 0000000000..edd2e9d79f --- /dev/null +++ b/test/986-native-method-bind/src/art/Test986.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 art; + +import java.lang.reflect.Method; +import java.util.HashMap; + +public class Test986 { + static { + // NB This is called before any setup is done so we don't need to worry about getting bind + // events. + Main.bindAgentJNIForClass(Test986.class); + } + + + private static final HashMap<Method, String> SymbolMap = new HashMap<>(); + + // A class with a native method we can play with. + static class Transform { + private static native void sayHi(); + } + + public static void run() throws Exception { + setupNativeBindNotify(); + setNativeBindNotify(true); + doTest(); + } + + private static void setNativeTransform(Method method, String dest) { + SymbolMap.put(method, dest); + } + + /** + * Notifies java that a native method bind has occurred and requests the new symbol to bind to. + */ + public static String doNativeMethodBind(Method method, String nativeSym) { + // Disable native bind notify for now to avoid infinite loops. + setNativeBindNotify(false); + String transSym = SymbolMap.getOrDefault(method, nativeSym); + System.out.println(method + " = " + nativeSym + " -> " + transSym); + setNativeBindNotify(true); + return transSym; + } + + public static void doTest() throws Exception { + Method say_hi_method = Transform.class.getDeclaredMethod("sayHi"); + // TODO We should test auto-binding but due to the way this is run that will be annoying. + Main.bindAgentJNIForClass(Transform.class); + Transform.sayHi(); + setNativeTransform(say_hi_method, "NoReallySayGoodbye"); + Main.bindAgentJNIForClass(Transform.class); + Transform.sayHi(); + Main.bindAgentJNIForClass(Main.class); + Main.bindAgentJNIForClass(Test986.class); + } + + // Functions called from native code. + public static void doSayHi() { + System.out.println("Hello"); + } + + public static void doSayBye() { + System.out.println("Bye"); + } + + private static native void setNativeBindNotify(boolean enable); + private static native void setupNativeBindNotify(); +} diff --git a/test/Android.bp b/test/Android.bp index 9a8e1742ef..d8a3f0eeed 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -250,6 +250,7 @@ art_cc_defaults { "ti-agent/jni_binder.cc", "ti-agent/jvmti_helper.cc", "ti-agent/test_env.cc", + "ti-agent/common_helper.cc", // This is the list of non-special OnLoad things and excludes BCI and anything that depends // on ART internals. "903-hello-tagging/tagging.cc", @@ -260,6 +261,8 @@ art_cc_defaults { "908-gc-start-finish/gc_callbacks.cc", "910-methods/methods.cc", "911-get-stack-trace/stack_trace.cc", + "912-classes/classes.cc", + "913-heaps/heaps.cc", "918-fields/fields.cc", "920-objects/objects.cc", "922-properties/properties.cc", @@ -271,6 +274,9 @@ art_cc_defaults { "929-search/search.cc", "931-agent-thread/agent_thread.cc", "933-misc-events/misc_events.cc", + "945-obsolete-native/obsolete_native.cc", + "984-obsolete-invoke/obsolete_invoke.cc", + "986-native-method-bind/native_bind.cc", ], shared_libs: [ "libbase", @@ -286,20 +292,14 @@ art_cc_defaults { // This is to get the IsInterpreted native method. "common/stack_inspect.cc", "common/runtime_state.cc", + "ti-agent/common_load.cc", // This includes the remaining test functions. We should try to refactor things to // make this list smaller. - "ti-agent/common_helper.cc", - "ti-agent/common_load.cc", "901-hello-ti-agent/basics.cc", "909-attach-agent/attach.cc", - "912-classes/classes.cc", - "913-heaps/heaps.cc", + "912-classes/classes_art.cc", "936-search-onload/search_onload.cc", - "944-transform-classloaders/classloader.cc", - "945-obsolete-native/obsolete_native.cc", - "980-redefine-object/redefine_object.cc", "983-source-transform-verify/source_transform.cc", - "984-obsolete-invoke/obsolete_invoke.cc", ], } @@ -318,6 +318,33 @@ art_cc_test_library { shared_libs: ["libartd"], } +art_cc_defaults { + name: "libtistress-defaults", + defaults: ["libartagent-defaults"], + srcs: [ + "ti-stress/stress.cc", + ], + shared_libs: [ + "libbase", + ], + header_libs: ["libopenjdkjvmti_headers"], +} + +art_cc_test_library { + name: "libtistress", + defaults: [ "libtistress-defaults"], + shared_libs: ["libart"], +} + +art_cc_test_library { + name: "libtistressd", + defaults: [ + "libtistress-defaults", + "art_debug_defaults", + ], + shared_libs: ["libartd"], +} + art_cc_test_library { name: "libctstiagent", defaults: ["libtiagent-base-defaults"], diff --git a/test/Android.run-test-jvmti-java-library.mk b/test/Android.run-test-jvmti-java-library.mk index b6da92b942..70ee693a60 100644 --- a/test/Android.run-test-jvmti-java-library.mk +++ b/test/Android.run-test-jvmti-java-library.mk @@ -18,13 +18,17 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -# Main shim classes. We use one that exposes the tagging common functionality. -LOCAL_MAIN_SHIM := 903-hello-tagging/src/art/Main.java -LOCAL_SRC_FILES := $(LOCAL_MAIN_SHIM) +# shim classes. We use one that exposes the common functionality. +LOCAL_SHIM_CLASSES := \ + 902-hello-transformation/src/art/Redefinition.java \ + 903-hello-tagging/src/art/Main.java \ + +LOCAL_SRC_FILES := $(LOCAL_SHIM_CLASSES) # Actual test classes. LOCAL_SRC_FILES += \ 901-hello-ti-agent/src/art/Test901.java \ + 902-hello-transformation/src/art/Test902.java \ 903-hello-tagging/src/art/Test903.java \ 904-object-allocation/src/art/Test904.java \ 905-object-free/src/art/Test905.java \ @@ -41,20 +45,39 @@ LOCAL_SRC_FILES += \ 911-get-stack-trace/src/art/Recurse.java \ 911-get-stack-trace/src/art/SameThread.java \ 911-get-stack-trace/src/art/ThreadListTraces.java \ + 912-classes/src/art/Test912.java \ + 912-classes/src/art/DexData.java \ 913-heaps/src/art/Test913.java \ + 914-hello-obsolescence/src/art/Test914.java \ + 915-obsolete-2/src/art/Test915.java \ + 917-fields-transformation/src/art/Test917.java \ 918-fields/src/art/Test918.java \ + 919-obsolete-fields/src/art/Test919.java \ 920-objects/src/art/Test920.java \ 922-properties/src/art/Test922.java \ 923-monitors/src/art/Test923.java \ 924-threads/src/art/Test924.java \ 925-threadgroups/src/art/Test925.java \ + 926-multi-obsolescence/src/art/Test926.java \ 927-timers/src/art/Test927.java \ 928-jni-table/src/art/Test928.java \ + 930-hello-retransform/src/art/Test930.java \ 931-agent-thread/src/art/Test931.java \ + 932-transform-saves/src/art/Test932.java \ 933-misc-events/src/art/Test933.java \ + 940-recursive-obsolete/src/art/Test940.java \ + 942-private-recursive/src/art/Test942.java \ + 944-transform-classloaders/src/art/Test944.java \ + 945-obsolete-native/src/art/Test945.java \ + 947-reflect-method/src/art/Test947.java \ + 951-threaded-obsolete/src/art/Test951.java \ + 981-dedup-original-dex/src/art/Test981.java \ + 982-ok-no-retransform/src/art/Test982.java \ + 984-obsolete-invoke/src/art/Test984.java \ JVMTI_RUN_TEST_GENERATED_NUMBERS := \ 901 \ + 902 \ 903 \ 904 \ 905 \ @@ -63,17 +86,34 @@ JVMTI_RUN_TEST_GENERATED_NUMBERS := \ 908 \ 910 \ 911 \ + 912 \ 913 \ + 914 \ + 915 \ + 917 \ 918 \ + 919 \ 920 \ 922 \ 923 \ 924 \ 925 \ + 926 \ 927 \ 928 \ + 930 \ 931 \ + 932 \ 933 \ + 940 \ + 942 \ + 944 \ + 945 \ + 947 \ + 951 \ + 981 \ + 982 \ + 984 \ # Try to enforce that the directories correspond to the Java files we pull in. JVMTI_RUN_TEST_DIR_CHECK := $(sort $(foreach DIR,$(JVMTI_RUN_TEST_GENERATED_NUMBERS), \ diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index f9e3213398..afd914432e 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -50,6 +50,14 @@ TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtiagentd) endif +# Also need libtistress. +TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtistress) +TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtistressd) +ifdef TARGET_2ND_ARCH +TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtistress) +TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtistressd) +endif + # Also need libarttest. TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libarttest) TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libarttestd) @@ -81,6 +89,8 @@ ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \ $(HOST_OUT_EXECUTABLES)/hprof-conv \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagent) \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagentd) \ + $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtistress) \ + $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtistressd) \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libartagent) \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libartagentd) \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libarttest) \ @@ -96,6 +106,8 @@ ifneq ($(HOST_PREFER_32_BIT),true) ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libtiagent) \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libtiagentd) \ + $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libtistress) \ + $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libtistressd) \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libartagent) \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libartagentd) \ $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libarttest) \ diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc index df7fa20226..ceb4ba241b 100644 --- a/test/common/stack_inspect.cc +++ b/test/common/stack_inspect.cc @@ -144,22 +144,11 @@ extern "C" JNIEXPORT void JNICALL Java_Main_assertIsInterpreted(JNIEnv* env, jcl } } -static jboolean IsManaged(JNIEnv* env, jclass cls, size_t level) { +static jboolean IsManaged(JNIEnv* env, jclass, size_t level) { ScopedObjectAccess soa(env); - - ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls); - const DexFile& dex_file = klass->GetDexFile(); - const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); - if (oat_dex_file == nullptr) { - // No oat file, this must be a test configuration that doesn't compile at all. Ignore that the - // result will be that we're running the interpreter. - return JNI_FALSE; - } - NthCallerVisitor caller(soa.Self(), level, false); caller.WalkStack(); CHECK(caller.caller != nullptr); - return caller.GetCurrentShadowFrame() != nullptr ? JNI_FALSE : JNI_TRUE; } diff --git a/test/etc/default-build b/test/etc/default-build index d74b24d985..744c38bb6d 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -91,7 +91,7 @@ JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["lambdas"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["method-handles"]="-source 1.8 -target 1.8" # We need to leave javac at default 1.7 so that dx will continue to work -JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.7 -target 1.7" +JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8" while true; do diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index f1b6132e94..56cfd244e6 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -62,6 +62,7 @@ DRY_RUN="n" # if y prepare to run the test but don't run it. TEST_VDEX="n" TEST_IS_NDEBUG="n" APP_IMAGE="y" +JVMTI_STRESS="n" VDEX_FILTER="" PROFILE="n" RANDOM_PROFILE="n" @@ -145,6 +146,11 @@ while true; do elif [ "x$1" = "x--prebuild" ]; then PREBUILD="y" shift + elif [ "x$1" = "x--jvmti-stress" ]; then + # APP_IMAGE doesn't really work with jvmti-torture + APP_IMAGE="n" + JVMTI_STRESS="y" + shift elif [ "x$1" = "x--no-app-image" ]; then APP_IMAGE="n" shift @@ -365,6 +371,28 @@ if [ "$IS_JVMTI_TEST" = "y" ]; then fi fi +if [[ "$JVMTI_STRESS" = "y" ]]; then + if [[ "$USE_JVM" = "n" ]]; then + plugin=libopenjdkjvmtid.so + agent=libtistressd.so + if [[ "$TEST_IS_NDEBUG" = "y" ]]; then + agent=libtistress.so + plugin=libopenjdkjvmti.so + fi + + file_1=$(mktemp --tmpdir=${DEX_LOCATION}) + file_2=$(mktemp --tmpdir=${DEX_LOCATION}) + # TODO Remove need for DEXTER_BINARY! + FLAGS="${FLAGS} -agentpath:${agent}=${DEXTER_BINARY},${file_1},${file_2}" + if [ "$IS_JVMTI_TEST" = "n" ]; then + FLAGS="${FLAGS} -Xplugin:${plugin}" + FLAGS="${FLAGS} -Xcompiler-option --debuggable" + # Always make the compilation be debuggable. + COMPILE_FLAGS="${COMPILE_FLAGS} --debuggable" + fi + fi +fi + if [ "$USE_JVM" = "y" ]; then export LD_LIBRARY_PATH=${ANDROID_HOST_OUT}/lib64 # Xmx is necessary since we don't pass down the ART flags to JVM. diff --git a/test/knownfailures.json b/test/knownfailures.json index 7891d4c19f..0e42a29bf6 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -220,7 +220,6 @@ "tests": ["604-hot-static-interface", "612-jit-dex-cache", "613-inlining-dex-cache", - "616-cha", "626-set-resolved-string"], "variant": "trace | stream", "description": ["These tests expect JIT compilation, which is", @@ -330,14 +329,8 @@ "variant": "interpreter | optimizing | regalloc_gc | jit" }, { - "tests": ["912-classes", - "616-cha", - "616-cha-abstract", - "616-cha-interface", - "616-cha-interface-default", - "616-cha-miranda", - "616-cha-proxy-method-inline"], - "bug": "http://b/36344364 http://b/36344221", + "tests": ["912-classes"], + "bug": "http://b/36344364", "variant": "no-dex2oat | relocate-npatchoat" }, { @@ -366,5 +359,248 @@ "634-vdex-duplicate"], "description": ["Profile driven dexlayout does not work with vdex or dex verifier."], "variant": "speed-profile" + }, + { + "tests": [ + "004-checker-UnsafeTest18", + "127-checker-secondarydex", + "441-checker-inliner", + "442-checker-constant-folding", + "444-checker-nce", + "445-checker-licm", + "446-checker-inliner2", + "447-checker-inliner3", + "449-checker-bce", + "450-checker-types", + "455-checker-gvn", + "458-checker-instruct-simplification", + "462-checker-inlining-dex-files", + "463-checker-boolean-simplifier", + "464-checker-inline-sharpen-calls", + "465-checker-clinit-gvn", + "468-checker-bool-simplif-regression", + "473-checker-inliner-constants", + "474-checker-boolean-input", + "476-checker-ctor-memory-barrier", + "477-checker-bound-type", + "478-checker-clinit-check-pruning", + "478-checker-inline-noreturn", + "478-checker-inliner-nested-loop", + "480-checker-dead-blocks", + "482-checker-loop-back-edge-use", + "484-checker-register-hints", + "485-checker-dce-loop-update", + "485-checker-dce-switch", + "486-checker-must-do-null-check", + "487-checker-inline-calls", + "488-checker-inline-recursive-calls", + "490-checker-inline", + "492-checker-inline-invoke-interface", + "493-checker-inline-invoke-interface", + "494-checker-instanceof-tests", + "495-checker-checkcast-tests", + "496-checker-inlining-class-loader", + "508-checker-disassembly", + "510-checker-try-catch", + "517-checker-builder-fallthrough", + "521-checker-array-set-null", + "522-checker-regression-monitor-exit", + "523-checker-can-throw-regression", + "525-checker-arrays-fields1", + "525-checker-arrays-fields2", + "526-checker-caller-callee-regs", + "527-checker-array-access-split", + "529-checker-unresolved", + "530-checker-loops1", + "530-checker-loops2", + "530-checker-loops3", + "530-checker-loops4", + "530-checker-loops5", + "530-checker-lse", + "530-checker-lse2", + "530-checker-regression-reftyp-final", + "532-checker-nonnull-arrayset", + "534-checker-bce-deoptimization", + "536-checker-intrinsic-optimization", + "536-checker-needs-access-check", + "537-checker-arraycopy", + "537-checker-debuggable", + "537-checker-inline-and-unverified", + "537-checker-jump-over-jump", + "538-checker-embed-constants", + "540-checker-rtp-bug", + "543-checker-dce-trycatch", + "548-checker-inlining-and-dce", + "549-checker-types-merge", + "550-checker-multiply-accumulate", + "550-checker-regression-wide-store", + "551-checker-clinit", + "551-checker-shifter-operand", + "552-checker-primitive-typeprop", + "552-checker-sharpening", + "554-checker-rtp-checkcast", + "557-checker-instruct-simplifier-ror", + "557-checker-ref-equivalent", + "559-checker-irreducible-loop", + "559-checker-rtp-ifnotnull", + "562-checker-no-intermediate", + "563-checker-fakestring", + "563-checker-invoke-super", + "564-checker-bitcount", + "564-checker-inline-loop", + "564-checker-irreducible-loop", + "564-checker-negbitwise", + "565-checker-condition-liveness", + "565-checker-doublenegbitwise", + "565-checker-irreducible-loop", + "565-checker-rotate", + "566-checker-codegen-select", + "566-checker-signum", + "567-checker-compare", + "568-checker-onebit", + "569-checker-pattern-replacement", + "570-checker-osr", + "570-checker-select", + "572-checker-array-get-regression", + "573-checker-checkcast-regression", + "575-checker-isnan", + "575-checker-string-init-alias", + "577-checker-fp2int", + "580-checker-round", + "580-checker-string-fact-intrinsics", + "582-checker-bce-length", + "583-checker-zero", + "584-checker-div-bool", + "586-checker-null-array-get", + "588-checker-irreducib-lifetime-hole", + "590-checker-arr-set-null-regression", + "591-checker-regression-dead-loop", + "592-checker-regression-bool-input", + "593-checker-boolean-2-integral-conv", + "593-checker-long-2-float-regression", + "593-checker-shift-and-simplifier", + "594-checker-array-alias", + "594-checker-irreducible-linorder", + "596-checker-dead-phi", + "598-checker-irreducible-dominance", + "599-checker-irreducible-loop", + "603-checker-instanceof", + "608-checker-unresolved-lse", + "609-checker-inline-interface", + "609-checker-x86-bounds-check", + "611-checker-simplify-if", + "614-checker-dump-constant-location", + "615-checker-arm64-store-zero", + "618-checker-induction", + "619-checker-current-method", + "620-checker-bce-intrinsics", + "622-checker-bce-regressions", + "623-checker-loop-regressions", + "624-checker-stringops", + "625-checker-licm-regressions", + "626-checker-arm64-scratch-register", + "627-checker-unroll", + "631-checker-fp-abs", + "631-checker-get-class", + "632-checker-char-at-bounds", + "633-checker-rtp-getclass", + "635-checker-arm64-volatile-load-cc", + "637-checker-throw-inline", + "638-checker-inline-caches", + "639-checker-code-sinking", + "640-checker-boolean-simd", + "640-checker-byte-simd", + "640-checker-char-simd", + "640-checker-double-simd", + "640-checker-float-simd", + "640-checker-integer-valueof", + "640-checker-int-simd", + "640-checker-long-simd", + "640-checker-short-simd", + "641-checker-arraycopy", + "643-checker-bogus-ic", + "644-checker-deopt", + "645-checker-abs-simd", + "706-checker-scheduler"], + "description": ["Checker tests are not compatible with jvmti."], + "variant": "jvmti-stress" + }, + { + "tests": [ + "961-default-iface-resolution-gen", + "964-default-iface-init-gen" + ], + "description": ["Tests that just take too long with jvmti-stress"], + "variant": "jvmti-stress" + }, + { + "tests": [ + "950-redefine-intrinsic", + "951-threaded-obsolete", + "952-invoke-custom", + "953-invoke-polymorphic-compiler", + "954-invoke-polymorphic-verifier", + "955-methodhandles-smali", + "956-methodhandles", + "957-methodhandle-transforms", + "958-methodhandle-stackframe", + "959-invoke-polymorphic-accessors" + ], + "description": [ + "Tests that use dex version 38 which is not yet supported by", + "dexter/slicer." + ], + "bug": "b/37272822", + "variant": "jvmti-stress" + }, + { + "tests": [ + "137-cfi", + "595-profile-saving", + "900-hello-plugin", + "909-attach-agent", + "981-dedup-original-dex" + ], + "description": ["Tests that require exact knowledge of the number of plugins and agents."], + "variant": "jvmti-stress" + }, + { + "tests": [ + "097-duplicate-method", + "138-duplicate-classes-check2", + "804-class-extends-itself", + "921-hello-failure" + ], + "description": [ + "Tests that use illegal dex files or otherwise break dexter assumptions" + ], + "variant": "jvmti-stress" + }, + { + "tests": [ + "018-stack-overflow", + "068-classloader", + "086-null-super", + "087-gc-after-link", + "626-const-class-linking", + "629-vdex-speed", + "944-transform-classloaders" + ], + "description": [ + "Tests that use custom class loaders or other features not supported ", + "by our JVMTI implementation" + ], + "variant": "jvmti-stress" + }, + { + "tests": [ + "031-class-attributes", + "911-get-stack-trace" + ], + "description": [ + "Tests that use annotations and debug data that is not kept around by dexter." + ], + "bug": "b/37239009", + "variant": "jvmti-stress" } ] diff --git a/test/run-test b/test/run-test index e46099d2e2..f60f766751 100755 --- a/test/run-test +++ b/test/run-test @@ -137,6 +137,7 @@ trace_stream="false" basic_verify="false" gc_verify="false" gc_stress="false" +jvmti_stress="false" strace="false" always_clean="no" never_clean="no" @@ -233,6 +234,9 @@ while true; do basic_verify="true" gc_stress="true" shift + elif [ "x$1" = "x--jvmti-stress" ]; then + jvmti_stress="true" + shift elif [ "x$1" = "x--suspend-timeout" ]; then shift suspend_timeout="$1" @@ -443,6 +447,9 @@ fi if [ "$gc_stress" = "true" ]; then run_args="${run_args} --gc-stress --runtime-option -Xgc:gcstress --runtime-option -Xms2m --runtime-option -Xmx16m" fi +if [ "$jvmti_stress" = "true" ]; then + run_args="${run_args} --no-app-image --jvmti-stress" +fi if [ "$trace" = "true" ]; then run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file-size:2000000" if [ "$trace_stream" = "true" ]; then @@ -651,6 +658,7 @@ if [ "$usage" = "yes" ]; then echo " --stream Run method tracing in streaming mode (requires --trace)" echo " --gcstress Run with gc stress testing" echo " --gcverify Run with gc verification" + echo " --jvmti-stress Run with jvmti stress testing" echo " --always-clean Delete the test files even if the test fails." echo " --never-clean Keep the test files even if the test succeeds." echo " --android-root [path] The path on target for the android root. (/system by default)." diff --git a/test/testrunner/env.py b/test/testrunner/env.py index f5e2a61685..7d9297ff89 100644 --- a/test/testrunner/env.py +++ b/test/testrunner/env.py @@ -202,6 +202,9 @@ TARGET_ARCH = _get_build_var('TARGET_ARCH') # Note: ART_2ND_PHONY_TEST_TARGET_SUFFIX is 2ND_ART_PHONY_TEST_TARGET_SUFFIX in .mk files # Note: ART_2ND_PHONY_TEST_HOST_SUFFIX is 2ND_ART_PHONY_HOST_TARGET_SUFFIX in .mk files # Python does not let us have variable names starting with a digit, so it has differ. + +ART_TEST_RUN_TEST_JVMTI_STRESS = _getEnvBoolean('ART_TEST_RUN_TEST_JVMTI_STRESS', ART_TEST_FULL) + if TARGET_2ND_ARCH: if "64" in TARGET_ARCH: ART_PHONY_TEST_TARGET_SUFFIX = "64" diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py index 95ab2e7875..6e47c5eb7a 100644 --- a/test/testrunner/target_config.py +++ b/test/testrunner/target_config.py @@ -26,7 +26,7 @@ target_config = { 'make' : 'test-art-host-gtest', 'run-test' : [], 'env' : { - 'ART_USE_READ_BARRIER' : 'false' + 'ART_USE_READ_BARRIER' : 'true' } }, @@ -45,19 +45,19 @@ target_config = { 'art-interpreter' : { 'run-test' : ['--interpreter'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false' + 'ART_USE_READ_BARRIER' : 'true' } }, 'art-interpreter-access-checks' : { 'run-test' : ['--interp-ac'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false' + 'ART_USE_READ_BARRIER' : 'true' } }, 'art-jit' : { 'run-test' : ['--jit'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false' + 'ART_USE_READ_BARRIER' : 'true' } }, 'art-gcstress-gcverify': { @@ -167,51 +167,51 @@ target_config = { 'art-tracing' : { 'run-test' : ['--trace'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false' + 'ART_USE_READ_BARRIER' : 'true' } }, 'art-interpreter-tracing' : { 'run-test' : ['--interpreter', '--trace'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false', + 'ART_USE_READ_BARRIER' : 'true', } }, 'art-forcecopy' : { 'run-test' : ['--forcecopy'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false', + 'ART_USE_READ_BARRIER' : 'true', } }, 'art-no-prebuild' : { 'run-test' : ['--no-prebuild'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false', + 'ART_USE_READ_BARRIER' : 'true', } }, 'art-no-image' : { 'run-test' : ['--no-image'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false', + 'ART_USE_READ_BARRIER' : 'true', } }, 'art-interpreter-no-image' : { 'run-test' : ['--interpreter', '--no-image'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false', + 'ART_USE_READ_BARRIER' : 'true', } }, 'art-relocate-no-patchoat' : { 'run-test' : ['--relocate-npatchoat'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false', + 'ART_USE_READ_BARRIER' : 'true', } }, 'art-no-dex2oat' : { 'run-test' : ['--no-dex2oat'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false', + 'ART_USE_READ_BARRIER' : 'true', } }, 'art-heap-poisoning' : { @@ -231,7 +231,7 @@ target_config = { '--relocate', '--jit'], 'env' : { - 'ART_USE_READ_BARRIER' : 'false' + 'ART_USE_READ_BARRIER' : 'true' } }, diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py index 5d3687e293..8072631e8e 100755 --- a/test/testrunner/testrunner.py +++ b/test/testrunner/testrunner.py @@ -73,6 +73,7 @@ PICTEST_TYPES = set() DEBUGGABLE_TYPES = set() ADDRESS_SIZES = set() OPTIMIZING_COMPILER_TYPES = set() +JVMTI_TYPES = set() ADDRESS_SIZES_TARGET = {'host': set(), 'target': set()} # timeout for individual tests. # TODO: make it adjustable per tests and for buildbots @@ -146,6 +147,7 @@ def gather_test_info(): VARIANT_TYPE_DICT['relocate'] = {'relocate-npatchoat', 'relocate', 'no-relocate'} VARIANT_TYPE_DICT['jni'] = {'jni', 'forcecopy', 'checkjni'} VARIANT_TYPE_DICT['address_sizes'] = {'64', '32'} + VARIANT_TYPE_DICT['jvmti'] = {'no-jvmti', 'jvmti-stress'} VARIANT_TYPE_DICT['compiler'] = {'interp-ac', 'interpreter', 'jit', 'optimizing', 'regalloc_gc', 'speed-profile'} @@ -195,6 +197,10 @@ def setup_test_env(): if env.ART_TEST_SPEED_PROFILE: COMPILER_TYPES.add('speed-profile') + # By default only run without jvmti + if not JVMTI_TYPES: + JVMTI_TYPES.add('no-jvmti') + # By default we run all 'compiler' variants. if not COMPILER_TYPES: COMPILER_TYPES.add('optimizing') @@ -310,6 +316,7 @@ def run_tests(tests): total_test_count *= len(PICTEST_TYPES) total_test_count *= len(DEBUGGABLE_TYPES) total_test_count *= len(COMPILER_TYPES) + total_test_count *= len(JVMTI_TYPES) target_address_combinations = 0 for target in TARGET_TYPES: for address_size in ADDRESS_SIZES_TARGET[target]: @@ -336,10 +343,10 @@ def run_tests(tests): config = itertools.product(tests, TARGET_TYPES, RUN_TYPES, PREBUILD_TYPES, COMPILER_TYPES, RELOCATE_TYPES, TRACE_TYPES, GC_TYPES, JNI_TYPES, IMAGE_TYPES, PICTEST_TYPES, - DEBUGGABLE_TYPES) + DEBUGGABLE_TYPES, JVMTI_TYPES) for test, target, run, prebuild, compiler, relocate, trace, gc, \ - jni, image, pictest, debuggable in config: + jni, image, pictest, debuggable, jvmti in config: for address_size in ADDRESS_SIZES_TARGET[target]: if stop_testrunner: # When ART_TEST_KEEP_GOING is set to false, then as soon as a test @@ -361,11 +368,12 @@ def run_tests(tests): test_name += image + '-' test_name += pictest + '-' test_name += debuggable + '-' + test_name += jvmti + '-' test_name += test test_name += address_size variant_set = {target, run, prebuild, compiler, relocate, trace, gc, jni, - image, pictest, debuggable, address_size} + image, pictest, debuggable, jvmti, address_size} options_test = options_all @@ -428,6 +436,9 @@ def run_tests(tests): if debuggable == 'debuggable': options_test += ' --debuggable' + if jvmti == 'jvmti-stress': + options_test += ' --jvmti-stress' + if address_size == '64': options_test += ' --64' @@ -762,6 +773,7 @@ def parse_test_name(test_name): regex += '(' + '|'.join(VARIANT_TYPE_DICT['image']) + ')-' regex += '(' + '|'.join(VARIANT_TYPE_DICT['pictest']) + ')-' regex += '(' + '|'.join(VARIANT_TYPE_DICT['debuggable']) + ')-' + regex += '(' + '|'.join(VARIANT_TYPE_DICT['jvmti']) + ')-' regex += '(' + '|'.join(RUN_TEST_SET) + ')' regex += '(' + '|'.join(VARIANT_TYPE_DICT['address_sizes']) + ')$' match = re.match(regex, test_name) @@ -777,8 +789,9 @@ def parse_test_name(test_name): IMAGE_TYPES.add(match.group(9)) PICTEST_TYPES.add(match.group(10)) DEBUGGABLE_TYPES.add(match.group(11)) - ADDRESS_SIZES.add(match.group(13)) - return {match.group(12)} + JVMTI_TYPES.add(match.group(12)) + ADDRESS_SIZES.add(match.group(14)) + return {match.group(13)} raise ValueError(test_name + " is not a valid test") @@ -918,6 +931,10 @@ def parse_option(): GC_TYPES.add('cms') if options['multipicimage']: IMAGE_TYPES.add('multipicimage') + if options['jvmti_stress']: + JVMTI_TYPES.add('jvmti-stress') + if options['no_jvmti']: + JVMTI_TYPES.add('no-jvmti') if options['verbose']: verbose = True if options['n_thread']: diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc index ab5dbcc0db..bfd4d254f4 100644 --- a/test/ti-agent/common_helper.cc +++ b/test/ti-agent/common_helper.cc @@ -17,18 +17,15 @@ #include "common_helper.h" #include <dlfcn.h> +#include <map> #include <stdio.h> #include <sstream> #include <deque> +#include <vector> #include "android-base/stringprintf.h" -#include "art_method.h" #include "jni.h" -#include "jni_internal.h" #include "jvmti.h" -#include "scoped_thread_state_change-inl.h" -#include "stack.h" -#include "utils.h" #include "jni_binder.h" #include "jvmti_helper.h" @@ -37,6 +34,10 @@ namespace art { +static void SetupCommonRetransform(); +static void SetupCommonRedefine(); +static void SetupCommonTransform(); + template <bool is_redefine> static void throwCommonRedefinitionError(jvmtiEnv* jvmti, JNIEnv* env, @@ -108,18 +109,15 @@ static void DoClassRedefine(jvmtiEnv* jvmti_env, // Magic JNI export that classes can use for redefining classes. // To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V -extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRedefinition(JNIEnv* env, - jclass, - jclass target, - jbyteArray class_file_bytes, - jbyteArray dex_file_bytes) { +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRedefinition( + JNIEnv* env, jclass, jclass target, jbyteArray class_file_bytes, jbyteArray dex_file_bytes) { DoClassRedefine(jvmti_env, env, target, class_file_bytes, dex_file_bytes); } // Magic JNI export that classes can use for redefining classes. // To use classes should declare this as a native function with signature // ([Ljava/lang/Class;[[B[[B)V -extern "C" JNIEXPORT void JNICALL Java_Main_doCommonMultiClassRedefinition( +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonMultiClassRedefinition( JNIEnv* env, jclass, jobjectArray targets, @@ -155,11 +153,7 @@ jint OnLoad(JavaVM* vm, printf("Unable to get jvmti env!\n"); return 1; } - jvmtiCapabilities caps; - jvmti_env->GetPotentialCapabilities(&caps); - caps.can_retransform_classes = 0; - caps.can_retransform_any_class = 0; - jvmti_env->AddCapabilities(&caps); + SetupCommonRedefine(); return 0; } @@ -183,11 +177,8 @@ struct CommonTransformationResult { std::map<std::string, std::deque<CommonTransformationResult>> gTransformations; bool gPopTransformations = true; -extern "C" JNIEXPORT void JNICALL Java_Main_addCommonTransformationResult(JNIEnv* env, - jclass, - jstring class_name, - jbyteArray class_array, - jbyteArray dex_array) { +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_addCommonTransformationResult( + JNIEnv* env, jclass, jstring class_name, jbyteArray class_array, jbyteArray dex_array) { const char* name_chrs = env->GetStringUTFChars(class_name, nullptr); std::string name_str(name_chrs); env->ReleaseStringUTFChars(class_name, name_chrs); @@ -244,15 +235,15 @@ void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* jvmti_env, } } -extern "C" JNIEXPORT void Java_Main_setPopRetransformations(JNIEnv*, - jclass, - jboolean enable) { +extern "C" JNIEXPORT void Java_art_Redefinition_setPopRetransformations(JNIEnv*, + jclass, + jboolean enable) { gPopTransformations = enable; } -extern "C" JNIEXPORT void Java_Main_popTransformationFor(JNIEnv* env, - jclass, - jstring class_name) { +extern "C" JNIEXPORT void Java_art_Redefinition_popTransformationFor(JNIEnv* env, + jclass, + jstring class_name) { const char* name_chrs = env->GetStringUTFChars(class_name, nullptr); std::string name_str(name_chrs); env->ReleaseStringUTFChars(class_name, name_chrs); @@ -267,9 +258,9 @@ extern "C" JNIEXPORT void Java_Main_popTransformationFor(JNIEnv* env, } } -extern "C" JNIEXPORT void Java_Main_enableCommonRetransformation(JNIEnv* env, - jclass, - jboolean enable) { +extern "C" JNIEXPORT void Java_art_Redefinition_enableCommonRetransformation(JNIEnv* env, + jclass, + jboolean enable) { jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr); @@ -298,9 +289,8 @@ static void DoClassRetransformation(jvmtiEnv* jvmti_env, JNIEnv* env, jobjectArr } } -extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRetransformation(JNIEnv* env, - jclass, - jobjectArray targets) { +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRetransformation( + JNIEnv* env, jclass, jobjectArray targets) { jvmtiCapabilities caps; jvmtiError caps_err = jvmti_env->GetCapabilities(&caps); if (caps_err != JVMTI_ERROR_NONE) { @@ -338,14 +328,7 @@ jint OnLoad(JavaVM* vm, printf("Unable to get jvmti env!\n"); return 1; } - SetAllCapabilities(jvmti_env); - jvmtiEventCallbacks cb; - memset(&cb, 0, sizeof(cb)); - cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable; - if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) { - printf("Unable to set class file load hook cb!\n"); - return 1; - } + SetupCommonRetransform(); return 0; } @@ -353,8 +336,6 @@ jint OnLoad(JavaVM* vm, namespace common_transform { -using art::common_retransform::CommonClassFileLoadHookRetransformable; - // Get all capabilities except those related to retransformation. jint OnLoad(JavaVM* vm, char* options ATTRIBUTE_UNUSED, @@ -363,6 +344,35 @@ jint OnLoad(JavaVM* vm, printf("Unable to get jvmti env!\n"); return 1; } + SetupCommonTransform(); + return 0; +} + +} // namespace common_transform + +#define CONFIGURATION_COMMON_REDEFINE 0 +#define CONFIGURATION_COMMON_RETRANSFORM 1 +#define CONFIGURATION_COMMON_TRANSFORM 2 + +static void SetupCommonRedefine() { + jvmtiCapabilities caps; + jvmti_env->GetPotentialCapabilities(&caps); + caps.can_retransform_classes = 0; + caps.can_retransform_any_class = 0; + jvmti_env->AddCapabilities(&caps); +} + +static void SetupCommonRetransform() { + SetAllCapabilities(jvmti_env); + jvmtiEventCallbacks cb; + memset(&cb, 0, sizeof(cb)); + cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable; + jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb)); + CHECK_EQ(res, JVMTI_ERROR_NONE); + common_retransform::gTransformations.clear(); +} + +static void SetupCommonTransform() { // Don't set the retransform caps jvmtiCapabilities caps; jvmti_env->GetPotentialCapabilities(&caps); @@ -373,14 +383,31 @@ jint OnLoad(JavaVM* vm, // Use the same callback as the retransform test. jvmtiEventCallbacks cb; memset(&cb, 0, sizeof(cb)); - cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable; - if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) { - printf("Unable to set class file load hook cb!\n"); - return 1; - } - return 0; + cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable; + jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb)); + CHECK_EQ(res, JVMTI_ERROR_NONE); + common_retransform::gTransformations.clear(); } -} // namespace common_transform - +extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_nativeSetTestConfiguration(JNIEnv*, + jclass, + jint type) { + switch (type) { + case CONFIGURATION_COMMON_REDEFINE: { + SetupCommonRedefine(); + return; + } + case CONFIGURATION_COMMON_RETRANSFORM: { + SetupCommonRetransform(); + return; + } + case CONFIGURATION_COMMON_TRANSFORM: { + SetupCommonTransform(); + return; + } + default: { + LOG(FATAL) << "Unknown test configuration: " << type; + } + } +} } // namespace art diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc index 9e7b75daf2..3455409b2d 100644 --- a/test/ti-agent/common_load.cc +++ b/test/ti-agent/common_load.cc @@ -60,31 +60,17 @@ static jint MinimalOnLoad(JavaVM* vm, // MinimalOnLoad. static AgentLib agents[] = { { "901-hello-ti-agent", Test901HelloTi::OnLoad, nullptr }, - { "902-hello-transformation", common_redefine::OnLoad, nullptr }, { "909-attach-agent", nullptr, Test909AttachAgent::OnAttach }, - { "914-hello-obsolescence", common_redefine::OnLoad, nullptr }, - { "915-obsolete-2", common_redefine::OnLoad, nullptr }, { "916-obsolete-jit", common_redefine::OnLoad, nullptr }, - { "917-fields-transformation", common_redefine::OnLoad, nullptr }, - { "919-obsolete-fields", common_redefine::OnLoad, nullptr }, { "921-hello-failure", common_retransform::OnLoad, nullptr }, - { "926-multi-obsolescence", common_redefine::OnLoad, nullptr }, - { "930-hello-retransform", common_retransform::OnLoad, nullptr }, - { "932-transform-saves", common_retransform::OnLoad, nullptr }, { "934-load-transform", common_retransform::OnLoad, nullptr }, { "935-non-retransformable", common_transform::OnLoad, nullptr }, { "936-search-onload", Test936SearchOnload::OnLoad, nullptr }, { "937-hello-retransform-package", common_retransform::OnLoad, nullptr }, { "938-load-transform-bcp", common_retransform::OnLoad, nullptr }, { "939-hello-transformation-bcp", common_redefine::OnLoad, nullptr }, - { "940-recursive-obsolete", common_redefine::OnLoad, nullptr }, { "941-recursive-obsolete-jit", common_redefine::OnLoad, nullptr }, - { "942-private-recursive", common_redefine::OnLoad, nullptr }, { "943-private-recursive-jit", common_redefine::OnLoad, nullptr }, - { "944-transform-classloaders", common_redefine::OnLoad, nullptr }, - { "945-obsolete-native", common_redefine::OnLoad, nullptr }, - { "981-dedup-original-dex", common_retransform::OnLoad, nullptr }, - { "982-ok-no-retransform", common_retransform::OnLoad, nullptr }, { "983-source-transform-verify", Test983SourceTransformVerify::OnLoad, nullptr }, }; diff --git a/test/ti-agent/scoped_local_ref.h b/test/ti-agent/scoped_local_ref.h index daa1583457..ba9725fdff 100644 --- a/test/ti-agent/scoped_local_ref.h +++ b/test/ti-agent/scoped_local_ref.h @@ -44,7 +44,7 @@ class ScopedLocalRef { } } - T release() __attribute__((warn_unused_result)) { + T release() WARN_UNUSED { T localRef = mLocalRef; mLocalRef = nullptr; return localRef; diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc new file mode 100644 index 0000000000..fa49a35a8e --- /dev/null +++ b/test/ti-stress/stress.cc @@ -0,0 +1,210 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * 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. + */ + +#include <jni.h> +#include <stdio.h> +#include <iostream> +#include <fstream> +#include <stdio.h> +#include <sstream> + +#include "jvmti.h" +#include "exec_utils.h" +#include "utils.h" + +namespace art { + +// Should we do a 'full_rewrite' with this test? +static constexpr bool kDoFullRewrite = true; + +struct StressData { + std::string dexter_cmd; + std::string out_temp_dex; + std::string in_temp_dex; + bool vm_class_loader_initialized; +}; + +static void WriteToFile(const std::string& fname, jint data_len, const unsigned char* data) { + std::ofstream file(fname, std::ios::binary | std::ios::out | std::ios::trunc); + file.write(reinterpret_cast<const char*>(data), data_len); + file.flush(); +} + +static bool ReadIntoBuffer(const std::string& fname, /*out*/std::vector<unsigned char>* data) { + std::ifstream file(fname, std::ios::binary | std::ios::in); + file.seekg(0, std::ios::end); + size_t len = file.tellg(); + data->resize(len); + file.seekg(0); + file.read(reinterpret_cast<char*>(data->data()), len); + return len != 0; +} + +// TODO rewrite later. +static bool DoExtractClassFromData(StressData* data, + const std::string& class_name, + jint in_len, + const unsigned char* in_data, + /*out*/std::vector<unsigned char>* dex) { + // Write the dex file into a temporary file. + WriteToFile(data->in_temp_dex, in_len, in_data); + // Clear out file so even if something suppresses the exit value we will still detect dexter + // failure. + WriteToFile(data->out_temp_dex, 0, nullptr); + // Have dexter do the extraction. + std::vector<std::string> args; + args.push_back(data->dexter_cmd); + if (kDoFullRewrite) { + args.push_back("-x"); + args.push_back("full_rewrite"); + } + args.push_back("-e"); + args.push_back(class_name); + args.push_back("-o"); + args.push_back(data->out_temp_dex); + args.push_back(data->in_temp_dex); + std::string error; + if (ExecAndReturnCode(args, &error) != 0) { + LOG(ERROR) << "unable to execute dexter: " << error; + return false; + } + return ReadIntoBuffer(data->out_temp_dex, dex); +} + +// The hook we are using. +void JNICALL ClassFileLoadHookSecretNoOp(jvmtiEnv* jvmti, + JNIEnv* jni_env ATTRIBUTE_UNUSED, + jclass class_being_redefined ATTRIBUTE_UNUSED, + jobject loader ATTRIBUTE_UNUSED, + const char* name, + jobject protection_domain ATTRIBUTE_UNUSED, + jint class_data_len, + const unsigned char* class_data, + jint* new_class_data_len, + unsigned char** new_class_data) { + std::vector<unsigned char> out; + std::string name_str(name); + // Make the jvmti semi-descriptor into the java style descriptor (though with $ for inner + // classes). + std::replace(name_str.begin(), name_str.end(), '/', '.'); + StressData* data = nullptr; + CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)), + JVMTI_ERROR_NONE); + if (!data->vm_class_loader_initialized) { + LOG(WARNING) << "Ignoring load of class " << name << " because VMClassLoader is not yet " + << "initialized. Transforming this class could cause spurious test failures."; + return; + } else if (DoExtractClassFromData(data, name_str, class_data_len, class_data, /*out*/ &out)) { + LOG(INFO) << "Extracted class: " << name; + unsigned char* new_data; + CHECK_EQ(JVMTI_ERROR_NONE, jvmti->Allocate(out.size(), &new_data)); + memcpy(new_data, out.data(), out.size()); + *new_class_data_len = static_cast<jint>(out.size()); + *new_class_data = new_data; + } else { + std::cerr << "Unable to extract class " << name_str << std::endl; + *new_class_data_len = 0; + *new_class_data = nullptr; + } +} + +// Options are ${DEXTER_BINARY},${TEMP_FILE_1},${TEMP_FILE_2} +static void ReadOptions(StressData* data, char* options) { + std::string ops(options); + data->dexter_cmd = ops.substr(0, ops.find(',')); + ops = ops.substr(ops.find(',') + 1); + data->in_temp_dex = ops.substr(0, ops.find(',')); + ops = ops.substr(ops.find(',') + 1); + data->out_temp_dex = ops; +} + +// We need to make sure that VMClassLoader is initialized before we start redefining anything since +// it can give (non-fatal) error messages if it's initialized after we've redefined BCP classes. +// These error messages are expected and no problem but they will mess up our testing +// infrastructure. +static void JNICALL EnsureVMClassloaderInitializedCB(jvmtiEnv *jvmti_env, + JNIEnv* jni_env, + jthread thread ATTRIBUTE_UNUSED) { + // Load the VMClassLoader class. We will get a ClassNotFound exception because we don't have + // visibility but the class will be loaded behind the scenes. + LOG(INFO) << "manual load & initialization of class java/lang/VMClassLoader!"; + jclass klass = jni_env->FindClass("java/lang/VMClassLoader"); + if (klass == nullptr) { + LOG(ERROR) << "Unable to find VMClassLoader class!"; + } else { + // GetMethodID is spec'd to cause the class to be initialized. + jni_env->GetMethodID(klass, "hashCode", "()I"); + jni_env->DeleteLocalRef(klass); + StressData* data = nullptr; + CHECK_EQ(jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)), + JVMTI_ERROR_NONE); + data->vm_class_loader_initialized = true; + } +} + +extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, + char* options, + void* reserved ATTRIBUTE_UNUSED) { + jvmtiEnv* jvmti = nullptr; + if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0)) { + LOG(ERROR) << "Unable to get jvmti env."; + return 1; + } + StressData* data = nullptr; + if (JVMTI_ERROR_NONE != jvmti->Allocate(sizeof(StressData), + reinterpret_cast<unsigned char**>(&data))) { + LOG(ERROR) << "Unable to allocate data for stress test."; + return 1; + } + memset(data, 0, sizeof(StressData)); + // Read the options into the static variables that hold them. + ReadOptions(data, options); + // Save the data + if (JVMTI_ERROR_NONE != jvmti->SetEnvironmentLocalStorage(data)) { + LOG(ERROR) << "Unable to save stress test data."; + return 1; + } + + // Just get all capabilities. + jvmtiCapabilities caps; + jvmti->GetPotentialCapabilities(&caps); + jvmti->AddCapabilities(&caps); + + // Set callbacks. + jvmtiEventCallbacks cb; + memset(&cb, 0, sizeof(cb)); + cb.ClassFileLoadHook = ClassFileLoadHookSecretNoOp; + cb.VMInit = EnsureVMClassloaderInitializedCB; + if (jvmti->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) { + LOG(ERROR) << "Unable to set class file load hook cb!"; + return 1; + } + if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, + JVMTI_EVENT_VM_INIT, + nullptr) != JVMTI_ERROR_NONE) { + LOG(ERROR) << "Unable to enable JVMTI_EVENT_VM_INIT event!"; + return 1; + } + if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, + JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, + nullptr) != JVMTI_ERROR_NONE) { + LOG(ERROR) << "Unable to enable CLASS_FILE_LOAD_HOOK event!"; + return 1; + } + return 0; +} + +} // namespace art |