OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/exceptions.h" | 5 #include "vm/exceptions.h" |
6 | 6 |
7 #include "platform/address_sanitizer.h" | 7 #include "platform/address_sanitizer.h" |
8 | 8 |
9 #include "vm/dart_api_impl.h" | 9 #include "vm/dart_api_impl.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 | 137 |
138 | 138 |
139 // Iterate through the stack frames and try to find a frame with an | 139 // Iterate through the stack frames and try to find a frame with an |
140 // exception handler. Once found, set the pc, sp and fp so that execution | 140 // exception handler. Once found, set the pc, sp and fp so that execution |
141 // can continue in that frame. Sets 'needs_stacktrace' if there is no | 141 // can continue in that frame. Sets 'needs_stacktrace' if there is no |
142 // cath-all handler or if a stack-trace is specified in the catch. | 142 // cath-all handler or if a stack-trace is specified in the catch. |
143 static bool FindExceptionHandler(Thread* thread, | 143 static bool FindExceptionHandler(Thread* thread, |
144 uword* handler_pc, | 144 uword* handler_pc, |
145 uword* handler_sp, | 145 uword* handler_sp, |
146 uword* handler_fp, | 146 uword* handler_fp, |
147 uword** handler_pp_slot, | |
148 bool* needs_stacktrace) { | 147 bool* needs_stacktrace) { |
149 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); | 148 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); |
150 StackFrame* frame = frames.NextFrame(); | 149 StackFrame* frame = frames.NextFrame(); |
151 if (frame == NULL) return false; // No Dart frame. | 150 if (frame == NULL) return false; // No Dart frame. |
152 bool handler_pc_set = false; | 151 bool handler_pc_set = false; |
153 *needs_stacktrace = false; | 152 *needs_stacktrace = false; |
154 bool is_catch_all = false; | 153 bool is_catch_all = false; |
155 uword temp_handler_pc = kUwordMax; | 154 uword temp_handler_pc = kUwordMax; |
156 uword* saved_pp_slot = 0; | |
157 while (!frame->IsEntryFrame()) { | 155 while (!frame->IsEntryFrame()) { |
158 if (frame->IsDartFrame()) { | 156 if (frame->IsDartFrame()) { |
159 if (frame->FindExceptionHandler(thread, | 157 if (frame->FindExceptionHandler(thread, |
160 &temp_handler_pc, | 158 &temp_handler_pc, |
161 needs_stacktrace, | 159 needs_stacktrace, |
162 &is_catch_all)) { | 160 &is_catch_all)) { |
163 if (!handler_pc_set) { | 161 if (!handler_pc_set) { |
164 handler_pc_set = true; | 162 handler_pc_set = true; |
165 *handler_pc = temp_handler_pc; | 163 *handler_pc = temp_handler_pc; |
166 *handler_sp = frame->sp(); | 164 *handler_sp = frame->sp(); |
167 *handler_fp = frame->fp(); | 165 *handler_fp = frame->fp(); |
168 *handler_pp_slot = saved_pp_slot; | |
169 } | 166 } |
170 if (*needs_stacktrace || is_catch_all) { | 167 if (*needs_stacktrace || is_catch_all) { |
171 return true; | 168 return true; |
172 } | 169 } |
173 } | 170 } |
174 } // if frame->IsDartFrame | 171 } // if frame->IsDartFrame |
175 #if !defined(TARGET_ARCH_IA32) && !defined(TARGET_ARCH_DBC) | |
176 saved_pp_slot = frame->saved_caller_pp_slot(); | |
177 #endif | |
178 frame = frames.NextFrame(); | 172 frame = frames.NextFrame(); |
179 ASSERT(frame != NULL); | 173 ASSERT(frame != NULL); |
180 } // while !frame->IsEntryFrame | 174 } // while !frame->IsEntryFrame |
181 ASSERT(frame->IsEntryFrame()); | 175 ASSERT(frame->IsEntryFrame()); |
182 if (!handler_pc_set) { | 176 if (!handler_pc_set) { |
183 *handler_pc = frame->pc(); | 177 *handler_pc = frame->pc(); |
184 *handler_sp = frame->sp(); | 178 *handler_sp = frame->sp(); |
185 *handler_fp = frame->fp(); | 179 *handler_fp = frame->fp(); |
186 *handler_pp_slot = saved_pp_slot; | |
187 } | 180 } |
188 // No catch-all encountered, needs stacktrace. | 181 // No catch-all encountered, needs stacktrace. |
189 *needs_stacktrace = true; | 182 *needs_stacktrace = true; |
190 return handler_pc_set; | 183 return handler_pc_set; |
191 } | 184 } |
192 | 185 |
193 | 186 |
194 static void FindErrorHandler(uword* handler_pc, | 187 static void FindErrorHandler(uword* handler_pc, |
195 uword* handler_sp, | 188 uword* handler_sp, |
196 uword* handler_fp, | 189 uword* handler_fp) { |
197 uword** handler_pp_slot) { | |
198 // TODO(turnidge): Is there a faster way to get the next entry frame? | 190 // TODO(turnidge): Is there a faster way to get the next entry frame? |
199 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); | 191 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); |
200 StackFrame* frame = frames.NextFrame(); | 192 StackFrame* frame = frames.NextFrame(); |
201 ASSERT(frame != NULL); | 193 ASSERT(frame != NULL); |
202 uword* saved_pp_slot = NULL; | |
203 while (!frame->IsEntryFrame()) { | 194 while (!frame->IsEntryFrame()) { |
204 #if !defined(TARGET_ARCH_IA32) && !defined(TARGET_ARCH_DBC) | |
205 saved_pp_slot = frame->saved_caller_pp_slot(); | |
206 #endif | |
207 frame = frames.NextFrame(); | 195 frame = frames.NextFrame(); |
208 ASSERT(frame != NULL); | 196 ASSERT(frame != NULL); |
209 } | 197 } |
210 ASSERT(frame->IsEntryFrame()); | 198 ASSERT(frame->IsEntryFrame()); |
211 *handler_pc = frame->pc(); | 199 *handler_pc = frame->pc(); |
212 *handler_sp = frame->sp(); | 200 *handler_sp = frame->sp(); |
213 *handler_fp = frame->fp(); | 201 *handler_fp = frame->fp(); |
214 *handler_pp_slot = saved_pp_slot; | |
215 } | 202 } |
216 | 203 |
217 | 204 |
218 static void JumpToExceptionHandler(Thread* thread, | 205 static void JumpToExceptionHandler(Thread* thread, |
219 uword program_counter, | 206 uword program_counter, |
220 uword stack_pointer, | 207 uword stack_pointer, |
221 uword frame_pointer, | 208 uword frame_pointer, |
222 uword* pool_pointer_slot, | |
223 const Object& exception_object, | 209 const Object& exception_object, |
224 const Object& stacktrace_object) { | 210 const Object& stacktrace_object) { |
225 // The no_gc StackResource is unwound through the tear down of | 211 // The no_gc StackResource is unwound through the tear down of |
226 // stack resources below. | 212 // stack resources below. |
227 NoSafepointScope no_safepoint; | 213 NoSafepointScope no_safepoint; |
228 RawObject* raw_exception = exception_object.raw(); | 214 RawObject* raw_exception = exception_object.raw(); |
229 RawObject* raw_stacktrace = stacktrace_object.raw(); | 215 RawObject* raw_stacktrace = stacktrace_object.raw(); |
230 | 216 |
231 #if !defined(TARGET_ARCH_IA32) && !defined(TARGET_ARCH_DBC) | |
232 ASSERT(pool_pointer_slot != NULL); | |
233 uword pool_pointer = *pool_pointer_slot; | |
234 // TODO(rmacnak): Lazy deopt without patching alters pc and pp here. | |
235 #else | |
236 uword pool_pointer = 0; | |
237 #endif | |
238 | |
239 #if defined(USING_SIMULATOR) | 217 #if defined(USING_SIMULATOR) |
240 // Unwinding of the C++ frames and destroying of their stack resources is done | 218 // Unwinding of the C++ frames and destroying of their stack resources is done |
241 // by the simulator, because the target stack_pointer is a simulated stack | 219 // by the simulator, because the target stack_pointer is a simulated stack |
242 // pointer and not the C++ stack pointer. | 220 // pointer and not the C++ stack pointer. |
243 | 221 |
244 // Continue simulating at the given pc in the given frame after setting up the | 222 // Continue simulating at the given pc in the given frame after setting up the |
245 // exception object in the kExceptionObjectReg register and the stacktrace | 223 // exception object in the kExceptionObjectReg register and the stacktrace |
246 // object (may be raw null) in the kStackTraceObjectReg register. | 224 // object (may be raw null) in the kStackTraceObjectReg register. |
247 | 225 |
248 Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer, | 226 Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer, |
249 pool_pointer, raw_exception, raw_stacktrace, | 227 raw_exception, raw_stacktrace, thread); |
250 thread); | |
251 #else | 228 #else |
252 // Prepare for unwinding frames by destroying all the stack resources | 229 // Prepare for unwinding frames by destroying all the stack resources |
253 // in the previous frames. | 230 // in the previous frames. |
254 StackResource::Unwind(thread); | 231 StackResource::Unwind(thread); |
255 | 232 |
256 // Call a stub to set up the exception object in kExceptionObjectReg, | 233 // Call a stub to set up the exception object in kExceptionObjectReg, |
257 // to set up the stacktrace object in kStackTraceObjectReg, and to | 234 // to set up the stacktrace object in kStackTraceObjectReg, and to |
258 // continue execution at the given pc in the given frame. | 235 // continue execution at the given pc in the given frame. |
259 typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*, | 236 typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*, |
260 Thread*, uword); | 237 Thread*); |
261 ExcpHandler func = reinterpret_cast<ExcpHandler>( | 238 ExcpHandler func = reinterpret_cast<ExcpHandler>( |
262 StubCode::JumpToExceptionHandler_entry()->EntryPoint()); | 239 StubCode::JumpToExceptionHandler_entry()->EntryPoint()); |
263 | 240 |
264 // Unpoison the stack before we tear it down in the generated stub code. | 241 // Unpoison the stack before we tear it down in the generated stub code. |
265 uword current_sp = Thread::GetCurrentStackPointer() - 1024; | 242 uword current_sp = Thread::GetCurrentStackPointer() - 1024; |
266 ASAN_UNPOISON(reinterpret_cast<void*>(current_sp), | 243 ASAN_UNPOISON(reinterpret_cast<void*>(current_sp), |
267 stack_pointer - current_sp); | 244 stack_pointer - current_sp); |
268 | 245 |
269 func(program_counter, stack_pointer, frame_pointer, | 246 func(program_counter, stack_pointer, frame_pointer, |
270 raw_exception, raw_stacktrace, thread, pool_pointer); | 247 raw_exception, raw_stacktrace, thread); |
271 #endif | 248 #endif |
272 UNREACHABLE(); | 249 UNREACHABLE(); |
273 } | 250 } |
274 | 251 |
275 | 252 |
276 static RawField* LookupStacktraceField(const Instance& instance) { | 253 static RawField* LookupStacktraceField(const Instance& instance) { |
277 if (instance.GetClassId() < kNumPredefinedCids) { | 254 if (instance.GetClassId() < kNumPredefinedCids) { |
278 // 'class Error' is not a predefined class. | 255 // 'class Error' is not a predefined class. |
279 return Field::null(); | 256 return Field::null(); |
280 } | 257 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 if (exception.IsNull()) { | 310 if (exception.IsNull()) { |
334 exception ^= Exceptions::Create(Exceptions::kNullThrown, | 311 exception ^= Exceptions::Create(Exceptions::kNullThrown, |
335 Object::empty_array()); | 312 Object::empty_array()); |
336 } else if (exception.raw() == isolate->object_store()->out_of_memory() || | 313 } else if (exception.raw() == isolate->object_store()->out_of_memory() || |
337 exception.raw() == isolate->object_store()->stack_overflow()) { | 314 exception.raw() == isolate->object_store()->stack_overflow()) { |
338 use_preallocated_stacktrace = true; | 315 use_preallocated_stacktrace = true; |
339 } | 316 } |
340 uword handler_pc = 0; | 317 uword handler_pc = 0; |
341 uword handler_sp = 0; | 318 uword handler_sp = 0; |
342 uword handler_fp = 0; | 319 uword handler_fp = 0; |
343 uword* handler_pp_slot = 0; | |
344 Instance& stacktrace = Instance::Handle(zone); | 320 Instance& stacktrace = Instance::Handle(zone); |
345 bool handler_exists = false; | 321 bool handler_exists = false; |
346 bool handler_needs_stacktrace = false; | 322 bool handler_needs_stacktrace = false; |
347 if (use_preallocated_stacktrace) { | 323 if (use_preallocated_stacktrace) { |
348 stacktrace ^= isolate->object_store()->preallocated_stack_trace(); | 324 stacktrace ^= isolate->object_store()->preallocated_stack_trace(); |
349 PreallocatedStacktraceBuilder frame_builder(stacktrace); | 325 PreallocatedStacktraceBuilder frame_builder(stacktrace); |
350 handler_exists = FindExceptionHandler(thread, | 326 handler_exists = FindExceptionHandler(thread, |
351 &handler_pc, | 327 &handler_pc, |
352 &handler_sp, | 328 &handler_sp, |
353 &handler_fp, | 329 &handler_fp, |
354 &handler_pp_slot, | |
355 &handler_needs_stacktrace); | 330 &handler_needs_stacktrace); |
356 if (handler_pc == 0) { | 331 if (handler_pc == 0) { |
357 // No Dart frame. | 332 // No Dart frame. |
358 ASSERT(incoming_exception.raw() == | 333 ASSERT(incoming_exception.raw() == |
359 isolate->object_store()->out_of_memory()); | 334 isolate->object_store()->out_of_memory()); |
360 const UnhandledException& error = UnhandledException::Handle( | 335 const UnhandledException& error = UnhandledException::Handle( |
361 zone, isolate->object_store()->preallocated_unhandled_exception()); | 336 zone, isolate->object_store()->preallocated_unhandled_exception()); |
362 thread->long_jump_base()->Jump(1, error); | 337 thread->long_jump_base()->Jump(1, error); |
363 UNREACHABLE(); | 338 UNREACHABLE(); |
364 } | 339 } |
365 if (handler_needs_stacktrace) { | 340 if (handler_needs_stacktrace) { |
366 BuildStackTrace(&frame_builder); | 341 BuildStackTrace(&frame_builder); |
367 } | 342 } |
368 } else { | 343 } else { |
369 // Get stacktrace field of class Error. This is needed to determine whether | 344 // Get stacktrace field of class Error. This is needed to determine whether |
370 // we have a subclass of Error which carries around its stack trace. | 345 // we have a subclass of Error which carries around its stack trace. |
371 const Field& stacktrace_field = | 346 const Field& stacktrace_field = |
372 Field::Handle(zone, LookupStacktraceField(exception)); | 347 Field::Handle(zone, LookupStacktraceField(exception)); |
373 | 348 |
374 // Find the exception handler and determine if the handler needs a | 349 // Find the exception handler and determine if the handler needs a |
375 // stacktrace. | 350 // stacktrace. |
376 handler_exists = FindExceptionHandler(thread, | 351 handler_exists = FindExceptionHandler(thread, |
377 &handler_pc, | 352 &handler_pc, |
378 &handler_sp, | 353 &handler_sp, |
379 &handler_fp, | 354 &handler_fp, |
380 &handler_pp_slot, | |
381 &handler_needs_stacktrace); | 355 &handler_needs_stacktrace); |
382 if (!existing_stacktrace.IsNull()) { | 356 if (!existing_stacktrace.IsNull()) { |
383 // If we have an existing stack trace then this better be a rethrow. The | 357 // If we have an existing stack trace then this better be a rethrow. The |
384 // reverse is not necessarily true (e.g. Dart_PropagateError can cause | 358 // reverse is not necessarily true (e.g. Dart_PropagateError can cause |
385 // a rethrow being called without an existing stacktrace.) | 359 // a rethrow being called without an existing stacktrace.) |
386 ASSERT(is_rethrow); | 360 ASSERT(is_rethrow); |
387 ASSERT(stacktrace_field.IsNull() || | 361 ASSERT(stacktrace_field.IsNull() || |
388 (exception.GetField(stacktrace_field) != Object::null())); | 362 (exception.GetField(stacktrace_field) != Object::null())); |
389 stacktrace = existing_stacktrace.raw(); | 363 stacktrace = existing_stacktrace.raw(); |
390 } else if (!stacktrace_field.IsNull() || handler_needs_stacktrace) { | 364 } else if (!stacktrace_field.IsNull() || handler_needs_stacktrace) { |
(...skipping 17 matching lines...) Expand all Loading... |
408 if (FLAG_print_stacktrace_at_throw) { | 382 if (FLAG_print_stacktrace_at_throw) { |
409 THR_Print("Exception '%s' thrown:\n", exception.ToCString()); | 383 THR_Print("Exception '%s' thrown:\n", exception.ToCString()); |
410 THR_Print("%s\n", stacktrace.ToCString()); | 384 THR_Print("%s\n", stacktrace.ToCString()); |
411 } | 385 } |
412 if (handler_exists) { | 386 if (handler_exists) { |
413 // Found a dart handler for the exception, jump to it. | 387 // Found a dart handler for the exception, jump to it. |
414 JumpToExceptionHandler(thread, | 388 JumpToExceptionHandler(thread, |
415 handler_pc, | 389 handler_pc, |
416 handler_sp, | 390 handler_sp, |
417 handler_fp, | 391 handler_fp, |
418 handler_pp_slot, | |
419 exception, | 392 exception, |
420 stacktrace); | 393 stacktrace); |
421 } else { | 394 } else { |
422 // No dart exception handler found in this invocation sequence, | 395 // No dart exception handler found in this invocation sequence, |
423 // so we create an unhandled exception object and return to the | 396 // so we create an unhandled exception object and return to the |
424 // invocation stub so that it returns this unhandled exception | 397 // invocation stub so that it returns this unhandled exception |
425 // object. The C++ code which invoked this dart sequence can check | 398 // object. The C++ code which invoked this dart sequence can check |
426 // and do the appropriate thing (rethrow the exception to the | 399 // and do the appropriate thing (rethrow the exception to the |
427 // dart invocation sequence above it, print diagnostics and terminate | 400 // dart invocation sequence above it, print diagnostics and terminate |
428 // the isolate etc.). | 401 // the isolate etc.). |
429 const UnhandledException& unhandled_exception = UnhandledException::Handle( | 402 const UnhandledException& unhandled_exception = UnhandledException::Handle( |
430 zone, UnhandledException::New(exception, stacktrace)); | 403 zone, UnhandledException::New(exception, stacktrace)); |
431 stacktrace = Stacktrace::null(); | 404 stacktrace = Stacktrace::null(); |
432 JumpToExceptionHandler(thread, | 405 JumpToExceptionHandler(thread, |
433 handler_pc, | 406 handler_pc, |
434 handler_sp, | 407 handler_sp, |
435 handler_fp, | 408 handler_fp, |
436 handler_pp_slot, | |
437 unhandled_exception, | 409 unhandled_exception, |
438 stacktrace); | 410 stacktrace); |
439 } | 411 } |
440 UNREACHABLE(); | 412 UNREACHABLE(); |
441 } | 413 } |
442 | 414 |
443 | 415 |
444 // Static helpers for allocating, initializing, and throwing an error instance. | 416 // Static helpers for allocating, initializing, and throwing an error instance. |
445 | 417 |
446 // Return the script of the Dart function that called the native entry or the | 418 // Return the script of the Dart function that called the native entry or the |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
610 const Instance& exc = Instance::Handle(zone, uhe.exception()); | 582 const Instance& exc = Instance::Handle(zone, uhe.exception()); |
611 const Instance& stk = Instance::Handle(zone, uhe.stacktrace()); | 583 const Instance& stk = Instance::Handle(zone, uhe.stacktrace()); |
612 Exceptions::ReThrow(thread, exc, stk); | 584 Exceptions::ReThrow(thread, exc, stk); |
613 } else { | 585 } else { |
614 // Return to the invocation stub and return this error object. The | 586 // Return to the invocation stub and return this error object. The |
615 // C++ code which invoked this dart sequence can check and do the | 587 // C++ code which invoked this dart sequence can check and do the |
616 // appropriate thing. | 588 // appropriate thing. |
617 uword handler_pc = 0; | 589 uword handler_pc = 0; |
618 uword handler_sp = 0; | 590 uword handler_sp = 0; |
619 uword handler_fp = 0; | 591 uword handler_fp = 0; |
620 uword* handler_pp_slot = NULL; | 592 FindErrorHandler(&handler_pc, &handler_sp, &handler_fp); |
621 const Stacktrace& stacktrace = Stacktrace::Handle(zone); // null | 593 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, error, |
622 FindErrorHandler(&handler_pc, &handler_sp, &handler_fp, &handler_pp_slot); | 594 Stacktrace::Handle(zone)); // Null stacktrace. |
623 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, | |
624 handler_pp_slot, error, stacktrace); | |
625 } | 595 } |
626 UNREACHABLE(); | 596 UNREACHABLE(); |
627 } | 597 } |
628 | 598 |
629 | 599 |
630 void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) { | 600 void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) { |
631 Thread* thread = Thread::Current(); | 601 Thread* thread = Thread::Current(); |
632 const Object& result = | 602 const Object& result = |
633 Object::Handle(thread->zone(), Create(type, arguments)); | 603 Object::Handle(thread->zone(), Create(type, arguments)); |
634 if (result.IsError()) { | 604 if (result.IsError()) { |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
768 } | 738 } |
769 | 739 |
770 return DartLibraryCalls::InstanceCreate(library, | 740 return DartLibraryCalls::InstanceCreate(library, |
771 *class_name, | 741 *class_name, |
772 *constructor_name, | 742 *constructor_name, |
773 arguments); | 743 arguments); |
774 } | 744 } |
775 | 745 |
776 | 746 |
777 } // namespace dart | 747 } // namespace dart |
OLD | NEW |