| // 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 |