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 "lib/stacktrace.h" | 9 #include "lib/stacktrace.h" |
10 | 10 |
11 #include "vm/dart_api_impl.h" | 11 #include "vm/dart_api_impl.h" |
12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/datastream.h" |
13 #include "vm/debugger.h" | 14 #include "vm/debugger.h" |
| 15 #include "vm/deopt_instructions.h" |
14 #include "vm/flags.h" | 16 #include "vm/flags.h" |
15 #include "vm/log.h" | 17 #include "vm/log.h" |
16 #include "vm/longjump.h" | 18 #include "vm/longjump.h" |
17 #include "vm/object.h" | 19 #include "vm/object.h" |
18 #include "vm/object_store.h" | 20 #include "vm/object_store.h" |
19 #include "vm/stack_frame.h" | 21 #include "vm/stack_frame.h" |
20 #include "vm/stub_code.h" | 22 #include "vm/stub_code.h" |
21 #include "vm/symbols.h" | 23 #include "vm/symbols.h" |
22 #include "vm/tags.h" | 24 #include "vm/tags.h" |
23 | 25 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 code = frame->LookupDartCode(); | 138 code = frame->LookupDartCode(); |
137 ASSERT(code.ContainsInstructionAt(frame->pc())); | 139 ASSERT(code.ContainsInstructionAt(frame->pc())); |
138 offset = Smi::New(frame->pc() - code.PayloadStart()); | 140 offset = Smi::New(frame->pc() - code.PayloadStart()); |
139 builder->AddFrame(code, offset); | 141 builder->AddFrame(code, offset); |
140 } | 142 } |
141 frame = frames.NextFrame(); | 143 frame = frames.NextFrame(); |
142 } | 144 } |
143 } | 145 } |
144 | 146 |
145 | 147 |
146 // Iterate through the stack frames and try to find a frame with an | 148 static RawObject** VariableAt(uword fp, int stack_slot) { |
147 // exception handler. Once found, set the pc, sp and fp so that execution | 149 #if defined(TARGET_ARCH_DBC) |
148 // can continue in that frame. Sets 'needs_stacktrace' if there is no | 150 return reinterpret_cast<RawObject**>(fp + stack_slot * kWordSize); |
149 // cath-all handler or if a stack-trace is specified in the catch. | 151 #else |
150 static bool FindExceptionHandler(Thread* thread, | 152 if (stack_slot < 0) { |
151 uword* handler_pc, | 153 return reinterpret_cast<RawObject**>(ParamAddress(fp, -stack_slot)); |
152 uword* handler_sp, | 154 } else { |
153 uword* handler_fp, | 155 return reinterpret_cast<RawObject**>( |
154 bool* needs_stacktrace) { | 156 LocalVarAddress(fp, kFirstLocalSlotFromFp - stack_slot)); |
155 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); | 157 } |
156 StackFrame* frame = frames.NextFrame(); | 158 #endif |
157 if (frame == NULL) return false; // No Dart frame. | 159 } |
158 bool handler_pc_set = false; | 160 |
159 *needs_stacktrace = false; | 161 |
160 bool is_catch_all = false; | 162 class ExceptionHandlerFinder : public StackResource { |
161 uword temp_handler_pc = kUwordMax; | 163 public: |
162 while (!frame->IsEntryFrame()) { | 164 explicit ExceptionHandlerFinder(Thread* thread) |
163 if (frame->IsDartFrame()) { | 165 : StackResource(thread), thread_(thread), cache_(NULL), metadata_(NULL) {} |
164 if (frame->FindExceptionHandler(thread, &temp_handler_pc, | 166 |
165 needs_stacktrace, &is_catch_all)) { | 167 // Iterate through the stack frames and try to find a frame with an |
166 if (!handler_pc_set) { | 168 // exception handler. Once found, set the pc, sp and fp so that execution |
167 handler_pc_set = true; | 169 // can continue in that frame. Sets 'needs_stacktrace' if there is no |
168 *handler_pc = temp_handler_pc; | 170 // cath-all handler or if a stack-trace is specified in the catch. |
169 *handler_sp = frame->sp(); | 171 bool Find() { |
170 *handler_fp = frame->fp(); | 172 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); |
171 } | 173 StackFrame* frame = frames.NextFrame(); |
172 if (*needs_stacktrace || is_catch_all) { | 174 if (frame == NULL) return false; // No Dart frame. |
173 return true; | 175 handler_pc_set_ = false; |
174 } | 176 needs_stacktrace = false; |
| 177 bool is_catch_all = false; |
| 178 uword temp_handler_pc = kUwordMax; |
| 179 bool is_optimized = false; |
| 180 code_ = NULL; |
| 181 cache_ = thread_->isolate()->catch_entry_state_cache(); |
| 182 |
| 183 while (!frame->IsEntryFrame()) { |
| 184 if (frame->IsDartFrame()) { |
| 185 if (frame->FindExceptionHandler(thread_, &temp_handler_pc, |
| 186 &needs_stacktrace, &is_catch_all, |
| 187 &is_optimized)) { |
| 188 if (!handler_pc_set_) { |
| 189 handler_pc_set_ = true; |
| 190 handler_pc = temp_handler_pc; |
| 191 handler_sp = frame->sp(); |
| 192 handler_fp = frame->fp(); |
| 193 if (is_optimized) { |
| 194 pc_ = frame->pc(); |
| 195 code_ = &Code::Handle(frame->LookupDartCode()); |
| 196 CatchEntryState* state = cache_->Lookup(pc_); |
| 197 if (state != NULL) cached_ = *state; |
| 198 #if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER) |
| 199 intptr_t num_vars = Smi::Value(code_->variables()); |
| 200 if (cached_.Empty()) GetMetaDataFromDeopt(num_vars, frame); |
| 201 #else |
| 202 if (cached_.Empty()) ReadCompressedMetaData(); |
| 203 #endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER) |
| 204 } |
| 205 } |
| 206 if (needs_stacktrace || is_catch_all) { |
| 207 return true; |
| 208 } |
| 209 } |
| 210 } // if frame->IsDartFrame |
| 211 frame = frames.NextFrame(); |
| 212 ASSERT(frame != NULL); |
| 213 } // while !frame->IsEntryFrame |
| 214 ASSERT(frame->IsEntryFrame()); |
| 215 if (!handler_pc_set_) { |
| 216 handler_pc = frame->pc(); |
| 217 handler_sp = frame->sp(); |
| 218 handler_fp = frame->fp(); |
| 219 } |
| 220 // No catch-all encountered, needs stacktrace. |
| 221 needs_stacktrace = true; |
| 222 return handler_pc_set_; |
| 223 } |
| 224 |
| 225 void TrySync() { |
| 226 if (code_ == NULL || !code_->is_optimized()) { |
| 227 return; |
| 228 } |
| 229 if (!cached_.Empty()) { |
| 230 // Cache hit. |
| 231 TrySyncCached(&cached_); |
| 232 } else { |
| 233 // New cache entry. |
| 234 CatchEntryState m(metadata_); |
| 235 TrySyncCached(&m); |
| 236 cache_->Insert(pc_, m); |
| 237 } |
| 238 } |
| 239 |
| 240 void TrySyncCached(CatchEntryState* md) { |
| 241 uword fp = handler_fp; |
| 242 ObjectPool* pool = NULL; |
| 243 intptr_t pairs = md->Pairs(); |
| 244 for (int j = 0; j < pairs; j++) { |
| 245 intptr_t src = md->Src(j); |
| 246 intptr_t dest = md->Dest(j); |
| 247 if (md->isMove(j)) { |
| 248 *VariableAt(fp, dest) = *VariableAt(fp, src); |
| 249 } else { |
| 250 if (pool == NULL) { |
| 251 pool = &ObjectPool::Handle(code_->object_pool()); |
| 252 } |
| 253 RawObject* obj = pool->ObjectAt(src); |
| 254 *VariableAt(fp, dest) = obj; |
175 } | 255 } |
176 } // if frame->IsDartFrame | 256 } |
177 frame = frames.NextFrame(); | 257 } |
178 ASSERT(frame != NULL); | 258 |
179 } // while !frame->IsEntryFrame | 259 #if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) |
180 ASSERT(frame->IsEntryFrame()); | 260 void ReadCompressedMetaData() { |
181 if (!handler_pc_set) { | 261 intptr_t pc_offset = pc_ - code_->PayloadStart(); |
182 *handler_pc = frame->pc(); | 262 const TypedData& td = TypedData::Handle(code_->catch_entry_state_maps()); |
183 *handler_sp = frame->sp(); | 263 NoSafepointScope no_safepoint; |
184 *handler_fp = frame->fp(); | 264 ReadStream stream(static_cast<uint8_t*>(td.DataAddr(0)), td.Length()); |
185 } | 265 |
186 // No catch-all encountered, needs stacktrace. | 266 bool found_metadata = false; |
187 *needs_stacktrace = true; | 267 while (stream.PendingBytes() > 0) { |
188 return handler_pc_set; | 268 intptr_t target_pc_offset = Reader::Read(&stream); |
189 } | 269 intptr_t variables = Reader::Read(&stream); |
| 270 intptr_t suffix_length = Reader::Read(&stream); |
| 271 intptr_t suffix_offset = Reader::Read(&stream); |
| 272 if (pc_offset == target_pc_offset) { |
| 273 metadata_ = new intptr_t[2 * (variables + suffix_length) + 1]; |
| 274 metadata_[0] = variables + suffix_length; |
| 275 for (int j = 0; j < variables; j++) { |
| 276 intptr_t src = Reader::Read(&stream); |
| 277 intptr_t dest = Reader::Read(&stream); |
| 278 metadata_[1 + 2 * j] = src; |
| 279 metadata_[2 + 2 * j] = dest; |
| 280 } |
| 281 ReadCompressedSuffix(&stream, suffix_offset, suffix_length, metadata_, |
| 282 2 * variables + 1); |
| 283 found_metadata = true; |
| 284 break; |
| 285 } else { |
| 286 for (intptr_t j = 0; j < 2 * variables; j++) { |
| 287 Reader::Read(&stream); |
| 288 } |
| 289 } |
| 290 } |
| 291 ASSERT(found_metadata); |
| 292 } |
| 293 |
| 294 void ReadCompressedSuffix(ReadStream* stream, |
| 295 intptr_t offset, |
| 296 intptr_t length, |
| 297 intptr_t* target, |
| 298 intptr_t target_offset) { |
| 299 stream->SetPosition(offset); |
| 300 Reader::Read(stream); // skip pc_offset |
| 301 Reader::Read(stream); // skip variables |
| 302 intptr_t suffix_length = Reader::Read(stream); |
| 303 intptr_t suffix_offset = Reader::Read(stream); |
| 304 intptr_t to_read = length - suffix_length; |
| 305 for (int j = 0; j < to_read; j++) { |
| 306 target[target_offset + 2 * j] = Reader::Read(stream); |
| 307 target[target_offset + 2 * j + 1] = Reader::Read(stream); |
| 308 } |
| 309 if (suffix_length > 0) { |
| 310 ReadCompressedSuffix(stream, suffix_offset, suffix_length, target, |
| 311 target_offset + to_read * 2); |
| 312 } |
| 313 } |
| 314 |
| 315 #else |
| 316 void GetMetaDataFromDeopt(intptr_t num_vars, StackFrame* frame) { |
| 317 Isolate* isolate = thread_->isolate(); |
| 318 DeoptContext* deopt_context = |
| 319 new DeoptContext(frame, *code_, DeoptContext::kDestIsAllocated, NULL, |
| 320 NULL, true, false /* deoptimizing_code */); |
| 321 isolate->set_deopt_context(deopt_context); |
| 322 |
| 323 metadata_ = deopt_context->CatchEntryState(num_vars); |
| 324 |
| 325 isolate->set_deopt_context(NULL); |
| 326 delete deopt_context; |
| 327 } |
| 328 #endif // defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) |
| 329 |
| 330 bool needs_stacktrace; |
| 331 uword handler_pc; |
| 332 uword handler_sp; |
| 333 uword handler_fp; |
| 334 |
| 335 private: |
| 336 typedef ReadStream::Raw<sizeof(intptr_t), intptr_t> Reader; |
| 337 Thread* thread_; |
| 338 CatchEntryStateCache* cache_; |
| 339 Code* code_; |
| 340 bool handler_pc_set_; |
| 341 intptr_t* metadata_; // MetaData generated from deopt. |
| 342 CatchEntryState cached_; // Value of per PC MetaData cache. |
| 343 intptr_t pc_; // Current pc in the handler frame. |
| 344 }; |
190 | 345 |
191 | 346 |
192 static void FindErrorHandler(uword* handler_pc, | 347 static void FindErrorHandler(uword* handler_pc, |
193 uword* handler_sp, | 348 uword* handler_sp, |
194 uword* handler_fp) { | 349 uword* handler_fp) { |
195 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); | 350 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); |
196 StackFrame* frame = frames.NextFrame(); | 351 StackFrame* frame = frames.NextFrame(); |
197 ASSERT(frame != NULL); | 352 ASSERT(frame != NULL); |
198 while (!frame->IsEntryFrame()) { | 353 while (!frame->IsEntryFrame()) { |
199 frame = frames.NextFrame(); | 354 frame = frames.NextFrame(); |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 Isolate* isolate = thread->isolate(); | 539 Isolate* isolate = thread->isolate(); |
385 bool use_preallocated_stacktrace = false; | 540 bool use_preallocated_stacktrace = false; |
386 Instance& exception = Instance::Handle(zone, incoming_exception.raw()); | 541 Instance& exception = Instance::Handle(zone, incoming_exception.raw()); |
387 if (exception.IsNull()) { | 542 if (exception.IsNull()) { |
388 exception ^= | 543 exception ^= |
389 Exceptions::Create(Exceptions::kNullThrown, Object::empty_array()); | 544 Exceptions::Create(Exceptions::kNullThrown, Object::empty_array()); |
390 } else if (exception.raw() == isolate->object_store()->out_of_memory() || | 545 } else if (exception.raw() == isolate->object_store()->out_of_memory() || |
391 exception.raw() == isolate->object_store()->stack_overflow()) { | 546 exception.raw() == isolate->object_store()->stack_overflow()) { |
392 use_preallocated_stacktrace = true; | 547 use_preallocated_stacktrace = true; |
393 } | 548 } |
394 uword handler_pc = 0; | |
395 uword handler_sp = 0; | |
396 uword handler_fp = 0; | |
397 Instance& stacktrace = Instance::Handle(zone); | |
398 bool handler_exists = false; | |
399 bool handler_needs_stacktrace = false; | |
400 // Find the exception handler and determine if the handler needs a | 549 // Find the exception handler and determine if the handler needs a |
401 // stacktrace. | 550 // stacktrace. |
402 handler_exists = FindExceptionHandler(thread, &handler_pc, &handler_sp, | 551 ExceptionHandlerFinder finder(thread); |
403 &handler_fp, &handler_needs_stacktrace); | 552 bool handler_exists = finder.Find(); |
| 553 uword handler_pc = finder.handler_pc; |
| 554 uword handler_sp = finder.handler_sp; |
| 555 uword handler_fp = finder.handler_fp; |
| 556 bool handler_needs_stacktrace = finder.needs_stacktrace; |
| 557 Instance& stacktrace = Instance::Handle(zone); |
404 if (use_preallocated_stacktrace) { | 558 if (use_preallocated_stacktrace) { |
405 if (handler_pc == 0) { | 559 if (handler_pc == 0) { |
406 // No Dart frame. | 560 // No Dart frame. |
407 ASSERT(incoming_exception.raw() == | 561 ASSERT(incoming_exception.raw() == |
408 isolate->object_store()->out_of_memory()); | 562 isolate->object_store()->out_of_memory()); |
409 const UnhandledException& error = UnhandledException::Handle( | 563 const UnhandledException& error = UnhandledException::Handle( |
410 zone, isolate->object_store()->preallocated_unhandled_exception()); | 564 zone, isolate->object_store()->preallocated_unhandled_exception()); |
411 thread->long_jump_base()->Jump(1, error); | 565 thread->long_jump_base()->Jump(1, error); |
412 UNREACHABLE(); | 566 UNREACHABLE(); |
413 } | 567 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
448 // then we expect to at least have the dart entry frame on the | 602 // then we expect to at least have the dart entry frame on the |
449 // stack as Exceptions::Throw should happen only after a dart | 603 // stack as Exceptions::Throw should happen only after a dart |
450 // invocation has been done. | 604 // invocation has been done. |
451 ASSERT(handler_pc != 0); | 605 ASSERT(handler_pc != 0); |
452 | 606 |
453 if (FLAG_print_stacktrace_at_throw) { | 607 if (FLAG_print_stacktrace_at_throw) { |
454 THR_Print("Exception '%s' thrown:\n", exception.ToCString()); | 608 THR_Print("Exception '%s' thrown:\n", exception.ToCString()); |
455 THR_Print("%s\n", stacktrace.ToCString()); | 609 THR_Print("%s\n", stacktrace.ToCString()); |
456 } | 610 } |
457 if (handler_exists) { | 611 if (handler_exists) { |
| 612 finder.TrySync(); |
458 // Found a dart handler for the exception, jump to it. | 613 // Found a dart handler for the exception, jump to it. |
459 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, | 614 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, |
460 exception, stacktrace); | 615 exception, stacktrace); |
461 } else { | 616 } else { |
462 // No dart exception handler found in this invocation sequence, | 617 // No dart exception handler found in this invocation sequence, |
463 // so we create an unhandled exception object and return to the | 618 // so we create an unhandled exception object and return to the |
464 // invocation stub so that it returns this unhandled exception | 619 // invocation stub so that it returns this unhandled exception |
465 // object. The C++ code which invoked this dart sequence can check | 620 // object. The C++ code which invoked this dart sequence can check |
466 // and do the appropriate thing (rethrow the exception to the | 621 // and do the appropriate thing (rethrow the exception to the |
467 // dart invocation sequence above it, print diagnostics and terminate | 622 // dart invocation sequence above it, print diagnostics and terminate |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
817 class_name = &Symbols::_CompileTimeError(); | 972 class_name = &Symbols::_CompileTimeError(); |
818 break; | 973 break; |
819 } | 974 } |
820 | 975 |
821 return DartLibraryCalls::InstanceCreate(library, *class_name, | 976 return DartLibraryCalls::InstanceCreate(library, *class_name, |
822 *constructor_name, arguments); | 977 *constructor_name, arguments); |
823 } | 978 } |
824 | 979 |
825 | 980 |
826 } // namespace dart | 981 } // namespace dart |
OLD | NEW |