| 1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 | |
| 5 | #include "include/dart_api.h" |
| 6 | #include "platform/assert.h" |
| 7 | #include "vm/dart_api_impl.h" |
| 8 | #include "vm/unit_test.h" |
| 9 | |
| 10 | namespace dart { |
| 11 | |
| 12 | #define FUNCTION_NAME(name) UnhandledExcp_##name |
| 13 | #define REGISTER_FUNCTION(name, count) {"" #name, FUNCTION_NAME(name), count}, |
| 14 | |
| 15 | void FUNCTION_NAME(Unhandled_equals)(Dart_NativeArguments args) { |
| 16 | NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); |
| 17 | TransitionNativeToVM transition(arguments->thread()); |
| 18 | Zone* zone = arguments->thread()->zone(); |
| 19 | const Instance& expected = |
| 20 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 21 | const Instance& actual = |
| 22 | Instance::CheckedHandle(zone, arguments->NativeArgAt(1)); |
| 23 | if (!expected.CanonicalizeEquals(actual)) { |
| 24 | OS::PrintErr("expected: '%s' actual: '%s'\n" , expected.ToCString(), |
| 25 | actual.ToCString()); |
| 26 | FATAL("Unhandled_equals fails.\n" ); |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | void FUNCTION_NAME(Unhandled_invoke)(Dart_NativeArguments args) { |
| 31 | // Invoke the specified entry point. |
| 32 | Dart_Handle cls = Dart_GetClass(TestCase::lib(), NewString("Second" )); |
| 33 | Dart_Handle result = Dart_Invoke(cls, NewString("method2" ), 0, NULL); |
| 34 | ASSERT(Dart_IsError(result)); |
| 35 | ASSERT(Dart_ErrorHasException(result)); |
| 36 | return; |
| 37 | } |
| 38 | |
| 39 | void FUNCTION_NAME(Unhandled_invoke2)(Dart_NativeArguments args) { |
| 40 | // Invoke the specified entry point. |
| 41 | Dart_Handle cls = Dart_GetClass(TestCase::lib(), NewString("Second" )); |
| 42 | Dart_Handle result = Dart_Invoke(cls, NewString("method2" ), 0, NULL); |
| 43 | ASSERT(Dart_IsError(result)); |
| 44 | ASSERT(Dart_ErrorHasException(result)); |
| 45 | Dart_Handle exception = Dart_ErrorGetException(result); |
| 46 | ASSERT(!Dart_IsError(exception)); |
| 47 | Dart_ThrowException(exception); |
| 48 | UNREACHABLE(); |
| 49 | return; |
| 50 | } |
| 51 | |
| 52 | // List all native functions implemented in the vm or core boot strap dart |
| 53 | // libraries so that we can resolve the native function to it's entry |
| 54 | // point. |
| 55 | #define UNHANDLED_NATIVE_LIST(V) \ |
| 56 | V(Unhandled_equals, 2) \ |
| 57 | V(Unhandled_invoke, 0) \ |
| 58 | V(Unhandled_invoke2, 0) |
| 59 | |
| 60 | static struct NativeEntries { |
| 61 | const char* name_; |
| 62 | Dart_NativeFunction function_; |
| 63 | int argument_count_; |
| 64 | } BuiltinEntries[] = {UNHANDLED_NATIVE_LIST(REGISTER_FUNCTION)}; |
| 65 | |
| 66 | static Dart_NativeFunction native_lookup(Dart_Handle name, |
| 67 | int argument_count, |
| 68 | bool* auto_setup_scope) { |
| 69 | ASSERT(auto_setup_scope != NULL); |
| 70 | *auto_setup_scope = true; |
| 71 | TransitionNativeToVM transition(Thread::Current()); |
| 72 | const Object& obj = Object::Handle(Api::UnwrapHandle(name)); |
| 73 | ASSERT(obj.IsString()); |
| 74 | const char* function_name = obj.ToCString(); |
| 75 | ASSERT(function_name != NULL); |
| 76 | int num_entries = sizeof(BuiltinEntries) / sizeof(struct NativeEntries); |
| 77 | for (int i = 0; i < num_entries; i++) { |
| 78 | struct NativeEntries* entry = &(BuiltinEntries[i]); |
| 79 | if ((strcmp(function_name, entry->name_) == 0) && |
| 80 | (argument_count == entry->argument_count_)) { |
| 81 | return reinterpret_cast<Dart_NativeFunction>(entry->function_); |
| 82 | } |
| 83 | } |
| 84 | return NULL; |
| 85 | } |
| 86 | |
| 87 | // Unit test case to verify unhandled exceptions. |
| 88 | TEST_CASE(UnhandledExceptions) { |
| 89 | const char* kScriptChars = |
| 90 | "class UnhandledExceptions {\n" |
| 91 | " static equals(var obj1, var obj2) native \"Unhandled_equals\";" |
| 92 | " static invoke() native \"Unhandled_invoke\";\n" |
| 93 | " static invoke2() native \"Unhandled_invoke2\";\n" |
| 94 | "}\n" |
| 95 | "class Second {\n" |
| 96 | " Second() { }\n" |
| 97 | " static int method1(int param) {\n" |
| 98 | " UnhandledExceptions.invoke();\n" |
| 99 | " return 2;\n" |
| 100 | " }\n" |
| 101 | " static int method2() {\n" |
| 102 | " throw new Second();\n" |
| 103 | " }\n" |
| 104 | " static int method3(int param) {\n" |
| 105 | " try {\n" |
| 106 | " UnhandledExceptions.invoke2();\n" |
| 107 | " } on Second catch (e) {\n" |
| 108 | " return 3;\n" |
| 109 | " }\n" |
| 110 | " return 2;\n" |
| 111 | " }\n" |
| 112 | "}\n" |
| 113 | "testMain() {\n" |
| 114 | " UnhandledExceptions.equals(2, Second.method1(1));\n" |
| 115 | " UnhandledExceptions.equals(3, Second.method3(1));\n" |
| 116 | "}" ; |
| 117 | Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, native_lookup); |
| 118 | EXPECT_VALID(Dart_Invoke(lib, NewString("testMain" ), 0, NULL)); |
| 119 | } |
| 120 | |
| 121 | } // namespace dart |
| 122 | |