| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "include/dart_api.h" |
| #include "platform/assert.h" |
| #include "vm/dart_api_impl.h" |
| #include "vm/unit_test.h" |
| |
| namespace dart { |
| |
| #define FUNCTION_NAME(name) UnhandledExcp_##name |
| #define REGISTER_FUNCTION(name, count) {"" #name, FUNCTION_NAME(name), count}, |
| |
| void FUNCTION_NAME(Unhandled_equals)(Dart_NativeArguments args) { |
| NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); |
| TransitionNativeToVM transition(arguments->thread()); |
| Zone* zone = arguments->thread()->zone(); |
| const Instance& expected = |
| Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| const Instance& actual = |
| Instance::CheckedHandle(zone, arguments->NativeArgAt(1)); |
| if (!expected.CanonicalizeEquals(actual)) { |
| OS::PrintErr("expected: '%s' actual: '%s'\n", expected.ToCString(), |
| actual.ToCString()); |
| FATAL("Unhandled_equals fails.\n"); |
| } |
| } |
| |
| void FUNCTION_NAME(Unhandled_invoke)(Dart_NativeArguments args) { |
| // Invoke the specified entry point. |
| Dart_Handle cls = Dart_GetClass(TestCase::lib(), NewString("Second")); |
| Dart_Handle result = Dart_Invoke(cls, NewString("method2"), 0, nullptr); |
| ASSERT(Dart_IsError(result)); |
| ASSERT(Dart_ErrorHasException(result)); |
| return; |
| } |
| |
| void FUNCTION_NAME(Unhandled_invoke2)(Dart_NativeArguments args) { |
| // Invoke the specified entry point. |
| Dart_Handle cls = Dart_GetClass(TestCase::lib(), NewString("Second")); |
| Dart_Handle result = Dart_Invoke(cls, NewString("method2"), 0, nullptr); |
| ASSERT(Dart_IsError(result)); |
| ASSERT(Dart_ErrorHasException(result)); |
| Dart_Handle exception = Dart_ErrorGetException(result); |
| ASSERT(!Dart_IsError(exception)); |
| Dart_ThrowException(exception); |
| UNREACHABLE(); |
| return; |
| } |
| |
| // List all native functions implemented in the vm or core boot strap dart |
| // libraries so that we can resolve the native function to it's entry |
| // point. |
| #define UNHANDLED_NATIVE_LIST(V) \ |
| V(Unhandled_equals, 2) \ |
| V(Unhandled_invoke, 0) \ |
| V(Unhandled_invoke2, 0) |
| |
| static struct NativeEntries { |
| const char* name_; |
| Dart_NativeFunction function_; |
| int argument_count_; |
| } BuiltinEntries[] = {UNHANDLED_NATIVE_LIST(REGISTER_FUNCTION)}; |
| |
| static Dart_NativeFunction native_lookup(Dart_Handle name, |
| int argument_count, |
| bool* auto_setup_scope) { |
| ASSERT(auto_setup_scope != nullptr); |
| *auto_setup_scope = true; |
| TransitionNativeToVM transition(Thread::Current()); |
| const Object& obj = Object::Handle(Api::UnwrapHandle(name)); |
| ASSERT(obj.IsString()); |
| const char* function_name = obj.ToCString(); |
| ASSERT(function_name != nullptr); |
| int num_entries = sizeof(BuiltinEntries) / sizeof(struct NativeEntries); |
| for (int i = 0; i < num_entries; i++) { |
| struct NativeEntries* entry = &(BuiltinEntries[i]); |
| if ((strcmp(function_name, entry->name_) == 0) && |
| (argument_count == entry->argument_count_)) { |
| return reinterpret_cast<Dart_NativeFunction>(entry->function_); |
| } |
| } |
| return nullptr; |
| } |
| |
| // Unit test case to verify unhandled exceptions. |
| TEST_CASE(UnhandledExceptions) { |
| const char* kScriptChars = |
| R"( |
| class UnhandledExceptions { |
| @pragma('vm:external-name', 'Unhandled_equals') |
| external static equals(var obj1, var obj2); |
| |
| @pragma('vm:external-name', 'Unhandled_invoke') |
| external static invoke(); |
| |
| @pragma('vm:external-name', 'Unhandled_invoke2') |
| external static invoke2(); |
| } |
| class Second { |
| Second() { } |
| static int method1(int param) { |
| UnhandledExceptions.invoke(); |
| return 2; |
| } |
| static int method2() { |
| throw new Second(); |
| } |
| static int method3(int param) { |
| try { |
| UnhandledExceptions.invoke2(); |
| } on Second catch (e) { |
| return 3; |
| } |
| return 2; |
| } |
| } |
| testMain() { |
| UnhandledExceptions.equals(2, Second.method1(1)); |
| UnhandledExceptions.equals(3, Second.method3(1)); |
| } |
| )"; |
| Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, native_lookup); |
| EXPECT_VALID(Dart_Invoke(lib, NewString("testMain"), 0, nullptr)); |
| } |
| |
| } // namespace dart |