| // 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 "include/dart_tools_api.h" | |
| #include "vm/class_finalizer.h" | |
| #include "vm/compiler/jit/compiler.h" | |
| #include "vm/dart_api_impl.h" | |
| #include "vm/dart_api_state.h" | |
| #include "vm/debugger.h" | |
| #include "vm/debugger_api_impl_test.h" | |
| #include "vm/isolate.h" | |
| #include "vm/object_store.h" | |
| #include "vm/symbols.h" | |
| namespace dart { | |
| // Facilitate quick access to the current zone once we have the current thread. | |
| #define Z (T->zone()) | |
| #ifndef PRODUCT | |
| #define UNWRAP_AND_CHECK_PARAM(type, var, param) \ | |
| type& var = type::Handle(); \ | |
| do { \ | |
| const Object& tmp = Object::Handle(Api::UnwrapHandle(param)); \ | |
| if (tmp.IsNull()) { \ | |
| return Api::NewError("%s expects argument '%s' to be non-null.", \ | |
| CURRENT_FUNC, #param); \ | |
| } else if (tmp.IsApiError()) { \ | |
| return param; \ | |
| } else if (!tmp.Is##type()) { \ | |
| return Api::NewError("%s expects argument '%s' to be of type %s.", \ | |
| CURRENT_FUNC, #param, #type); \ | |
| } \ | |
| var ^= tmp.ptr(); \ | |
| } while (0) | |
| #define CHECK_AND_CAST(type, var, param) \ | |
| type* var = nullptr; \ | |
| do { \ | |
| if (param == nullptr) { \ | |
| return Api::NewError("%s expects argument '%s' to be non-null.", \ | |
| CURRENT_FUNC, #param); \ | |
| } \ | |
| var = reinterpret_cast<type*>(param); \ | |
| } while (0) | |
| #define CHECK_NOT_NULL(param) \ | |
| if (param == nullptr) { \ | |
| return Api::NewError("%s expects argument '%s' to be non-null.", \ | |
| CURRENT_FUNC, #param); \ | |
| } | |
| #define CHECK_DEBUGGER(isolate) \ | |
| if (isolate->debugger() == nullptr) { \ | |
| return Api::NewError("%s requires debugger support.", CURRENT_FUNC); \ | |
| } | |
| Dart_Handle Dart_StackTraceLength(Dart_StackTrace trace, intptr_t* length) { | |
| DARTSCOPE(Thread::Current()); | |
| CHECK_NOT_NULL(length); | |
| CHECK_AND_CAST(DebuggerStackTrace, stack_trace, trace); | |
| *length = stack_trace->Length(); | |
| return Api::Success(); | |
| } | |
| Dart_Handle Dart_GetActivationFrame(Dart_StackTrace trace, | |
| int frame_index, | |
| Dart_ActivationFrame* frame) { | |
| DARTSCOPE(Thread::Current()); | |
| CHECK_NOT_NULL(frame); | |
| CHECK_AND_CAST(DebuggerStackTrace, stack_trace, trace); | |
| if ((frame_index < 0) || (frame_index >= stack_trace->Length())) { | |
| return Api::NewError("argument 'frame_index' is out of range for %s", | |
| CURRENT_FUNC); | |
| } | |
| *frame = | |
| reinterpret_cast<Dart_ActivationFrame>(stack_trace->FrameAt(frame_index)); | |
| return Api::Success(); | |
| } | |
| Dart_Handle Dart_GetStackTrace(Dart_StackTrace* trace) { | |
| DARTSCOPE(Thread::Current()); | |
| Isolate* I = T->isolate(); | |
| CHECK_DEBUGGER(I); | |
| CHECK_NOT_NULL(trace); | |
| *trace = reinterpret_cast<Dart_StackTrace>(DebuggerStackTrace::Collect()); | |
| return Api::Success(); | |
| } | |
| Dart_Handle Dart_GetStackTraceFromError(Dart_Handle handle, | |
| Dart_StackTrace* trace) { | |
| DARTSCOPE(Thread::Current()); | |
| CHECK_DEBUGGER(T->isolate()); | |
| CHECK_NOT_NULL(trace); | |
| const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle)); | |
| if (obj.IsUnhandledException()) { | |
| const UnhandledException& error = UnhandledException::Cast(obj); | |
| StackTrace& dart_stacktrace = StackTrace::Handle(Z); | |
| dart_stacktrace ^= error.stacktrace(); | |
| if (dart_stacktrace.IsNull()) { | |
| *trace = nullptr; | |
| } else { | |
| *trace = reinterpret_cast<Dart_StackTrace>( | |
| DebuggerStackTrace::From(dart_stacktrace)); | |
| } | |
| return Api::Success(); | |
| } else { | |
| return Api::NewError( | |
| "Can only get stacktraces from error handles or " | |
| "instances of Error."); | |
| } | |
| } | |
| Dart_Handle Dart_ActivationFrameInfo(Dart_ActivationFrame activation_frame, | |
| Dart_Handle* function_name, | |
| Dart_Handle* script_url, | |
| intptr_t* line_number, | |
| intptr_t* column_number) { | |
| DARTSCOPE(Thread::Current()); | |
| CHECK_AND_CAST(ActivationFrame, frame, activation_frame); | |
| if (function_name != nullptr) { | |
| *function_name = Api::NewHandle(T, frame->QualifiedFunctionName()); | |
| } | |
| if (script_url != nullptr) { | |
| *script_url = Api::NewHandle(T, frame->SourceUrl()); | |
| } | |
| if (line_number != nullptr) { | |
| *line_number = frame->LineNumber(); | |
| } | |
| if (column_number != nullptr) { | |
| *column_number = frame->ColumnNumber(); | |
| } | |
| return Api::Success(); | |
| } | |
| Dart_Handle Dart_SetBreakpoint(Dart_Handle script_url_in, | |
| intptr_t line_number) { | |
| Breakpoint* bpt; | |
| { | |
| DARTSCOPE(Thread::Current()); | |
| Isolate* I = T->isolate(); | |
| CHECK_DEBUGGER(I); | |
| UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in); | |
| Debugger* debugger = I->debugger(); | |
| const Error& error = Error::Handle( | |
| debugger->SetBreakpointAtLineCol(script_url, line_number, -1, &bpt)); | |
| if (!error.IsNull() || bpt == nullptr) { | |
| return Api::NewError("%s: could not set breakpoint at line %" Pd | |
| " in '%s'", | |
| CURRENT_FUNC, line_number, script_url.ToCString()); | |
| } | |
| } | |
| return Dart_NewInteger(bpt->id()); | |
| } | |
| Dart_Handle Dart_RemoveBreakpoint(Dart_Handle breakpoint_id_in) { | |
| DARTSCOPE(Thread::Current()); | |
| Isolate* I = T->isolate(); | |
| CHECK_DEBUGGER(I); | |
| UNWRAP_AND_CHECK_PARAM(Integer, breakpoint_id, breakpoint_id_in); | |
| I->debugger()->RemoveBreakpoint(breakpoint_id.Value()); | |
| return Api::Success(); | |
| } | |
| Dart_Handle Dart_EvaluateStaticExpr(Dart_Handle lib_handle, | |
| Dart_Handle expr_in) { | |
| DARTSCOPE(Thread::Current()); | |
| CHECK_DEBUGGER(T->isolate()); | |
| const Object& target = Object::Handle(Z, Api::UnwrapHandle(lib_handle)); | |
| if (target.IsError()) return lib_handle; | |
| if (target.IsNull()) { | |
| return Api::NewError("%s expects argument 'target' to be non-null", | |
| CURRENT_FUNC); | |
| } | |
| const Library& lib = Library::Cast(target); | |
| UNWRAP_AND_CHECK_PARAM(String, expr, expr_in); | |
| if (!KernelIsolate::IsRunning()) { | |
| UNREACHABLE(); | |
| } else { | |
| Dart_KernelCompilationResult compilation_result = | |
| KernelIsolate::CompileExpressionToKernel( | |
| /* platform_kernel= */ nullptr, /* platform_kernel_size= */ 0, | |
| expr.ToCString(), | |
| /* definitions= */ Array::empty_array(), | |
| /* definition_types= */ Array::empty_array(), | |
| /* type_definitions= */ Array::empty_array(), | |
| /* type_bounds= */ Array::empty_array(), | |
| /* type_defaults= */ Array::empty_array(), | |
| String::Handle(lib.url()).ToCString(), | |
| /* klass= */ nullptr, | |
| /* method= */ nullptr, | |
| /* token_pos= */ TokenPosition::kNoSource, | |
| /* script_uri= */ String::Handle(lib.url()).ToCString(), | |
| /* is_static= */ true); | |
| if (compilation_result.status != Dart_KernelCompilationStatus_Ok) { | |
| return Api::NewError("Failed to compile expression."); | |
| } | |
| const ExternalTypedData& kernel_buffer = | |
| ExternalTypedData::Handle(ExternalTypedData::NewFinalizeWithFree( | |
| const_cast<uint8_t*>(compilation_result.kernel), | |
| compilation_result.kernel_size)); | |
| Dart_Handle result = Api::NewHandle( | |
| T, | |
| lib.EvaluateCompiledExpression(kernel_buffer, | |
| /* type_definitions= */ | |
| Array::empty_array(), | |
| /* param_values= */ | |
| Array::empty_array(), | |
| /* type_param_values= */ | |
| TypeArguments::null_type_arguments())); | |
| return result; | |
| } | |
| } | |
| Dart_Handle Dart_LibraryId(Dart_Handle library, intptr_t* library_id) { | |
| DARTSCOPE(Thread::Current()); | |
| const Library& lib = Api::UnwrapLibraryHandle(Z, library); | |
| if (lib.IsNull()) { | |
| RETURN_TYPE_ERROR(Z, library, Library); | |
| } | |
| if (library_id == nullptr) { | |
| RETURN_NULL_ERROR(library_id); | |
| } | |
| *library_id = lib.index(); | |
| return Api::Success(); | |
| } | |
| Dart_Handle Dart_GetLibraryDebuggable(intptr_t library_id, | |
| bool* is_debuggable) { | |
| DARTSCOPE(Thread::Current()); | |
| CHECK_NOT_NULL(is_debuggable); | |
| const Library& lib = Library::Handle(Library::GetLibrary(library_id)); | |
| if (lib.IsNull()) { | |
| return Api::NewError("%s: %" Pd " is not a valid library id", CURRENT_FUNC, | |
| library_id); | |
| } | |
| *is_debuggable = lib.IsDebuggable(); | |
| return Api::Success(); | |
| } | |
| Dart_Handle Dart_SetLibraryDebuggable(intptr_t library_id, bool is_debuggable) { | |
| DARTSCOPE(Thread::Current()); | |
| const Library& lib = Library::Handle(Z, Library::GetLibrary(library_id)); | |
| if (lib.IsNull()) { | |
| return Api::NewError("%s: %" Pd " is not a valid library id", CURRENT_FUNC, | |
| library_id); | |
| } | |
| lib.set_debuggable(is_debuggable); | |
| return Api::Success(); | |
| } | |
| #endif // !PRODUCT | |
| } // namespace dart |