| // 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(obj1, 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; | |
| } | |
| @pragma('vm:entry-point', 'call') | |
| 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)); | |
| } | |
| )"; | |
| SetFlagScope<bool> sfs(&FLAG_verify_entry_points, false); | |
| Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, native_lookup); | |
| EXPECT_VALID(Dart_Invoke(lib, NewString("testMain"), 0, nullptr)); | |
| } | |
| } // namespace dart |