blob: e2e5c946a3e6cfda62a33523ac7b6b7d457e0857 [file] [log] [blame]
Ian Rogers57b86d42012-03-27 16:05:41 -07001/*
Elliott Hughes0f3c5532012-03-30 14:51:51 -07002 * Copyright (C) 2012 The Android Open Source Project
Ian Rogers57b86d42012-03-27 16:05:41 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "callee_save_frame.h"
18#include "dex_verifier.h"
19#include "object.h"
20#include "object_utils.h"
21#include "runtime_support.h"
22#include "thread.h"
23
24namespace art {
25
26// Deliver an exception that's pending on thread helping set up a callee save frame on the way.
27extern "C" void artDeliverPendingExceptionFromCode(Thread* thread, Method** sp) {
28 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
29 thread->DeliverException();
30}
31
32// Called by generated call to throw an exception.
33extern "C" void artDeliverExceptionFromCode(Throwable* exception, Thread* thread, Method** sp) {
34 /*
35 * exception may be NULL, in which case this routine should
36 * throw NPE. NOTE: this is a convenience for generated code,
37 * which previously did the null check inline and constructed
38 * and threw a NPE if NULL. This routine responsible for setting
39 * exception_ in thread and delivering the exception.
40 */
41 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
42 if (exception == NULL) {
43 thread->ThrowNewException("Ljava/lang/NullPointerException;", "throw with null exception");
44 } else {
45 thread->SetException(exception);
46 }
47 thread->DeliverException();
48}
49
50// Called by generated call to throw a NPE exception.
51extern "C" void artThrowNullPointerExceptionFromCode(Thread* self, Method** sp) {
52 FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
53 Frame fr = self->GetTopOfStack();
54 uintptr_t throw_native_pc = fr.GetReturnPC();
55 fr.Next();
56 Method* throw_method = fr.GetMethod();
57 uint32_t dex_pc = throw_method->ToDexPC(throw_native_pc - 2);
58 const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem();
59 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
60 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
61 DecodedInstruction dec_insn(instr);
62 switch (instr->Opcode()) {
63 case Instruction::INVOKE_DIRECT:
64 case Instruction::INVOKE_DIRECT_RANGE:
65 ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kDirect);
66 break;
67 case Instruction::INVOKE_VIRTUAL:
68 case Instruction::INVOKE_VIRTUAL_RANGE:
69 ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kVirtual);
70 break;
71 case Instruction::IGET:
72 case Instruction::IGET_WIDE:
73 case Instruction::IGET_OBJECT:
74 case Instruction::IGET_BOOLEAN:
75 case Instruction::IGET_BYTE:
76 case Instruction::IGET_CHAR:
77 case Instruction::IGET_SHORT: {
78 Field* field =
79 Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
80 ThrowNullPointerExceptionForFieldAccess(self, field, true /* read */);
81 break;
82 }
83 case Instruction::IPUT:
84 case Instruction::IPUT_WIDE:
85 case Instruction::IPUT_OBJECT:
86 case Instruction::IPUT_BOOLEAN:
87 case Instruction::IPUT_BYTE:
88 case Instruction::IPUT_CHAR:
89 case Instruction::IPUT_SHORT: {
90 Field* field =
91 Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
92 ThrowNullPointerExceptionForFieldAccess(self, field, false /* write */);
93 break;
94 }
95 case Instruction::AGET:
96 case Instruction::AGET_WIDE:
97 case Instruction::AGET_OBJECT:
98 case Instruction::AGET_BOOLEAN:
99 case Instruction::AGET_BYTE:
100 case Instruction::AGET_CHAR:
101 case Instruction::AGET_SHORT:
102 self->ThrowNewException("Ljava/lang/NullPointerException;",
103 "Attempt to read from null array");
104 break;
105 case Instruction::APUT:
106 case Instruction::APUT_WIDE:
107 case Instruction::APUT_OBJECT:
108 case Instruction::APUT_BOOLEAN:
109 case Instruction::APUT_BYTE:
110 case Instruction::APUT_CHAR:
111 case Instruction::APUT_SHORT:
112 self->ThrowNewException("Ljava/lang/NullPointerException;",
113 "Attempt to write to null array");
114 break;
115 default: {
116 const DexFile& dex_file = Runtime::Current()->GetClassLinker()
117 ->FindDexFile(throw_method->GetDeclaringClass()->GetDexCache());
118 std::string message("Null pointer exception during instruction '");
119 message += instr->DumpString(&dex_file);
120 message += "'";
121 self->ThrowNewException("Ljava/lang/NullPointerException;", message.c_str());
122 break;
123 }
124 }
125 self->DeliverException();
126}
127
128// Called by generated call to throw an arithmetic divide by zero exception.
129extern "C" void artThrowDivZeroFromCode(Thread* thread, Method** sp) {
130 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
131 thread->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
132 thread->DeliverException();
133}
134
135// Called by generated call to throw an array index out of bounds exception.
136extern "C" void artThrowArrayBoundsFromCode(int index, int limit, Thread* thread, Method** sp) {
137 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
138 thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
139 "length=%d; index=%d", limit, index);
140 thread->DeliverException();
141}
142
143extern "C" void artThrowStackOverflowFromCode(Thread* thread, Method** sp) {
144 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
145 // Remove extra entry pushed onto second stack during method tracing
146 if (Runtime::Current()->IsMethodTracingActive()) {
147 TraceMethodUnwindFromCode(thread);
148 }
149 thread->SetStackEndForStackOverflow(); // Allow space on the stack for constructor to execute
150 thread->ThrowNewExceptionF("Ljava/lang/StackOverflowError;",
151 "stack size %zdkb; default stack size: %zdkb",
152 thread->GetStackSize() / KB, Runtime::Current()->GetDefaultStackSize() / KB);
153 thread->ResetDefaultStackEnd(); // Return to default stack size
154 thread->DeliverException();
155}
156
157extern "C" void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self, Method** sp) {
158 FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
159 Frame frame = self->GetTopOfStack(); // We need the calling method as context for the method_idx
160 frame.Next();
161 Method* method = frame.GetMethod();
162 self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
163 MethodNameFromIndex(method, method_idx, verifier::VERIFY_ERROR_REF_METHOD, false).c_str());
164 self->DeliverException();
165}
166
167static std::string ClassNameFromIndex(Method* method, uint32_t ref,
168 verifier::VerifyErrorRefType ref_type, bool access) {
169 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
170 const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
171
172 uint16_t type_idx = 0;
173 if (ref_type == verifier::VERIFY_ERROR_REF_FIELD) {
174 const DexFile::FieldId& id = dex_file.GetFieldId(ref);
175 type_idx = id.class_idx_;
176 } else if (ref_type == verifier::VERIFY_ERROR_REF_METHOD) {
177 const DexFile::MethodId& id = dex_file.GetMethodId(ref);
178 type_idx = id.class_idx_;
179 } else if (ref_type == verifier::VERIFY_ERROR_REF_CLASS) {
180 type_idx = ref;
181 } else {
182 CHECK(false) << static_cast<int>(ref_type);
183 }
184
185 std::string class_name(PrettyDescriptor(dex_file.StringByTypeIdx(type_idx)));
186 if (!access) {
187 return class_name;
188 }
189
190 std::string result;
191 result += "tried to access class ";
192 result += class_name;
193 result += " from class ";
194 result += PrettyDescriptor(method->GetDeclaringClass());
195 return result;
196}
197
198extern "C" void artThrowVerificationErrorFromCode(int32_t kind, int32_t ref, Thread* self, Method** sp) {
199 FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
200 Frame frame = self->GetTopOfStack(); // We need the calling method as context to interpret 'ref'
201 frame.Next();
202 Method* method = frame.GetMethod();
203
204 verifier::VerifyErrorRefType ref_type =
205 static_cast<verifier::VerifyErrorRefType>(kind >> verifier::kVerifyErrorRefTypeShift);
206
207 const char* exception_class = "Ljava/lang/VerifyError;";
208 std::string msg;
209
210 switch (static_cast<verifier::VerifyError>(kind & ~(0xff << verifier::kVerifyErrorRefTypeShift))) {
211 case verifier::VERIFY_ERROR_NO_CLASS:
212 exception_class = "Ljava/lang/NoClassDefFoundError;";
213 msg = ClassNameFromIndex(method, ref, ref_type, false);
214 break;
215 case verifier::VERIFY_ERROR_NO_FIELD:
216 exception_class = "Ljava/lang/NoSuchFieldError;";
217 msg = FieldNameFromIndex(method, ref, ref_type, false);
218 break;
219 case verifier::VERIFY_ERROR_NO_METHOD:
220 exception_class = "Ljava/lang/NoSuchMethodError;";
221 msg = MethodNameFromIndex(method, ref, ref_type, false);
222 break;
223 case verifier::VERIFY_ERROR_ACCESS_CLASS:
224 exception_class = "Ljava/lang/IllegalAccessError;";
225 msg = ClassNameFromIndex(method, ref, ref_type, true);
226 break;
227 case verifier::VERIFY_ERROR_ACCESS_FIELD:
228 exception_class = "Ljava/lang/IllegalAccessError;";
229 msg = FieldNameFromIndex(method, ref, ref_type, true);
230 break;
231 case verifier::VERIFY_ERROR_ACCESS_METHOD:
232 exception_class = "Ljava/lang/IllegalAccessError;";
233 msg = MethodNameFromIndex(method, ref, ref_type, true);
234 break;
235 case verifier::VERIFY_ERROR_CLASS_CHANGE:
236 exception_class = "Ljava/lang/IncompatibleClassChangeError;";
237 msg = ClassNameFromIndex(method, ref, ref_type, false);
238 break;
239 case verifier::VERIFY_ERROR_INSTANTIATION:
240 exception_class = "Ljava/lang/InstantiationError;";
241 msg = ClassNameFromIndex(method, ref, ref_type, false);
242 break;
243 case verifier::VERIFY_ERROR_BAD_CLASS_SOFT:
244 case verifier::VERIFY_ERROR_BAD_CLASS_HARD:
245 // Generic VerifyError; use default exception, no message.
246 break;
247 case verifier::VERIFY_ERROR_NONE:
248 CHECK(false);
249 break;
250 }
251 self->ThrowNewException(exception_class, msg.c_str());
252 self->DeliverException();
253}
254
255} // namespace art