summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Igor Murashkin <iam@google.com> 2015-07-22 01:00:59 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2015-07-22 01:00:59 +0000
commit236d0a3c35a369da99bb1f0c617a29f23b2f4df8 (patch)
tree4935e2495e930ee319a618ce6ab7a5dfa924eaaf
parentc962dd742ea2c514cd36f02381c0ad33fc89e8b3 (diff)
parent6bd980c17a023d99ae84acf62a033832caf13f58 (diff)
Merge changes from topic 'lambda_experimental'
* changes: interpreter: Add tests for move-result after invoke-lambda verifier: Skip verification of methods when seeing experimental opcodes
-rw-r--r--runtime/verifier/method_verifier.cc27
-rw-r--r--runtime/verifier/method_verifier.h2
-rw-r--r--test/955-lambda-smali/expected.txt9
-rw-r--r--test/955-lambda-smali/smali/Main.smali1
-rw-r--r--test/955-lambda-smali/smali/MoveResult.smali330
5 files changed, 365 insertions, 4 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 764b6ba0aa..8c950a0610 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -329,14 +329,21 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, uint32_t
} else {
// Bad method data.
CHECK_NE(verifier.failures_.size(), 0U);
- CHECK(verifier.have_pending_hard_failure_);
- verifier.DumpFailures(LOG(INFO) << "Verification error in "
- << PrettyMethod(method_idx, *dex_file) << "\n");
+
+ if (UNLIKELY(verifier.have_pending_experimental_failure_)) {
+ // Failed due to being forced into interpreter. This is ok because
+ // we just want to skip verification.
+ result = kSoftFailure;
+ } else {
+ CHECK(verifier.have_pending_hard_failure_);
+ verifier.DumpFailures(LOG(INFO) << "Verification error in "
+ << PrettyMethod(method_idx, *dex_file) << "\n");
+ result = kHardFailure;
+ }
if (gDebugVerify) {
std::cout << "\n" << verifier.info_messages_.str();
verifier.Dump(std::cout);
}
- result = kHardFailure;
}
if (kTimeVerifyMethod) {
uint64_t duration_ns = NanoTime() - start_ns;
@@ -402,6 +409,7 @@ MethodVerifier::MethodVerifier(Thread* self,
monitor_enter_dex_pcs_(nullptr),
have_pending_hard_failure_(false),
have_pending_runtime_throw_failure_(false),
+ have_pending_experimental_failure_(false),
have_any_pending_runtime_throw_failure_(false),
new_instance_count_(0),
monitor_enter_count_(0),
@@ -813,6 +821,17 @@ bool MethodVerifier::VerifyInstructions() {
}
bool MethodVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_offset) {
+ if (UNLIKELY(inst->IsExperimental())) {
+ // Experimental instructions don't yet have verifier support implementation.
+ // While it is possible to use them by themselves, when we try to use stable instructions
+ // with a virtual register that was created by an experimental instruction,
+ // the data flow analysis will fail.
+ Fail(VERIFY_ERROR_FORCE_INTERPRETER)
+ << "experimental instruction is not supported by verifier; skipping verification";
+ have_pending_experimental_failure_ = true;
+ return false;
+ }
+
bool result = true;
switch (inst->GetVerifyTypeArgumentA()) {
case Instruction::kVerifyRegA:
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index d9334487fa..a2835f56b9 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -736,6 +736,8 @@ class MethodVerifier {
// instructions that would hard fail the verification.
// Note: this flag is reset after processing each instruction.
bool have_pending_runtime_throw_failure_;
+ // Is there a pending experimental failure?
+ bool have_pending_experimental_failure_;
// A version of the above that is not reset and thus captures if there were *any* throw failures.
bool have_any_pending_runtime_throw_failure_;
diff --git a/test/955-lambda-smali/expected.txt b/test/955-lambda-smali/expected.txt
index 5059f4be12..36370998f4 100644
--- a/test/955-lambda-smali/expected.txt
+++ b/test/955-lambda-smali/expected.txt
@@ -7,3 +7,12 @@ Caught NPE
(BoxUnbox) Caught NPE for unbox-lambda
(BoxUnbox) Caught NPE for box-lambda
(BoxUnbox) Caught ClassCastException for unbox-lambda
+(MoveResult) testZ success
+(MoveResult) testB success
+(MoveResult) testS success
+(MoveResult) testI success
+(MoveResult) testC success
+(MoveResult) testJ success
+(MoveResult) testF success
+(MoveResult) testD success
+(MoveResult) testL success
diff --git a/test/955-lambda-smali/smali/Main.smali b/test/955-lambda-smali/smali/Main.smali
index 92afd79ada..5d2aabb386 100644
--- a/test/955-lambda-smali/smali/Main.smali
+++ b/test/955-lambda-smali/smali/Main.smali
@@ -23,6 +23,7 @@
invoke-static {}, LSanityCheck;->run()I
invoke-static {}, LTrivialHelloWorld;->run()V
invoke-static {}, LBoxUnbox;->run()V
+ invoke-static {}, LMoveResult;->run()V
# TODO: add tests when verification fails
diff --git a/test/955-lambda-smali/smali/MoveResult.smali b/test/955-lambda-smali/smali/MoveResult.smali
new file mode 100644
index 0000000000..1725da3044
--- /dev/null
+++ b/test/955-lambda-smali/smali/MoveResult.smali
@@ -0,0 +1,330 @@
+#
+# Copyright (C) 2015 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 public LMoveResult;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 1
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+ return-void
+.end method
+
+.method public static run()V
+.registers 8
+ invoke-static {}, LMoveResult;->testZ()V
+ invoke-static {}, LMoveResult;->testB()V
+ invoke-static {}, LMoveResult;->testS()V
+ invoke-static {}, LMoveResult;->testI()V
+ invoke-static {}, LMoveResult;->testC()V
+ invoke-static {}, LMoveResult;->testJ()V
+ invoke-static {}, LMoveResult;->testF()V
+ invoke-static {}, LMoveResult;->testD()V
+ invoke-static {}, LMoveResult;->testL()V
+
+ return-void
+.end method
+
+# Test that booleans are returned correctly via move-result.
+.method public static testZ()V
+ .registers 6
+
+ create-lambda v0, LMoveResult;->lambdaZ(Ljava/lang/reflect/ArtMethod;)Z
+ invoke-lambda v0, {}
+ move-result v2
+ const v3, 1
+
+ if-ne v3, v2, :is_not_equal
+ const-string v4, "(MoveResult) testZ success"
+ goto :end
+
+:is_not_equal
+ const-string v4, "(MoveResult) testZ failed"
+
+:end
+ sget-object v5, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v5, v4}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+
+.end method
+
+# Lambda target for testZ. Always returns "true".
+.method public static lambdaZ(Ljava/lang/reflect/ArtMethod;)Z
+ .registers 3
+
+ const v0, 1
+ return v0
+
+.end method
+
+# Test that bytes are returned correctly via move-result.
+.method public static testB()V
+ .registers 6
+
+ create-lambda v0, LMoveResult;->lambdaB(Ljava/lang/reflect/ArtMethod;)B
+ invoke-lambda v0, {}
+ move-result v2
+ const v3, 15
+
+ if-ne v3, v2, :is_not_equal
+ const-string v4, "(MoveResult) testB success"
+ goto :end
+
+:is_not_equal
+ const-string v4, "(MoveResult) testB failed"
+
+:end
+ sget-object v5, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v5, v4}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+
+.end method
+
+# Lambda target for testB. Always returns "15".
+.method public static lambdaB(Ljava/lang/reflect/ArtMethod;)B
+ .registers 3 # 1 parameters, 2 locals
+
+ const v0, 15
+ return v0
+
+.end method
+
+# Test that shorts are returned correctly via move-result.
+.method public static testS()V
+ .registers 6
+
+ create-lambda v0, LMoveResult;->lambdaS(Ljava/lang/reflect/ArtMethod;)S
+ invoke-lambda v0, {}
+ move-result v2
+ const/16 v3, 31000
+
+ if-ne v3, v2, :is_not_equal
+ const-string v4, "(MoveResult) testS success"
+ goto :end
+
+:is_not_equal
+ const-string v4, "(MoveResult) testS failed"
+
+:end
+ sget-object v5, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v5, v4}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+
+.end method
+
+# Lambda target for testS. Always returns "31000".
+.method public static lambdaS(Ljava/lang/reflect/ArtMethod;)S
+ .registers 3
+
+ const/16 v0, 31000
+ return v0
+
+.end method
+
+# Test that ints are returned correctly via move-result.
+.method public static testI()V
+ .registers 6
+
+ create-lambda v0, LMoveResult;->lambdaI(Ljava/lang/reflect/ArtMethod;)I
+ invoke-lambda v0, {}
+ move-result v2
+ const v3, 128000
+
+ if-ne v3, v2, :is_not_equal
+ const-string v4, "(MoveResult) testI success"
+ goto :end
+
+:is_not_equal
+ const-string v4, "(MoveResult) testI failed"
+
+:end
+ sget-object v5, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v5, v4}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+
+.end method
+
+# Lambda target for testI. Always returns "128000".
+.method public static lambdaI(Ljava/lang/reflect/ArtMethod;)I
+ .registers 3
+
+ const v0, 128000
+ return v0
+
+.end method
+
+# Test that chars are returned correctly via move-result.
+.method public static testC()V
+ .registers 6
+
+ create-lambda v0, LMoveResult;->lambdaC(Ljava/lang/reflect/ArtMethod;)C
+ invoke-lambda v0, {}
+ move-result v2
+ const v3, 65535
+
+ if-ne v3, v2, :is_not_equal
+ const-string v4, "(MoveResult) testC success"
+ goto :end
+
+:is_not_equal
+ const-string v4, "(MoveResult) testC failed"
+
+:end
+ sget-object v5, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v5, v4}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+
+.end method
+
+# Lambda target for testC. Always returns "65535".
+.method public static lambdaC(Ljava/lang/reflect/ArtMethod;)C
+ .registers 3
+
+ const v0, 65535
+ return v0
+
+.end method
+
+# Test that longs are returned correctly via move-result.
+.method public static testJ()V
+ .registers 8
+
+ create-lambda v0, LMoveResult;->lambdaJ(Ljava/lang/reflect/ArtMethod;)J
+ invoke-lambda v0, {}
+ move-result v2
+ const-wide v4, 0xdeadf00dc0ffee
+
+ if-ne v4, v2, :is_not_equal
+ const-string v6, "(MoveResult) testJ success"
+ goto :end
+
+:is_not_equal
+ const-string v6, "(MoveResult) testJ failed"
+
+:end
+ sget-object v7, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v7, v6}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+
+.end method
+
+# Lambda target for testC. Always returns "0xdeadf00dc0ffee".
+.method public static lambdaJ(Ljava/lang/reflect/ArtMethod;)J
+ .registers 4
+
+ const-wide v0, 0xdeadf00dc0ffee
+ return-wide v0
+
+.end method
+
+# Test that floats are returned correctly via move-result.
+.method public static testF()V
+ .registers 6
+
+ create-lambda v0, LMoveResult;->lambdaF(Ljava/lang/reflect/ArtMethod;)F
+ invoke-lambda v0, {}
+ move-result v2
+ const v3, infinityf
+
+ if-ne v3, v2, :is_not_equal
+ const-string v4, "(MoveResult) testF success"
+ goto :end
+
+:is_not_equal
+ const-string v4, "(MoveResult) testF failed"
+
+:end
+ sget-object v5, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v5, v4}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+
+.end method
+
+# Lambda target for testF. Always returns "infinityf".
+.method public static lambdaF(Ljava/lang/reflect/ArtMethod;)F
+ .registers 3
+
+ const v0, infinityf
+ return v0
+
+.end method
+
+# Test that doubles are returned correctly via move-result.
+.method public static testD()V
+ .registers 8
+
+ create-lambda v0, LMoveResult;->lambdaD(Ljava/lang/reflect/ArtMethod;)D
+ invoke-lambda v0, {}
+ move-result-wide v2
+ const-wide v4, infinity
+
+ if-ne v4, v2, :is_not_equal
+ const-string v6, "(MoveResult) testD success"
+ goto :end
+
+:is_not_equal
+ const-string v6, "(MoveResult) testD failed"
+
+:end
+ sget-object v7, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v7, v6}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+
+.end method
+
+# Lambda target for testD. Always returns "infinity".
+.method public static lambdaD(Ljava/lang/reflect/ArtMethod;)D
+ .registers 4
+
+ const-wide v0, infinity # 123.456789
+ return-wide v0
+
+.end method
+
+
+# Test that objects are returned correctly via move-result.
+.method public static testL()V
+ .registers 8
+
+ create-lambda v0, LMoveResult;->lambdaL(Ljava/lang/reflect/ArtMethod;)Ljava/lang/String;
+ invoke-lambda v0, {}
+ move-result-object v2
+ const-string v4, "Interned string"
+
+ # relies on string interning returning identical object references
+ if-ne v4, v2, :is_not_equal
+ const-string v6, "(MoveResult) testL success"
+ goto :end
+
+:is_not_equal
+ const-string v6, "(MoveResult) testL failed"
+
+:end
+ sget-object v7, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v7, v6}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+
+.end method
+
+# Lambda target for testL. Always returns "Interned string" (string).
+.method public static lambdaL(Ljava/lang/reflect/ArtMethod;)Ljava/lang/String;
+ .registers 4
+
+ const-string v0, "Interned string"
+ return-object v0
+
+.end method
+
+