Revert^2 "Remove finalizable restriction on structural redefinition"
This reverts commit 0b1afb7c63d99c88f90f17770ad94ccb0b0c57d3.
Daemon shutdown is known to be somewhat flaky. That seems to be the
cause of this failure.
Reason for revert: Removed Daemon threads from tests 2006 & 2007.
Bug: 134162467
Test: % ./art/test/run-test --create-runner --host --prebuild --compact-dex-level fast --jit --no-relocate --runtime-option -Xcheck:jni --debuggable --runtime-option -Xopaque-jni-ids:true --64 2007
...
Runnable test script written to /tmp/allight/test-230585/runit.sh
...
% ./art/tools/parallel_run.py -j80 /tmp/allight/test-230585/runit.sh --out failure.txt
Test: ./art/test/run-test --create-runner --host --prebuild --compact-dex-level fast --jit --no-relocate --runtime-option -Xcheck:jni --debuggable --runtime-option -Xopaque-jni-ids:true --64 2006
Change-Id: I392a2936995dd05b08feea36f11b616c1548ae46
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index c505933..dccc226 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -1131,10 +1131,6 @@
jvmtiError res;
if (driver_->type_ == RedefinitionType::kStructural && this->IsStructuralRedefinition()) {
res = Redefiner::GetClassRedefinitionError<RedefinitionType::kStructural>(h_klass, &err);
- if (res == OK && HasVirtualMembers() && h_klass->IsFinalizable()) {
- res = ERR(INTERNAL);
- err = "Cannot redefine finalizable objects at this time.";
- }
} else {
res = Redefiner::GetClassRedefinitionError<RedefinitionType::kNormal>(h_klass, &err);
}
@@ -1750,7 +1746,21 @@
[&](auto class_pair) REQUIRES_SHARED(art::Locks::mutator_lock_) {
return class_pair.first == hinstance->GetClass();
}));
- art::ObjPtr<art::mirror::Object> new_instance(new_type->AllocObject(driver_->self_));
+ // Make sure when allocating the new instance we don't add it's finalizer since we will directly
+ // replace the old object in the finalizer reference. If we added it here to we would call
+ // finalize twice.
+ // NB If a type is changed from being non-finalizable to finalizable the finalizers on any
+ // objects created before the redefine will never be called. This is (sort of) allowable by
+ // the spec and greatly simplifies implementation.
+ // TODO Make it so we will always call all finalizers, even if the object when it was created
+ // wasn't finalizable. To do this we need to be careful of handling failure correctly and making
+ // sure that objects aren't finalized multiple times and that instances of failed redefinitions
+ // aren't finalized.
+ art::ObjPtr<art::mirror::Object> new_instance(
+ new_type->Alloc</*kIsInstrumented=*/true,
+ art::mirror::Class::AddFinalizer::kNoAddFinalizer,
+ /*kCheckAddFinalizer=*/false>(
+ driver_->self_, driver_->runtime_->GetHeap()->GetCurrentAllocator()));
if (new_instance.IsNull()) {
driver_->self_->AssertPendingOOMException();
driver_->self_->ClearException();
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 338928e..1e42201 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -199,14 +199,15 @@
return nullptr;
}
gc::Heap* heap = Runtime::Current()->GetHeap();
- // Pass in false since the object cannot be finalizable.
+ // Pass in kNoAddFinalizer since the object cannot be finalizable.
// CheckClassInitializedForObjectAlloc can cause thread suspension which means we may now be
// instrumented.
- return klass->Alloc</*kInstrumented=*/true, /*kCheckAddFinalizer=*/false>(
+ return klass->Alloc</*kInstrumented=*/true, mirror::Class::AddFinalizer::kNoAddFinalizer>(
self, heap->GetCurrentAllocator());
}
- // Pass in false since the object cannot be finalizable.
- return klass->Alloc<kInstrumented, /*kCheckAddFinalizer=*/false>(self, allocator_type);
+ // Pass in kNoAddFinalizer since the object cannot be finalizable.
+ return klass->Alloc<kInstrumented,
+ mirror::Class::AddFinalizer::kNoAddFinalizer>(self, allocator_type);
}
// Given the context of a calling Method and an initialized class, create an instance.
@@ -216,8 +217,9 @@
Thread* self,
gc::AllocatorType allocator_type) {
DCHECK(klass != nullptr);
- // Pass in false since the object cannot be finalizable.
- return klass->Alloc<kInstrumented, /*kCheckAddFinalizer=*/false>(self, allocator_type);
+ // Pass in kNoAddFinalizer since the object cannot be finalizable.
+ return klass->Alloc<kInstrumented,
+ mirror::Class::AddFinalizer::kNoAddFinalizer>(self, allocator_type);
}
diff --git a/runtime/mirror/class-alloc-inl.h b/runtime/mirror/class-alloc-inl.h
index 2861244..5627b49 100644
--- a/runtime/mirror/class-alloc-inl.h
+++ b/runtime/mirror/class-alloc-inl.h
@@ -46,13 +46,19 @@
DCHECK_GE(this->object_size_, sizeof(Object));
}
-template<bool kIsInstrumented, bool kCheckAddFinalizer>
+template<bool kIsInstrumented, Class::AddFinalizer kAddFinalizer, bool kCheckAddFinalizer>
inline ObjPtr<Object> Class::Alloc(Thread* self, gc::AllocatorType allocator_type) {
CheckObjectAlloc();
gc::Heap* heap = Runtime::Current()->GetHeap();
- const bool add_finalizer = kCheckAddFinalizer && IsFinalizable();
- if (!kCheckAddFinalizer) {
- DCHECK(!IsFinalizable());
+ bool add_finalizer;
+ switch (kAddFinalizer) {
+ case Class::AddFinalizer::kUseClassTag:
+ add_finalizer = IsFinalizable();
+ break;
+ case Class::AddFinalizer::kNoAddFinalizer:
+ add_finalizer = false;
+ DCHECK(!kCheckAddFinalizer || !IsFinalizable());
+ break;
}
// Note that the `this` pointer may be invalidated after the allocation.
ObjPtr<Object> obj =
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index b600c43..3e24346 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -498,8 +498,21 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsPrimitiveArray() REQUIRES_SHARED(Locks::mutator_lock_);
+ // Enum used to control whether we try to add a finalizer-reference for object alloc or not.
+ enum class AddFinalizer {
+ // Don't create a finalizer reference regardless of what the class-flags say.
+ kNoAddFinalizer,
+ // Use the class-flags to figure out if we should make a finalizer reference.
+ kUseClassTag,
+ };
+
// Creates a raw object instance but does not invoke the default constructor.
- template<bool kIsInstrumented = true, bool kCheckAddFinalizer = true>
+ // kCheckAddFinalizer controls whether we use a DCHECK to sanity check that we create a
+ // finalizer-reference if needed. This should only be disabled when doing structural class
+ // redefinition.
+ template <bool kIsInstrumented = true,
+ AddFinalizer kAddFinalizer = AddFinalizer::kUseClassTag,
+ bool kCheckAddFinalizer = true>
ALWAYS_INLINE ObjPtr<Object> Alloc(Thread* self, gc::AllocatorType allocator_type)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
diff --git a/test/2006-virtual-structural-finalizing/expected.txt b/test/2006-virtual-structural-finalizing/expected.txt
new file mode 100644
index 0000000..e965357
--- /dev/null
+++ b/test/2006-virtual-structural-finalizing/expected.txt
@@ -0,0 +1,3 @@
+Finalizing
+start_counter: 1
+Finish_counter: 1
diff --git a/test/2006-virtual-structural-finalizing/info.txt b/test/2006-virtual-structural-finalizing/info.txt
new file mode 100644
index 0000000..3e5291d
--- /dev/null
+++ b/test/2006-virtual-structural-finalizing/info.txt
@@ -0,0 +1,4 @@
+Tests structural redefinition with multiple threads.
+
+Tests that using the structural redefinition while concurrently loading and using a subtype of
+the class being redefined doesn't cause any unexpected problems.
diff --git a/test/2006-virtual-structural-finalizing/run b/test/2006-virtual-structural-finalizing/run
new file mode 100755
index 0000000..03e41a5
--- /dev/null
+++ b/test/2006-virtual-structural-finalizing/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+./default-run "$@" --jvmti --runtime-option -Xopaque-jni-ids:true
diff --git a/test/2006-virtual-structural-finalizing/src-art/Main.java b/test/2006-virtual-structural-finalizing/src-art/Main.java
new file mode 100644
index 0000000..11f9aa7
--- /dev/null
+++ b/test/2006-virtual-structural-finalizing/src-art/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2019 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) throws Exception {
+ art.Test2006.run();
+ }
+}
diff --git a/test/2006-virtual-structural-finalizing/src-art/art/Redefinition.java b/test/2006-virtual-structural-finalizing/src-art/art/Redefinition.java
new file mode 120000
index 0000000..81eaf31
--- /dev/null
+++ b/test/2006-virtual-structural-finalizing/src-art/art/Redefinition.java
@@ -0,0 +1 @@
+../../../jvmti-common/Redefinition.java
\ No newline at end of file
diff --git a/test/2006-virtual-structural-finalizing/src-art/art/Test2006.java b/test/2006-virtual-structural-finalizing/src-art/art/Test2006.java
new file mode 100644
index 0000000..510d13d
--- /dev/null
+++ b/test/2006-virtual-structural-finalizing/src-art/art/Test2006.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 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 dalvik.system.InMemoryDexClassLoader;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Supplier;
+import java.util.concurrent.atomic.*;
+import java.lang.ref.*;
+
+public class Test2006 {
+ public static final CountDownLatch start_latch = new CountDownLatch(1);
+ public static final CountDownLatch redefine_latch = new CountDownLatch(1);
+ public static final CountDownLatch finish_latch = new CountDownLatch(1);
+ public static volatile int start_counter = 0;
+ public static volatile int finish_counter = 0;
+ public static class Transform {
+ public Transform() { }
+ protected void finalize() throws Throwable {
+ System.out.println("Finalizing");
+ start_counter++;
+ start_latch.countDown();
+ redefine_latch.await();
+ finish_counter++;
+ finish_latch.countDown();
+ }
+ }
+
+ /**
+ * base64 encoded class/dex file for
+ * public static class Transform {
+ * public String greeting;
+ *
+ * public Transform() {
+ * greeting = "Hello";
+ * }
+ * protected void finalize() {
+ * System.out.println("NOTHING HERE!");
+ * }
+ * }
+ */
+ private static final byte[] DEX_BYTES =
+ Base64.getDecoder()
+ .decode(
+"ZGV4CjAzNQDtxu0Tsy2rLn9iTZHx3r+yuY0IuN+y1el4BAAAcAAAAHhWNBIAAAAAAAAAALQDAAAX" +
+"AAAAcAAAAAkAAADMAAAAAgAAAPAAAAACAAAACAEAAAQAAAAYAQAAAQAAADgBAAAgAwAAWAEAAKoB" +
+"AACyAQAAuQEAANMBAADjAQAABwIAACcCAAA+AgAAUgIAAGYCAAB6AgAAiQIAAJgCAACjAgAApgIA" +
+"AKoCAAC3AgAAwQIAAMsCAADRAgAA1gIAAN8CAADmAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAA" +
+"CAAAAAkAAAANAAAADQAAAAgAAAAAAAAADgAAAAgAAACkAQAAAAAGABEAAAAHAAQAEwAAAAAAAAAA" +
+"AAAAAAAAABAAAAAEAAEAFAAAAAUAAAAAAAAAAAAAAAEAAAAFAAAAAAAAAAsAAACkAwAAhAMAAAAA" +
+"AAACAAEAAQAAAJgBAAAIAAAAcBADAAEAGgABAFsQAAAOAAMAAQACAAAAngEAAAgAAABiAAEAGgEK" +
+"AG4gAgAQAA4ABgAOPEsACgAOeAAAAQAAAAYABjxpbml0PgAFSGVsbG8AGExhcnQvVGVzdDIwMDYk" +
+"VHJhbnNmb3JtOwAOTGFydC9UZXN0MjAwNjsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdD" +
+"bGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRTdHJl" +
+"YW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9T" +
+"eXN0ZW07AA1OT1RISU5HIEhFUkUhAA1UZXN0MjAwNi5qYXZhAAlUcmFuc2Zvcm0AAVYAAlZMAAth" +
+"Y2Nlc3NGbGFncwAIZmluYWxpemUACGdyZWV0aW5nAARuYW1lAANvdXQAB3ByaW50bG4ABXZhbHVl" +
+"AIwBfn5EOHsiY29tcGlsYXRpb24tbW9kZSI6ImRlYnVnIiwiaGFzLWNoZWNrc3VtcyI6ZmFsc2Us" +
+"Im1pbi1hcGkiOjEsInNoYS0xIjoiMTI5ZWU5ZjY3NTZjMzlkZjU3ZmYwNzg1ZDI1NmIyMzc3MjY0" +
+"MmI3YyIsInZlcnNpb24iOiIyLjAuMTAtZGV2In0AAgIBFRgBAgMCDwQJEhcMAAEBAQABAIGABNgC" +
+"AQT4AgAAAAACAAAAdQMAAHsDAACYAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAX" +
+"AAAAcAAAAAIAAAAJAAAAzAAAAAMAAAACAAAA8AAAAAQAAAACAAAACAEAAAUAAAAEAAAAGAEAAAYA" +
+"AAABAAAAOAEAAAEgAAACAAAAWAEAAAMgAAACAAAAmAEAAAEQAAABAAAApAEAAAIgAAAXAAAAqgEA" +
+"AAQgAAACAAAAdQMAAAAgAAABAAAAhAMAAAMQAAACAAAAlAMAAAYgAAABAAAApAMAAAAQAAABAAAA" +
+"tAMAAA==");
+
+ public static void run() throws Exception {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest();
+ }
+
+ public static final class GcThread extends Thread {
+ public volatile boolean finished = false;
+ public void run() {
+ while (!finished) {
+ Runtime.getRuntime().gc();
+ System.runFinalization();
+ }
+ }
+ }
+
+ public static void doTest() throws Exception {
+ GcThread gc_thr = new GcThread();
+ gc_thr.start();
+ mktransform();
+ start_latch.await();
+ System.out.println("start_counter: " + start_counter);
+ Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES);
+ redefine_latch.countDown();
+ finish_latch.await();
+ System.out.println("Finish_counter: " + finish_counter);
+ gc_thr.finished = true;
+ gc_thr.join();
+ }
+ public static void mktransform() throws Exception {
+ Transform tr = new Transform();
+ }
+}
diff --git a/test/2006-virtual-structural-finalizing/src/Main.java b/test/2006-virtual-structural-finalizing/src/Main.java
new file mode 100644
index 0000000..89b8557
--- /dev/null
+++ b/test/2006-virtual-structural-finalizing/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2019 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) throws Exception {
+ System.out.println("FAIL: Test is only for art!");
+ }
+}
diff --git a/test/2007-virtual-structural-finalizable/expected.txt b/test/2007-virtual-structural-finalizable/expected.txt
new file mode 100644
index 0000000..781fc9a
--- /dev/null
+++ b/test/2007-virtual-structural-finalizable/expected.txt
@@ -0,0 +1,2 @@
+Finalizing
+counter: 1
diff --git a/test/2007-virtual-structural-finalizable/info.txt b/test/2007-virtual-structural-finalizable/info.txt
new file mode 100644
index 0000000..3e5291d
--- /dev/null
+++ b/test/2007-virtual-structural-finalizable/info.txt
@@ -0,0 +1,4 @@
+Tests structural redefinition with multiple threads.
+
+Tests that using the structural redefinition while concurrently loading and using a subtype of
+the class being redefined doesn't cause any unexpected problems.
diff --git a/test/2007-virtual-structural-finalizable/run b/test/2007-virtual-structural-finalizable/run
new file mode 100755
index 0000000..03e41a5
--- /dev/null
+++ b/test/2007-virtual-structural-finalizable/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+./default-run "$@" --jvmti --runtime-option -Xopaque-jni-ids:true
diff --git a/test/2007-virtual-structural-finalizable/src-art/Main.java b/test/2007-virtual-structural-finalizable/src-art/Main.java
new file mode 100644
index 0000000..ab8daea
--- /dev/null
+++ b/test/2007-virtual-structural-finalizable/src-art/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2019 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) throws Exception {
+ art.Test2007.run();
+ }
+}
diff --git a/test/2007-virtual-structural-finalizable/src-art/art/Redefinition.java b/test/2007-virtual-structural-finalizable/src-art/art/Redefinition.java
new file mode 120000
index 0000000..81eaf31
--- /dev/null
+++ b/test/2007-virtual-structural-finalizable/src-art/art/Redefinition.java
@@ -0,0 +1 @@
+../../../jvmti-common/Redefinition.java
\ No newline at end of file
diff --git a/test/2007-virtual-structural-finalizable/src-art/art/Test2007.java b/test/2007-virtual-structural-finalizable/src-art/art/Test2007.java
new file mode 100644
index 0000000..77284eb
--- /dev/null
+++ b/test/2007-virtual-structural-finalizable/src-art/art/Test2007.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2019 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 dalvik.system.InMemoryDexClassLoader;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Supplier;
+import java.util.concurrent.atomic.*;
+import java.lang.ref.*;
+
+public class Test2007 {
+ public static final CountDownLatch finish_latch = new CountDownLatch(1);
+ public static volatile int counter = 0;
+ public static Object theObject = null;
+ public static class Transform {
+ public Transform() { }
+ protected void finalize() throws Throwable {
+ System.out.println("Should never be called!");
+ // Do nothing.
+ }
+ }
+
+ /**
+ * base64 encoded class/dex file for
+ * public static class Transform {
+ * public String greeting;
+ *
+ * public Transform() {
+ * greeting = "Hello";
+ * }
+ * protected void finalize() throws Throwable {
+ * System.out.println("Finalizing");
+ * counter++;
+ * finish_latch.countDown();
+ * }
+ * }
+ */
+ private static final byte[] DEX_BYTES =
+ Base64.getDecoder()
+ .decode(
+"ZGV4CjAzNQCC9DECxo2lTpw7FCCSqZArgZe8ab49ywRoBQAAcAAAAHhWNBIAAAAAAAAAAKQEAAAe" +
+"AAAAcAAAAA0AAADoAAAAAgAAABwBAAAEAAAANAEAAAUAAABUAQAAAQAAAHwBAADMAwAAnAEAAAYC" +
+"AAAOAgAAGgIAACECAAAkAgAAPgIAAE4CAAByAgAAkgIAAK4CAADFAgAA2QIAAO0CAAABAwAAGAMA" +
+"AD8DAABOAwAAWQMAAFwDAABgAwAAbQMAAHgDAACBAwAAiwMAAJkDAACjAwAAqQMAAK4DAAC3AwAA" +
+"vgMAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAABEAAAAR" +
+"AAAADAAAAAAAAAASAAAADAAAAAACAAABAAgAGAAAAAIAAAAVAAAAAgALABcAAAAJAAYAGgAAAAEA" +
+"AAAAAAAAAQAAABYAAAAGAAEAGwAAAAcAAAAAAAAACwAAABQAAAABAAAAAQAAAAcAAAAAAAAADwAA" +
+"AIwEAABkBAAAAAAAAAIAAQABAAAA8gEAAAgAAABwEAMAAQAaAAIAWxAAAA4AAwABAAIAAAD4AQAA" +
+"EwAAAGIAAwAaAQEAbiACABAAYAABANgAAAFnAAEAYgACAG4QBAAAAA4ADAAOPEsAEAAOeGlaAAAB" +
+"AAAACAAGPGluaXQ+AApGaW5hbGl6aW5nAAVIZWxsbwABSQAYTGFydC9UZXN0MjAwNyRUcmFuc2Zv" +
+"cm07AA5MYXJ0L1Rlc3QyMDA3OwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAe" +
+"TGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABpMZGFsdmlrL2Fubm90YXRpb24vVGhyb3dz" +
+"OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcv" +
+"U3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07ABVMamF2YS9sYW5nL1Rocm93YWJsZTsAJUxqYXZh" +
+"L3V0aWwvY29uY3VycmVudC9Db3VudERvd25MYXRjaDsADVRlc3QyMDA3LmphdmEACVRyYW5zZm9y" +
+"bQABVgACVkwAC2FjY2Vzc0ZsYWdzAAljb3VudERvd24AB2NvdW50ZXIACGZpbmFsaXplAAxmaW5p" +
+"c2hfbGF0Y2gACGdyZWV0aW5nAARuYW1lAANvdXQAB3ByaW50bG4ABXZhbHVlAIwBfn5EOHsiY29t" +
+"cGlsYXRpb24tbW9kZSI6ImRlYnVnIiwiaGFzLWNoZWNrc3VtcyI6ZmFsc2UsIm1pbi1hcGkiOjEs" +
+"InNoYS0xIjoiMTI5ZWU5ZjY3NTZjMzlkZjU3ZmYwNzg1ZDI1NmIyMzc3MjY0MmI3YyIsInZlcnNp" +
+"b24iOiIyLjAuMTAtZGV2In0AAgUBHBwBGAoCAwEcGAICBAITBAkZFxAAAQEBAAEAgYAEnAMBBLwD" +
+"AAAAAAEAAABNBAAAAgAAAFUEAABbBAAAgAQAAAAAAAABAAAAAAAAAAEAAAB4BAAAEAAAAAAAAAAB" +
+"AAAAAAAAAAEAAAAeAAAAcAAAAAIAAAANAAAA6AAAAAMAAAACAAAAHAEAAAQAAAAEAAAANAEAAAUA" +
+"AAAFAAAAVAEAAAYAAAABAAAAfAEAAAEgAAACAAAAnAEAAAMgAAACAAAA8gEAAAEQAAABAAAAAAIA" +
+"AAIgAAAeAAAABgIAAAQgAAADAAAATQQAAAAgAAABAAAAZAQAAAMQAAADAAAAdAQAAAYgAAABAAAA" +
+"jAQAAAAQAAABAAAApAQAAA==");
+
+
+ public static void run() throws Exception {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest();
+ }
+
+ public static final class GcThread extends Thread {
+ public volatile boolean finished = false;
+ public void run() {
+ while (!finished) {
+ Runtime.getRuntime().gc();
+ System.runFinalization();
+ }
+ }
+ }
+
+ public static void doTest() throws Exception {
+ // Try GC forever
+ GcThread gc_thr = new GcThread();
+ gc_thr.start();
+ // Make a transform
+ mktransform();
+ Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES);
+ theObject = null;
+ finish_latch.await();
+ System.out.println("counter: " + counter);
+ // Make sure we don't have any remaining things to finalize, eg obsolete objects or something.
+ Runtime.getRuntime().gc();
+ System.runFinalization();
+ gc_thr.finished = true;
+ gc_thr.join();
+ }
+
+ // Make sure there is never a transform in the frame of doTest.
+ public static void mktransform() throws Exception {
+ theObject = new Transform();
+ }
+}
diff --git a/test/2007-virtual-structural-finalizable/src/Main.java b/test/2007-virtual-structural-finalizable/src/Main.java
new file mode 100644
index 0000000..89b8557
--- /dev/null
+++ b/test/2007-virtual-structural-finalizable/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2019 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) throws Exception {
+ System.out.println("FAIL: Test is only for art!");
+ }
+}