| 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 19 matching lines...) Expand all Loading... |
| 30 public: | 30 public: |
| 31 StacktraceBuilder() { } | 31 StacktraceBuilder() { } |
| 32 virtual ~StacktraceBuilder() { } | 32 virtual ~StacktraceBuilder() { } |
| 33 | 33 |
| 34 virtual void AddFrame(const Code& code, const Smi& offset) = 0; | 34 virtual void AddFrame(const Code& code, const Smi& offset) = 0; |
| 35 }; | 35 }; |
| 36 | 36 |
| 37 | 37 |
| 38 class RegularStacktraceBuilder : public StacktraceBuilder { | 38 class RegularStacktraceBuilder : public StacktraceBuilder { |
| 39 public: | 39 public: |
| 40 explicit RegularStacktraceBuilder(Isolate* isolate) | 40 explicit RegularStacktraceBuilder(Zone* zone) |
| 41 : code_list_( | 41 : code_list_( |
| 42 GrowableObjectArray::Handle(isolate, GrowableObjectArray::New())), | 42 GrowableObjectArray::Handle(zone, GrowableObjectArray::New())), |
| 43 pc_offset_list_( | 43 pc_offset_list_( |
| 44 GrowableObjectArray::Handle(isolate, GrowableObjectArray::New())) { } | 44 GrowableObjectArray::Handle(zone, GrowableObjectArray::New())) { } |
| 45 ~RegularStacktraceBuilder() { } | 45 ~RegularStacktraceBuilder() { } |
| 46 | 46 |
| 47 const GrowableObjectArray& code_list() const { return code_list_; } | 47 const GrowableObjectArray& code_list() const { return code_list_; } |
| 48 const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; } | 48 const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; } |
| 49 | 49 |
| 50 virtual void AddFrame(const Code& code, const Smi& offset) { | 50 virtual void AddFrame(const Code& code, const Smi& offset) { |
| 51 code_list_.Add(code); | 51 code_list_.Add(code); |
| 52 pc_offset_list_.Add(offset); | 52 pc_offset_list_.Add(offset); |
| 53 } | 53 } |
| 54 | 54 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 stacktrace_.SetPcOffsetAtFrame(prev, frame_offset); | 104 stacktrace_.SetPcOffsetAtFrame(prev, frame_offset); |
| 105 } | 105 } |
| 106 cur_index_ = (Stacktrace::kPreallocatedStackdepth - 1); | 106 cur_index_ = (Stacktrace::kPreallocatedStackdepth - 1); |
| 107 } | 107 } |
| 108 stacktrace_.SetCodeAtFrame(cur_index_, code); | 108 stacktrace_.SetCodeAtFrame(cur_index_, code); |
| 109 stacktrace_.SetPcOffsetAtFrame(cur_index_, offset); | 109 stacktrace_.SetPcOffsetAtFrame(cur_index_, offset); |
| 110 cur_index_ += 1; | 110 cur_index_ += 1; |
| 111 } | 111 } |
| 112 | 112 |
| 113 | 113 |
| 114 static void BuildStackTrace(Isolate* isolate, StacktraceBuilder* builder) { | 114 static void BuildStackTrace(StacktraceBuilder* builder) { |
| 115 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); | 115 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); |
| 116 StackFrame* frame = frames.NextFrame(); | 116 StackFrame* frame = frames.NextFrame(); |
| 117 ASSERT(frame != NULL); // We expect to find a dart invocation frame. | 117 ASSERT(frame != NULL); // We expect to find a dart invocation frame. |
| 118 Code& code = Code::Handle(); | 118 Code& code = Code::Handle(); |
| 119 Smi& offset = Smi::Handle(); | 119 Smi& offset = Smi::Handle(); |
| 120 while (frame != NULL) { | 120 while (frame != NULL) { |
| 121 if (frame->IsDartFrame()) { | 121 if (frame->IsDartFrame()) { |
| 122 code = frame->LookupDartCode(); | 122 code = frame->LookupDartCode(); |
| 123 offset = Smi::New(frame->pc() - code.EntryPoint()); | 123 offset = Smi::New(frame->pc() - code.EntryPoint()); |
| 124 builder->AddFrame(code, offset); | 124 builder->AddFrame(code, offset); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 #endif | 240 #endif |
| 241 UNREACHABLE(); | 241 UNREACHABLE(); |
| 242 } | 242 } |
| 243 | 243 |
| 244 | 244 |
| 245 static RawField* LookupStacktraceField(const Instance& instance) { | 245 static RawField* LookupStacktraceField(const Instance& instance) { |
| 246 if (instance.GetClassId() < kNumPredefinedCids) { | 246 if (instance.GetClassId() < kNumPredefinedCids) { |
| 247 // 'class Error' is not a predefined class. | 247 // 'class Error' is not a predefined class. |
| 248 return Field::null(); | 248 return Field::null(); |
| 249 } | 249 } |
| 250 Isolate* isolate = Isolate::Current(); | 250 Thread* thread = Thread::Current(); |
| 251 Class& error_class = Class::Handle(isolate, | 251 Zone* zone = thread->zone(); |
| 252 Isolate* isolate = thread->isolate(); |
| 253 Class& error_class = Class::Handle(zone, |
| 252 isolate->object_store()->error_class()); | 254 isolate->object_store()->error_class()); |
| 253 if (error_class.IsNull()) { | 255 if (error_class.IsNull()) { |
| 254 const Library& core_lib = Library::Handle(isolate, Library::CoreLibrary()); | 256 const Library& core_lib = Library::Handle(zone, Library::CoreLibrary()); |
| 255 error_class = core_lib.LookupClass(Symbols::Error()); | 257 error_class = core_lib.LookupClass(Symbols::Error()); |
| 256 ASSERT(!error_class.IsNull()); | 258 ASSERT(!error_class.IsNull()); |
| 257 isolate->object_store()->set_error_class(error_class); | 259 isolate->object_store()->set_error_class(error_class); |
| 258 } | 260 } |
| 259 // If instance class extends 'class Error' return '_stackTrace' field. | 261 // If instance class extends 'class Error' return '_stackTrace' field. |
| 260 Class& test_class = Class::Handle(isolate, instance.clazz()); | 262 Class& test_class = Class::Handle(zone, instance.clazz()); |
| 261 AbstractType& type = AbstractType::Handle(isolate, AbstractType::null()); | 263 AbstractType& type = AbstractType::Handle(zone, AbstractType::null()); |
| 262 while (true) { | 264 while (true) { |
| 263 if (test_class.raw() == error_class.raw()) { | 265 if (test_class.raw() == error_class.raw()) { |
| 264 return error_class.LookupInstanceField(Symbols::_stackTrace()); | 266 return error_class.LookupInstanceField(Symbols::_stackTrace()); |
| 265 } | 267 } |
| 266 type = test_class.super_type(); | 268 type = test_class.super_type(); |
| 267 if (type.IsNull()) return Field::null(); | 269 if (type.IsNull()) return Field::null(); |
| 268 test_class = type.type_class(); | 270 test_class = type.type_class(); |
| 269 } | 271 } |
| 270 UNREACHABLE(); | 272 UNREACHABLE(); |
| 271 return Field::null(); | 273 return Field::null(); |
| 272 } | 274 } |
| 273 | 275 |
| 274 | 276 |
| 275 RawStacktrace* Exceptions::CurrentStacktrace() { | 277 RawStacktrace* Exceptions::CurrentStacktrace() { |
| 276 Isolate* isolate = Isolate::Current(); | 278 Zone* zone = Thread::Current()->zone(); |
| 277 RegularStacktraceBuilder frame_builder(isolate); | 279 RegularStacktraceBuilder frame_builder(zone); |
| 278 BuildStackTrace(isolate, &frame_builder); | 280 BuildStackTrace(&frame_builder); |
| 279 | 281 |
| 280 // Create arrays for code and pc_offset tuples of each frame. | 282 // Create arrays for code and pc_offset tuples of each frame. |
| 281 const Array& full_code_array = Array::Handle(isolate, | 283 const Array& full_code_array = Array::Handle(zone, |
| 282 Array::MakeArray(frame_builder.code_list())); | 284 Array::MakeArray(frame_builder.code_list())); |
| 283 const Array& full_pc_offset_array = Array::Handle(isolate, | 285 const Array& full_pc_offset_array = Array::Handle(zone, |
| 284 Array::MakeArray(frame_builder.pc_offset_list())); | 286 Array::MakeArray(frame_builder.pc_offset_list())); |
| 285 const Stacktrace& full_stacktrace = Stacktrace::Handle( | 287 const Stacktrace& full_stacktrace = Stacktrace::Handle( |
| 286 Stacktrace::New(full_code_array, full_pc_offset_array)); | 288 Stacktrace::New(full_code_array, full_pc_offset_array)); |
| 287 return full_stacktrace.raw(); | 289 return full_stacktrace.raw(); |
| 288 } | 290 } |
| 289 | 291 |
| 290 | 292 |
| 291 static void ThrowExceptionHelper(Thread* thread, | 293 static void ThrowExceptionHelper(Thread* thread, |
| 292 const Instance& incoming_exception, | 294 const Instance& incoming_exception, |
| 293 const Instance& existing_stacktrace, | 295 const Instance& existing_stacktrace, |
| 294 const bool is_rethrow) { | 296 const bool is_rethrow) { |
| 297 Zone* zone = thread->zone(); |
| 295 Isolate* isolate = thread->isolate(); | 298 Isolate* isolate = thread->isolate(); |
| 296 bool use_preallocated_stacktrace = false; | 299 bool use_preallocated_stacktrace = false; |
| 297 Instance& exception = Instance::Handle(isolate, incoming_exception.raw()); | 300 Instance& exception = Instance::Handle(zone, incoming_exception.raw()); |
| 298 if (exception.IsNull()) { | 301 if (exception.IsNull()) { |
| 299 exception ^= Exceptions::Create(Exceptions::kNullThrown, | 302 exception ^= Exceptions::Create(Exceptions::kNullThrown, |
| 300 Object::empty_array()); | 303 Object::empty_array()); |
| 301 } else if (exception.raw() == isolate->object_store()->out_of_memory() || | 304 } else if (exception.raw() == isolate->object_store()->out_of_memory() || |
| 302 exception.raw() == isolate->object_store()->stack_overflow()) { | 305 exception.raw() == isolate->object_store()->stack_overflow()) { |
| 303 use_preallocated_stacktrace = true; | 306 use_preallocated_stacktrace = true; |
| 304 } | 307 } |
| 305 uword handler_pc = 0; | 308 uword handler_pc = 0; |
| 306 uword handler_sp = 0; | 309 uword handler_sp = 0; |
| 307 uword handler_fp = 0; | 310 uword handler_fp = 0; |
| 308 Instance& stacktrace = Instance::Handle(isolate); | 311 Instance& stacktrace = Instance::Handle(zone); |
| 309 bool handler_exists = false; | 312 bool handler_exists = false; |
| 310 bool handler_needs_stacktrace = false; | 313 bool handler_needs_stacktrace = false; |
| 311 if (use_preallocated_stacktrace) { | 314 if (use_preallocated_stacktrace) { |
| 312 stacktrace ^= isolate->object_store()->preallocated_stack_trace(); | 315 stacktrace ^= isolate->object_store()->preallocated_stack_trace(); |
| 313 PreallocatedStacktraceBuilder frame_builder(stacktrace); | 316 PreallocatedStacktraceBuilder frame_builder(stacktrace); |
| 314 handler_exists = FindExceptionHandler(thread, | 317 handler_exists = FindExceptionHandler(thread, |
| 315 &handler_pc, | 318 &handler_pc, |
| 316 &handler_sp, | 319 &handler_sp, |
| 317 &handler_fp, | 320 &handler_fp, |
| 318 &handler_needs_stacktrace); | 321 &handler_needs_stacktrace); |
| 319 if (handler_needs_stacktrace) { | 322 if (handler_needs_stacktrace) { |
| 320 BuildStackTrace(isolate, &frame_builder); | 323 BuildStackTrace(&frame_builder); |
| 321 } | 324 } |
| 322 } else { | 325 } else { |
| 323 // Get stacktrace field of class Error. This is needed to determine whether | 326 // Get stacktrace field of class Error. This is needed to determine whether |
| 324 // we have a subclass of Error which carries around its stack trace. | 327 // we have a subclass of Error which carries around its stack trace. |
| 325 const Field& stacktrace_field = | 328 const Field& stacktrace_field = |
| 326 Field::Handle(isolate, LookupStacktraceField(exception)); | 329 Field::Handle(zone, LookupStacktraceField(exception)); |
| 327 | 330 |
| 328 // Find the exception handler and determine if the handler needs a | 331 // Find the exception handler and determine if the handler needs a |
| 329 // stacktrace. | 332 // stacktrace. |
| 330 handler_exists = FindExceptionHandler(thread, | 333 handler_exists = FindExceptionHandler(thread, |
| 331 &handler_pc, | 334 &handler_pc, |
| 332 &handler_sp, | 335 &handler_sp, |
| 333 &handler_fp, | 336 &handler_fp, |
| 334 &handler_needs_stacktrace); | 337 &handler_needs_stacktrace); |
| 335 if (!existing_stacktrace.IsNull()) { | 338 if (!existing_stacktrace.IsNull()) { |
| 336 // If we have an existing stack trace then this better be a rethrow. The | 339 // If we have an existing stack trace then this better be a rethrow. The |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 stacktrace); | 375 stacktrace); |
| 373 } else { | 376 } else { |
| 374 // No dart exception handler found in this invocation sequence, | 377 // No dart exception handler found in this invocation sequence, |
| 375 // so we create an unhandled exception object and return to the | 378 // so we create an unhandled exception object and return to the |
| 376 // invocation stub so that it returns this unhandled exception | 379 // invocation stub so that it returns this unhandled exception |
| 377 // object. The C++ code which invoked this dart sequence can check | 380 // object. The C++ code which invoked this dart sequence can check |
| 378 // and do the appropriate thing (rethrow the exception to the | 381 // and do the appropriate thing (rethrow the exception to the |
| 379 // dart invocation sequence above it, print diagnostics and terminate | 382 // dart invocation sequence above it, print diagnostics and terminate |
| 380 // the isolate etc.). | 383 // the isolate etc.). |
| 381 const UnhandledException& unhandled_exception = UnhandledException::Handle( | 384 const UnhandledException& unhandled_exception = UnhandledException::Handle( |
| 382 isolate, UnhandledException::New(exception, stacktrace)); | 385 zone, UnhandledException::New(exception, stacktrace)); |
| 383 stacktrace = Stacktrace::null(); | 386 stacktrace = Stacktrace::null(); |
| 384 JumpToExceptionHandler(thread, | 387 JumpToExceptionHandler(thread, |
| 385 handler_pc, | 388 handler_pc, |
| 386 handler_sp, | 389 handler_sp, |
| 387 handler_fp, | 390 handler_fp, |
| 388 unhandled_exception, | 391 unhandled_exception, |
| 389 stacktrace); | 392 stacktrace); |
| 390 } | 393 } |
| 391 UNREACHABLE(); | 394 UNREACHABLE(); |
| 392 } | 395 } |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 void Exceptions::Throw(Thread* thread, const Instance& exception) { | 481 void Exceptions::Throw(Thread* thread, const Instance& exception) { |
| 479 // Do not notify debugger on stack overflow and out of memory exceptions. | 482 // Do not notify debugger on stack overflow and out of memory exceptions. |
| 480 // The VM would crash when the debugger calls back into the VM to | 483 // The VM would crash when the debugger calls back into the VM to |
| 481 // get values of variables. | 484 // get values of variables. |
| 482 Isolate* isolate = thread->isolate(); | 485 Isolate* isolate = thread->isolate(); |
| 483 if (exception.raw() != isolate->object_store()->out_of_memory() && | 486 if (exception.raw() != isolate->object_store()->out_of_memory() && |
| 484 exception.raw() != isolate->object_store()->stack_overflow()) { | 487 exception.raw() != isolate->object_store()->stack_overflow()) { |
| 485 isolate->debugger()->SignalExceptionThrown(exception); | 488 isolate->debugger()->SignalExceptionThrown(exception); |
| 486 } | 489 } |
| 487 // Null object is a valid exception object. | 490 // Null object is a valid exception object. |
| 488 ThrowExceptionHelper(thread, exception, Stacktrace::Handle(isolate), false); | 491 ThrowExceptionHelper(thread, exception, |
| 492 Stacktrace::Handle(thread->zone()), false); |
| 489 } | 493 } |
| 490 | 494 |
| 491 void Exceptions::ReThrow(Thread* thread, | 495 void Exceptions::ReThrow(Thread* thread, |
| 492 const Instance& exception, | 496 const Instance& exception, |
| 493 const Instance& stacktrace) { | 497 const Instance& stacktrace) { |
| 494 // Null object is a valid exception object. | 498 // Null object is a valid exception object. |
| 495 ThrowExceptionHelper(thread, exception, stacktrace, true); | 499 ThrowExceptionHelper(thread, exception, stacktrace, true); |
| 496 } | 500 } |
| 497 | 501 |
| 498 | 502 |
| 499 void Exceptions::PropagateError(const Error& error) { | 503 void Exceptions::PropagateError(const Error& error) { |
| 500 Thread* thread = Thread::Current(); | 504 Thread* thread = Thread::Current(); |
| 501 Isolate* isolate = thread->isolate(); | 505 Isolate* isolate = thread->isolate(); |
| 506 Zone* zone = thread->zone(); |
| 502 ASSERT(isolate->top_exit_frame_info() != 0); | 507 ASSERT(isolate->top_exit_frame_info() != 0); |
| 503 if (error.IsUnhandledException()) { | 508 if (error.IsUnhandledException()) { |
| 504 // If the error object represents an unhandled exception, then | 509 // If the error object represents an unhandled exception, then |
| 505 // rethrow the exception in the normal fashion. | 510 // rethrow the exception in the normal fashion. |
| 506 const UnhandledException& uhe = UnhandledException::Cast(error); | 511 const UnhandledException& uhe = UnhandledException::Cast(error); |
| 507 const Instance& exc = Instance::Handle(isolate, uhe.exception()); | 512 const Instance& exc = Instance::Handle(zone, uhe.exception()); |
| 508 const Instance& stk = Instance::Handle(isolate, uhe.stacktrace()); | 513 const Instance& stk = Instance::Handle(zone, uhe.stacktrace()); |
| 509 Exceptions::ReThrow(thread, exc, stk); | 514 Exceptions::ReThrow(thread, exc, stk); |
| 510 } else { | 515 } else { |
| 511 // Return to the invocation stub and return this error object. The | 516 // Return to the invocation stub and return this error object. The |
| 512 // C++ code which invoked this dart sequence can check and do the | 517 // C++ code which invoked this dart sequence can check and do the |
| 513 // appropriate thing. | 518 // appropriate thing. |
| 514 uword handler_pc = 0; | 519 uword handler_pc = 0; |
| 515 uword handler_sp = 0; | 520 uword handler_sp = 0; |
| 516 uword handler_fp = 0; | 521 uword handler_fp = 0; |
| 517 FindErrorHandler(&handler_pc, &handler_sp, &handler_fp); | 522 FindErrorHandler(&handler_pc, &handler_sp, &handler_fp); |
| 518 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, error, | 523 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, error, |
| 519 Stacktrace::Handle(isolate)); // Null stacktrace. | 524 Stacktrace::Handle(zone)); // Null stacktrace. |
| 520 } | 525 } |
| 521 UNREACHABLE(); | 526 UNREACHABLE(); |
| 522 } | 527 } |
| 523 | 528 |
| 524 | 529 |
| 525 void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) { | 530 void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) { |
| 526 Thread* thread = Thread::Current(); | 531 Thread* thread = Thread::Current(); |
| 527 Isolate* isolate = thread->isolate(); | 532 const Object& result = |
| 528 const Object& result = Object::Handle(isolate, Create(type, arguments)); | 533 Object::Handle(thread->zone(), Create(type, arguments)); |
| 529 if (result.IsError()) { | 534 if (result.IsError()) { |
| 530 // We got an error while constructing the exception object. | 535 // We got an error while constructing the exception object. |
| 531 // Propagate the error instead of throwing the exception. | 536 // Propagate the error instead of throwing the exception. |
| 532 PropagateError(Error::Cast(result)); | 537 PropagateError(Error::Cast(result)); |
| 533 } else { | 538 } else { |
| 534 ASSERT(result.IsInstance()); | 539 ASSERT(result.IsInstance()); |
| 535 Throw(thread, Instance::Cast(result)); | 540 Throw(thread, Instance::Cast(result)); |
| 536 } | 541 } |
| 537 } | 542 } |
| 538 | 543 |
| 539 | 544 |
| 540 void Exceptions::ThrowOOM() { | 545 void Exceptions::ThrowOOM() { |
| 541 Thread* thread = Thread::Current(); | 546 Thread* thread = Thread::Current(); |
| 542 Isolate* isolate = thread->isolate(); | 547 Isolate* isolate = thread->isolate(); |
| 543 const Instance& oom = Instance::Handle( | 548 const Instance& oom = Instance::Handle( |
| 544 isolate, isolate->object_store()->out_of_memory()); | 549 thread->zone(), isolate->object_store()->out_of_memory()); |
| 545 Throw(thread, oom); | 550 Throw(thread, oom); |
| 546 } | 551 } |
| 547 | 552 |
| 548 | 553 |
| 549 void Exceptions::ThrowStackOverflow() { | 554 void Exceptions::ThrowStackOverflow() { |
| 550 Thread* thread = Thread::Current(); | 555 Thread* thread = Thread::Current(); |
| 551 Isolate* isolate = thread->isolate(); | 556 Isolate* isolate = thread->isolate(); |
| 552 const Instance& stack_overflow = Instance::Handle( | 557 const Instance& stack_overflow = Instance::Handle( |
| 553 isolate, isolate->object_store()->stack_overflow()); | 558 thread->zone(), isolate->object_store()->stack_overflow()); |
| 554 Throw(thread, stack_overflow); | 559 Throw(thread, stack_overflow); |
| 555 } | 560 } |
| 556 | 561 |
| 557 | 562 |
| 558 void Exceptions::ThrowArgumentError(const Instance& arg) { | 563 void Exceptions::ThrowArgumentError(const Instance& arg) { |
| 559 const Array& args = Array::Handle(Array::New(1)); | 564 const Array& args = Array::Handle(Array::New(1)); |
| 560 args.SetAt(0, arg); | 565 args.SetAt(0, arg); |
| 561 Exceptions::ThrowByType(Exceptions::kArgument, args); | 566 Exceptions::ThrowByType(Exceptions::kArgument, args); |
| 562 } | 567 } |
| 563 | 568 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 671 | 676 |
| 672 // Throw JavascriptCompatibilityError exception. | 677 // Throw JavascriptCompatibilityError exception. |
| 673 void Exceptions::ThrowJavascriptCompatibilityError(const char* msg) { | 678 void Exceptions::ThrowJavascriptCompatibilityError(const char* msg) { |
| 674 const Array& exc_args = Array::Handle(Array::New(1)); | 679 const Array& exc_args = Array::Handle(Array::New(1)); |
| 675 const String& msg_str = String::Handle(String::New(msg)); | 680 const String& msg_str = String::Handle(String::New(msg)); |
| 676 exc_args.SetAt(0, msg_str); | 681 exc_args.SetAt(0, msg_str); |
| 677 Exceptions::ThrowByType(Exceptions::kJavascriptCompatibilityError, exc_args); | 682 Exceptions::ThrowByType(Exceptions::kJavascriptCompatibilityError, exc_args); |
| 678 } | 683 } |
| 679 | 684 |
| 680 } // namespace dart | 685 } // namespace dart |
| OLD | NEW |