| 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/native_entry.h" | 5 #include "vm/native_entry.h" |
| 6 | 6 |
| 7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 | 8 |
| 9 #include "vm/bootstrap.h" | 9 #include "vm/bootstrap.h" |
| 10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 ASSERT(!lib.IsNull()); | 84 ASSERT(!lib.IsNull()); |
| 85 const uint8_t* r = ResolveSymbolInLibrary(lib, pc); | 85 const uint8_t* r = ResolveSymbolInLibrary(lib, pc); |
| 86 if (r != NULL) { | 86 if (r != NULL) { |
| 87 return r; | 87 return r; |
| 88 } | 88 } |
| 89 } | 89 } |
| 90 return NULL; | 90 return NULL; |
| 91 } | 91 } |
| 92 | 92 |
| 93 | 93 |
| 94 uword NativeEntry::NativeCallWrapperEntry() { | |
| 95 uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper); | |
| 96 #if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC) | |
| 97 // DBC does not use redirections unlike other simulators. | |
| 98 entry = Simulator::RedirectExternalReference( | |
| 99 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments); | |
| 100 #endif | |
| 101 return entry; | |
| 102 } | |
| 103 | |
| 104 | |
| 105 bool NativeEntry::ReturnValueIsError(NativeArguments* arguments) { | 94 bool NativeEntry::ReturnValueIsError(NativeArguments* arguments) { |
| 106 RawObject* retval = arguments->ReturnValue(); | 95 RawObject* retval = arguments->ReturnValue(); |
| 107 return (retval->IsHeapObject() && | 96 return (retval->IsHeapObject() && |
| 108 RawObject::IsErrorClassId(retval->GetClassId())); | 97 RawObject::IsErrorClassId(retval->GetClassId())); |
| 109 } | 98 } |
| 110 | 99 |
| 111 | 100 |
| 112 void NativeEntry::PropagateErrors(NativeArguments* arguments) { | 101 void NativeEntry::PropagateErrors(NativeArguments* arguments) { |
| 113 Thread* thread = arguments->thread(); | 102 Thread* thread = arguments->thread(); |
| 114 thread->UnwindScopes(thread->top_exit_frame_info()); | 103 thread->UnwindScopes(thread->top_exit_frame_info()); |
| 115 | 104 |
| 116 // The thread->zone() is different here than before we unwound. | 105 // The thread->zone() is different here than before we unwound. |
| 117 const Object& error = | 106 const Object& error = |
| 118 Object::Handle(thread->zone(), arguments->ReturnValue()); | 107 Object::Handle(thread->zone(), arguments->ReturnValue()); |
| 119 Exceptions::PropagateError(Error::Cast(error)); | 108 Exceptions::PropagateError(Error::Cast(error)); |
| 120 UNREACHABLE(); | 109 UNREACHABLE(); |
| 121 } | 110 } |
| 122 | 111 |
| 123 | 112 |
| 124 void NativeEntry::NativeCallWrapper(Dart_NativeArguments args, | 113 uword NativeEntry::NoScopeNativeCallWrapperEntry() { |
| 125 Dart_NativeFunction func) { | 114 uword entry = reinterpret_cast<uword>(NativeEntry::NoScopeNativeCallWrapper); |
| 126 CHECK_STACK_ALIGNMENT; | 115 #if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC) |
| 127 NativeCallWrapperNoStackCheck(args, func); | 116 // DBC does not use redirections unlike other simulators. |
| 117 entry = Simulator::RedirectExternalReference( |
| 118 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments); |
| 119 #endif |
| 120 return entry; |
| 128 } | 121 } |
| 129 | 122 |
| 130 | 123 |
| 131 void NativeEntry::NativeCallWrapperNoStackCheck(Dart_NativeArguments args, | 124 void NativeEntry::NoScopeNativeCallWrapper(Dart_NativeArguments args, |
| 132 Dart_NativeFunction func) { | 125 Dart_NativeFunction func) { |
| 126 CHECK_STACK_ALIGNMENT; |
| 127 NoScopeNativeCallWrapperNoStackCheck(args, func); |
| 128 } |
| 129 |
| 130 |
| 131 void NativeEntry::NoScopeNativeCallWrapperNoStackCheck( |
| 132 Dart_NativeArguments args, |
| 133 Dart_NativeFunction func) { |
| 133 VERIFY_ON_TRANSITION; | 134 VERIFY_ON_TRANSITION; |
| 134 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); | 135 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); |
| 135 /* Tell MemorySanitizer 'arguments' is initialized by generated code. */ | 136 /* Tell MemorySanitizer 'arguments' is initialized by generated code. */ |
| 136 MSAN_UNPOISON(arguments, sizeof(*arguments)); | 137 MSAN_UNPOISON(arguments, sizeof(*arguments)); |
| 137 Thread* thread = arguments->thread(); | 138 Thread* thread = arguments->thread(); |
| 138 ASSERT(thread->execution_state() == Thread::kThreadInGenerated); | 139 ASSERT(thread->execution_state() == Thread::kThreadInGenerated); |
| 139 if (!arguments->IsNativeAutoSetupScope()) { | 140 { |
| 140 TransitionGeneratedToNative transition(thread); | 141 TransitionGeneratedToNative transition(thread); |
| 141 func(args); | 142 func(args); |
| 142 if (ReturnValueIsError(arguments)) { | 143 if (ReturnValueIsError(arguments)) { |
| 143 PropagateErrors(arguments); | 144 PropagateErrors(arguments); |
| 144 } | 145 } |
| 145 } else { | 146 } |
| 147 ASSERT(thread->execution_state() == Thread::kThreadInGenerated); |
| 148 VERIFY_ON_TRANSITION; |
| 149 } |
| 150 |
| 151 |
| 152 uword NativeEntry::AutoScopeNativeCallWrapperEntry() { |
| 153 uword entry = |
| 154 reinterpret_cast<uword>(NativeEntry::AutoScopeNativeCallWrapper); |
| 155 #if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC) |
| 156 // DBC does not use redirections unlike other simulators. |
| 157 entry = Simulator::RedirectExternalReference( |
| 158 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments); |
| 159 #endif |
| 160 return entry; |
| 161 } |
| 162 |
| 163 |
| 164 void NativeEntry::AutoScopeNativeCallWrapper(Dart_NativeArguments args, |
| 165 Dart_NativeFunction func) { |
| 166 CHECK_STACK_ALIGNMENT; |
| 167 AutoScopeNativeCallWrapperNoStackCheck(args, func); |
| 168 } |
| 169 |
| 170 |
| 171 void NativeEntry::AutoScopeNativeCallWrapperNoStackCheck( |
| 172 Dart_NativeArguments args, |
| 173 Dart_NativeFunction func) { |
| 174 VERIFY_ON_TRANSITION; |
| 175 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); |
| 176 /* Tell MemorySanitizer 'arguments' is initialized by generated code. */ |
| 177 MSAN_UNPOISON(arguments, sizeof(*arguments)); |
| 178 Thread* thread = arguments->thread(); |
| 179 ASSERT(thread->execution_state() == Thread::kThreadInGenerated); |
| 180 { |
| 146 Isolate* isolate = thread->isolate(); | 181 Isolate* isolate = thread->isolate(); |
| 147 ApiState* state = isolate->api_state(); | 182 ApiState* state = isolate->api_state(); |
| 148 ASSERT(state != NULL); | 183 ASSERT(state != NULL); |
| 149 ApiLocalScope* current_top_scope = thread->api_top_scope(); | 184 ApiLocalScope* current_top_scope = thread->api_top_scope(); |
| 150 ApiLocalScope* scope = thread->api_reusable_scope(); | 185 ApiLocalScope* scope = thread->api_reusable_scope(); |
| 151 TRACE_NATIVE_CALL("0x%" Px "", reinterpret_cast<uintptr_t>(func)); | 186 TRACE_NATIVE_CALL("0x%" Px "", reinterpret_cast<uintptr_t>(func)); |
| 152 TransitionGeneratedToNative transition(thread); | 187 TransitionGeneratedToNative transition(thread); |
| 153 if (scope == NULL) { | 188 if (scope == NULL) { |
| 154 scope = | 189 scope = |
| 155 new ApiLocalScope(current_top_scope, thread->top_exit_frame_info()); | 190 new ApiLocalScope(current_top_scope, thread->top_exit_frame_info()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 178 } | 213 } |
| 179 ASSERT(thread->execution_state() == Thread::kThreadInGenerated); | 214 ASSERT(thread->execution_state() == Thread::kThreadInGenerated); |
| 180 VERIFY_ON_TRANSITION; | 215 VERIFY_ON_TRANSITION; |
| 181 } | 216 } |
| 182 | 217 |
| 183 | 218 |
| 184 // DBC does not support lazy native call linking. | 219 // DBC does not support lazy native call linking. |
| 185 #if !defined(TARGET_ARCH_DBC) | 220 #if !defined(TARGET_ARCH_DBC) |
| 186 static NativeFunction ResolveNativeFunction(Zone* zone, | 221 static NativeFunction ResolveNativeFunction(Zone* zone, |
| 187 const Function& func, | 222 const Function& func, |
| 188 bool* is_bootstrap_native) { | 223 bool* is_bootstrap_native, |
| 224 bool* is_auto_scope) { |
| 189 const Class& cls = Class::Handle(zone, func.Owner()); | 225 const Class& cls = Class::Handle(zone, func.Owner()); |
| 190 const Library& library = Library::Handle(zone, cls.library()); | 226 const Library& library = Library::Handle(zone, cls.library()); |
| 191 | 227 |
| 192 *is_bootstrap_native = | 228 *is_bootstrap_native = |
| 193 Bootstrap::IsBootstapResolver(library.native_entry_resolver()); | 229 Bootstrap::IsBootstapResolver(library.native_entry_resolver()); |
| 194 | 230 |
| 195 const String& native_name = String::Handle(zone, func.native_name()); | 231 const String& native_name = String::Handle(zone, func.native_name()); |
| 196 ASSERT(!native_name.IsNull()); | 232 ASSERT(!native_name.IsNull()); |
| 197 | 233 |
| 198 const int num_params = NativeArguments::ParameterCountForResolution(func); | 234 const int num_params = NativeArguments::ParameterCountForResolution(func); |
| 199 bool auto_setup_scope = true; | |
| 200 return NativeEntry::ResolveNative(library, native_name, num_params, | 235 return NativeEntry::ResolveNative(library, native_name, num_params, |
| 201 &auto_setup_scope); | 236 is_auto_scope); |
| 202 } | 237 } |
| 203 | 238 |
| 204 | 239 |
| 205 uword NativeEntry::LinkNativeCallEntry() { | 240 uword NativeEntry::LinkNativeCallEntry() { |
| 206 uword entry = reinterpret_cast<uword>(NativeEntry::LinkNativeCall); | 241 uword entry = reinterpret_cast<uword>(NativeEntry::LinkNativeCall); |
| 207 #if defined(USING_SIMULATOR) | 242 #if defined(USING_SIMULATOR) |
| 208 entry = Simulator::RedirectExternalReference( | 243 entry = Simulator::RedirectExternalReference( |
| 209 entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments); | 244 entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments); |
| 210 #endif | 245 #endif |
| 211 return entry; | 246 return entry; |
| 212 } | 247 } |
| 213 | 248 |
| 214 | 249 |
| 215 void NativeEntry::LinkNativeCall(Dart_NativeArguments args) { | 250 void NativeEntry::LinkNativeCall(Dart_NativeArguments args) { |
| 216 CHECK_STACK_ALIGNMENT; | 251 CHECK_STACK_ALIGNMENT; |
| 217 VERIFY_ON_TRANSITION; | 252 VERIFY_ON_TRANSITION; |
| 218 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); | 253 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); |
| 219 /* Tell MemorySanitizer 'arguments' is initialized by generated code. */ | 254 /* Tell MemorySanitizer 'arguments' is initialized by generated code. */ |
| 220 MSAN_UNPOISON(arguments, sizeof(*arguments)); | 255 MSAN_UNPOISON(arguments, sizeof(*arguments)); |
| 221 TRACE_NATIVE_CALL("%s", "LinkNative"); | 256 TRACE_NATIVE_CALL("%s", "LinkNative"); |
| 222 | 257 |
| 223 NativeFunction target_function = NULL; | 258 NativeFunction target_function = NULL; |
| 224 bool call_through_wrapper = false; | 259 bool is_bootstrap_native = false; |
| 260 bool is_auto_scope = true; |
| 225 | 261 |
| 226 { | 262 { |
| 227 TransitionGeneratedToVM transition(arguments->thread()); | 263 TransitionGeneratedToVM transition(arguments->thread()); |
| 228 StackZone zone(arguments->thread()); | 264 StackZone stack_zone(arguments->thread()); |
| 265 Zone* zone = stack_zone.GetZone(); |
| 229 | 266 |
| 230 DartFrameIterator iterator; | 267 DartFrameIterator iterator; |
| 231 StackFrame* caller_frame = iterator.NextFrame(); | 268 StackFrame* caller_frame = iterator.NextFrame(); |
| 232 | 269 |
| 233 const Code& code = Code::Handle(caller_frame->LookupDartCode()); | 270 const Code& code = Code::Handle(zone, caller_frame->LookupDartCode()); |
| 234 const Function& func = Function::Handle(code.function()); | 271 const Function& func = Function::Handle(zone, code.function()); |
| 235 | 272 |
| 236 if (FLAG_trace_natives) { | 273 if (FLAG_trace_natives) { |
| 237 OS::Print("Resolving native target for %s\n", func.ToCString()); | 274 OS::Print("Resolving native target for %s\n", func.ToCString()); |
| 238 } | 275 } |
| 239 | 276 |
| 240 bool is_bootstrap_native = false; | 277 target_function = |
| 241 target_function = ResolveNativeFunction(arguments->thread()->zone(), func, | 278 ResolveNativeFunction(arguments->thread()->zone(), func, |
| 242 &is_bootstrap_native); | 279 &is_bootstrap_native, &is_auto_scope); |
| 243 ASSERT(target_function != NULL); | 280 ASSERT(target_function != NULL); |
| 244 | 281 |
| 245 #if defined(DEBUG) | 282 #if defined(DEBUG) |
| 246 { | 283 { |
| 247 NativeFunction current_function = NULL; | 284 NativeFunction current_function = NULL; |
| 248 const Code& current_trampoline = | 285 const Code& current_trampoline = |
| 249 Code::Handle(CodePatcher::GetNativeCallAt(caller_frame->pc(), code, | 286 Code::Handle(zone, CodePatcher::GetNativeCallAt( |
| 250 ¤t_function)); | 287 caller_frame->pc(), code, ¤t_function)); |
| 251 #if !defined(USING_SIMULATOR) | 288 #if !defined(USING_SIMULATOR) |
| 252 ASSERT(current_function == | 289 ASSERT(current_function == |
| 253 reinterpret_cast<NativeFunction>(LinkNativeCall)); | 290 reinterpret_cast<NativeFunction>(LinkNativeCall)); |
| 254 #else | 291 #else |
| 255 ASSERT( | 292 ASSERT( |
| 256 current_function == | 293 current_function == |
| 257 reinterpret_cast<NativeFunction>(Simulator::RedirectExternalReference( | 294 reinterpret_cast<NativeFunction>(Simulator::RedirectExternalReference( |
| 258 reinterpret_cast<uword>(LinkNativeCall), | 295 reinterpret_cast<uword>(LinkNativeCall), |
| 259 Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments))); | 296 Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments))); |
| 260 #endif | 297 #endif |
| 261 ASSERT(current_trampoline.raw() == | 298 ASSERT(current_trampoline.raw() == |
| 262 StubCode::CallBootstrapCFunction_entry()->code()); | 299 StubCode::CallBootstrapNative_entry()->code()); |
| 263 } | 300 } |
| 264 #endif | 301 #endif |
| 265 | 302 |
| 266 call_through_wrapper = !is_bootstrap_native; | |
| 267 const Code& trampoline = | |
| 268 Code::Handle(call_through_wrapper | |
| 269 ? StubCode::CallNativeCFunction_entry()->code() | |
| 270 : StubCode::CallBootstrapCFunction_entry()->code()); | |
| 271 | |
| 272 NativeFunction patch_target_function = target_function; | 303 NativeFunction patch_target_function = target_function; |
| 304 Code& trampoline = Code::Handle(zone); |
| 305 if (is_bootstrap_native) { |
| 306 trampoline = StubCode::CallBootstrapNative_entry()->code(); |
| 273 #if defined(USING_SIMULATOR) | 307 #if defined(USING_SIMULATOR) |
| 274 if (!call_through_wrapper) { | |
| 275 patch_target_function = | 308 patch_target_function = |
| 276 reinterpret_cast<NativeFunction>(Simulator::RedirectExternalReference( | 309 reinterpret_cast<NativeFunction>(Simulator::RedirectExternalReference( |
| 277 reinterpret_cast<uword>(patch_target_function), | 310 reinterpret_cast<uword>(patch_target_function), |
| 278 Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments)); | 311 Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments)); |
| 312 #endif |
| 313 } else if (is_auto_scope) { |
| 314 trampoline = StubCode::CallAutoScopeNative_entry()->code(); |
| 315 } else { |
| 316 trampoline = StubCode::CallNoScopeNative_entry()->code(); |
| 279 } | 317 } |
| 280 #endif | |
| 281 | 318 |
| 282 CodePatcher::PatchNativeCallAt(caller_frame->pc(), code, | 319 CodePatcher::PatchNativeCallAt(caller_frame->pc(), code, |
| 283 patch_target_function, trampoline); | 320 patch_target_function, trampoline); |
| 284 | 321 |
| 285 if (FLAG_trace_natives) { | 322 if (FLAG_trace_natives) { |
| 286 OS::Print(" -> %p (%s)\n", target_function, | 323 OS::Print(" -> %p (%s)\n", target_function, |
| 287 is_bootstrap_native ? "bootstrap" : "non-bootstrap"); | 324 is_bootstrap_native ? "bootstrap" : "non-bootstrap"); |
| 288 } | 325 } |
| 289 } | 326 } |
| 290 VERIFY_ON_TRANSITION; | 327 VERIFY_ON_TRANSITION; |
| 291 | 328 |
| 292 // Tail-call resolved target. | 329 // Tail-call resolved target. |
| 293 if (call_through_wrapper) { | 330 if (is_bootstrap_native) { |
| 331 target_function(arguments); |
| 332 } else if (is_auto_scope) { |
| 294 // Because this call is within a compilation unit, Clang doesn't respect | 333 // Because this call is within a compilation unit, Clang doesn't respect |
| 295 // the ABI alignment here. | 334 // the ABI alignment here. |
| 296 NativeEntry::NativeCallWrapperNoStackCheck( | 335 NativeEntry::AutoScopeNativeCallWrapperNoStackCheck( |
| 297 args, reinterpret_cast<Dart_NativeFunction>(target_function)); | 336 args, reinterpret_cast<Dart_NativeFunction>(target_function)); |
| 298 } else { | 337 } else { |
| 299 target_function(arguments); | 338 // Because this call is within a compilation unit, Clang doesn't respect |
| 339 // the ABI alignment here. |
| 340 NativeEntry::NoScopeNativeCallWrapperNoStackCheck( |
| 341 args, reinterpret_cast<Dart_NativeFunction>(target_function)); |
| 300 } | 342 } |
| 301 } | 343 } |
| 302 #endif // !defined(TARGET_ARCH_DBC) | 344 #endif // !defined(TARGET_ARCH_DBC) |
| 303 | 345 |
| 304 | 346 |
| 305 } // namespace dart | 347 } // namespace dart |
| OLD | NEW |