| // 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 = NULL; \ |
| do { \ |
| if (param == NULL) { \ |
| 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 == NULL) { \ |
| return Api::NewError("%s expects argument '%s' to be non-null.", \ |
| CURRENT_FUNC, #param); \ |
| } |
| |
| #define CHECK_DEBUGGER(isolate) \ |
| if (isolate->debugger() == NULL) { \ |
| return Api::NewError("%s requires debugger support.", CURRENT_FUNC); \ |
| } |
| |
| DART_EXPORT 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_EXPORT 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_EXPORT 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_EXPORT 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 = NULL; |
| } 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_EXPORT 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 != NULL) { |
| *function_name = Api::NewHandle(T, frame->QualifiedFunctionName()); |
| } |
| if (script_url != NULL) { |
| *script_url = Api::NewHandle(T, frame->SourceUrl()); |
| } |
| if (line_number != NULL) { |
| *line_number = frame->LineNumber(); |
| } |
| if (column_number != NULL) { |
| *column_number = frame->ColumnNumber(); |
| } |
| return Api::Success(); |
| } |
| |
| DART_EXPORT 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(); |
| bpt = debugger->SetBreakpointAtLineCol(script_url, line_number, -1); |
| if (bpt == NULL) { |
| 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_EXPORT 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_defintions= */ Array::empty_array(), |
| /* type_bounds= */ Array::empty_array(), |
| /* type_defaults= */ Array::empty_array(), |
| String::Handle(lib.url()).ToCString(), |
| /* klass= */ nullptr, |
| /* method= */ nullptr, |
| /* 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_EXPORT 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 == NULL) { |
| RETURN_NULL_ERROR(library_id); |
| } |
| *library_id = lib.index(); |
| return Api::Success(); |
| } |
| |
| DART_EXPORT 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_EXPORT 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 |