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