| 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 "include/dart_tools_api.h" |
| 7 | |
| 8 | #include "vm/class_finalizer.h" |
| 9 | #include "vm/compiler/jit/compiler.h" |
| 10 | #include "vm/dart_api_impl.h" |
| 11 | #include "vm/dart_api_state.h" |
| 12 | #include "vm/debugger.h" |
| 13 | #include "vm/debugger_api_impl_test.h" |
| 14 | #include "vm/isolate.h" |
| 15 | #include "vm/object_store.h" |
| 16 | #include "vm/symbols.h" |
| 17 | |
| 18 | namespace dart { |
| 19 | |
| 20 | // Facilitate quick access to the current zone once we have the current thread. |
| 21 | #define Z (T->zone()) |
| 22 | |
| 23 | #ifndef PRODUCT |
| 24 | |
| 25 | #define UNWRAP_AND_CHECK_PARAM(type, var, param) \ |
| 26 | type& var = type::Handle(); \ |
| 27 | do { \ |
| 28 | const Object& tmp = Object::Handle(Api::UnwrapHandle(param)); \ |
| 29 | if (tmp.IsNull()) { \ |
| 30 | return Api::NewError("%s expects argument '%s' to be non-null.", \ |
| 31 | CURRENT_FUNC, #param); \ |
| 32 | } else if (tmp.IsApiError()) { \ |
| 33 | return param; \ |
| 34 | } else if (!tmp.Is##type()) { \ |
| 35 | return Api::NewError("%s expects argument '%s' to be of type %s.", \ |
| 36 | CURRENT_FUNC, #param, #type); \ |
| 37 | } \ |
| 38 | var ^= tmp.raw(); \ |
| 39 | } while (0) |
| 40 | |
| 41 | #define CHECK_AND_CAST(type, var, param) \ |
| 42 | type* var = NULL; \ |
| 43 | do { \ |
| 44 | if (param == NULL) { \ |
| 45 | return Api::NewError("%s expects argument '%s' to be non-null.", \ |
| 46 | CURRENT_FUNC, #param); \ |
| 47 | } \ |
| 48 | var = reinterpret_cast<type*>(param); \ |
| 49 | } while (0) |
| 50 | |
| 51 | #define CHECK_NOT_NULL(param) \ |
| 52 | if (param == NULL) { \ |
| 53 | return Api::NewError("%s expects argument '%s' to be non-null.", \ |
| 54 | CURRENT_FUNC, #param); \ |
| 55 | } |
| 56 | |
| 57 | #define CHECK_DEBUGGER(isolate) \ |
| 58 | if (isolate->debugger() == NULL) { \ |
| 59 | return Api::NewError("%s requires debugger support.", CURRENT_FUNC); \ |
| 60 | } |
| 61 | |
| 62 | DART_EXPORT Dart_Handle Dart_StackTraceLength(Dart_StackTrace trace, |
| 63 | intptr_t* length) { |
| 64 | DARTSCOPE(Thread::Current()); |
| 65 | CHECK_NOT_NULL(length); |
| 66 | CHECK_AND_CAST(DebuggerStackTrace, stack_trace, trace); |
| 67 | *length = stack_trace->Length(); |
| 68 | return Api::Success(); |
| 69 | } |
| 70 | |
| 71 | DART_EXPORT Dart_Handle Dart_GetActivationFrame(Dart_StackTrace trace, |
| 72 | int frame_index, |
| 73 | Dart_ActivationFrame* frame) { |
| 74 | DARTSCOPE(Thread::Current()); |
| 75 | CHECK_NOT_NULL(frame); |
| 76 | CHECK_AND_CAST(DebuggerStackTrace, stack_trace, trace); |
| 77 | if ((frame_index < 0) || (frame_index >= stack_trace->Length())) { |
| 78 | return Api::NewError("argument 'frame_index' is out of range for %s" , |
| 79 | CURRENT_FUNC); |
| 80 | } |
| 81 | *frame = |
| 82 | reinterpret_cast<Dart_ActivationFrame>(stack_trace->FrameAt(frame_index)); |
| 83 | return Api::Success(); |
| 84 | } |
| 85 | |
| 86 | DART_EXPORT Dart_Handle Dart_GetStackTrace(Dart_StackTrace* trace) { |
| 87 | DARTSCOPE(Thread::Current()); |
| 88 | Isolate* I = T->isolate(); |
| 89 | CHECK_DEBUGGER(I); |
| 90 | CHECK_NOT_NULL(trace); |
| 91 | *trace = |
| 92 | reinterpret_cast<Dart_StackTrace>(I->debugger()->CurrentStackTrace()); |
| 93 | return Api::Success(); |
| 94 | } |
| 95 | |
| 96 | DART_EXPORT Dart_Handle Dart_GetStackTraceFromError(Dart_Handle handle, |
| 97 | Dart_StackTrace* trace) { |
| 98 | DARTSCOPE(Thread::Current()); |
| 99 | CHECK_DEBUGGER(T->isolate()); |
| 100 | CHECK_NOT_NULL(trace); |
| 101 | const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle)); |
| 102 | if (obj.IsUnhandledException()) { |
| 103 | const UnhandledException& error = UnhandledException::Cast(obj); |
| 104 | StackTrace& dart_stacktrace = StackTrace::Handle(Z); |
| 105 | dart_stacktrace ^= error.stacktrace(); |
| 106 | if (dart_stacktrace.IsNull()) { |
| 107 | *trace = NULL; |
| 108 | } else { |
| 109 | Isolate* I = T->isolate(); |
| 110 | *trace = reinterpret_cast<Dart_StackTrace>( |
| 111 | I->debugger()->StackTraceFrom(dart_stacktrace)); |
| 112 | } |
| 113 | return Api::Success(); |
| 114 | } else { |
| 115 | return Api::NewError( |
| 116 | "Can only get stacktraces from error handles or " |
| 117 | "instances of Error." ); |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | DART_EXPORT Dart_Handle |
| 122 | Dart_ActivationFrameInfo(Dart_ActivationFrame activation_frame, |
| 123 | Dart_Handle* function_name, |
| 124 | Dart_Handle* script_url, |
| 125 | intptr_t* line_number, |
| 126 | intptr_t* column_number) { |
| 127 | DARTSCOPE(Thread::Current()); |
| 128 | CHECK_AND_CAST(ActivationFrame, frame, activation_frame); |
| 129 | if (function_name != NULL) { |
| 130 | *function_name = Api::NewHandle(T, frame->QualifiedFunctionName()); |
| 131 | } |
| 132 | if (script_url != NULL) { |
| 133 | *script_url = Api::NewHandle(T, frame->SourceUrl()); |
| 134 | } |
| 135 | if (line_number != NULL) { |
| 136 | *line_number = frame->LineNumber(); |
| 137 | } |
| 138 | if (column_number != NULL) { |
| 139 | *column_number = frame->ColumnNumber(); |
| 140 | } |
| 141 | return Api::Success(); |
| 142 | } |
| 143 | |
| 144 | DART_EXPORT Dart_Handle Dart_SetBreakpoint(Dart_Handle script_url_in, |
| 145 | intptr_t line_number) { |
| 146 | Breakpoint* bpt; |
| 147 | { |
| 148 | DARTSCOPE(Thread::Current()); |
| 149 | Isolate* I = T->isolate(); |
| 150 | CHECK_DEBUGGER(I); |
| 151 | UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in); |
| 152 | |
| 153 | Debugger* debugger = I->debugger(); |
| 154 | bpt = debugger->SetBreakpointAtLine(script_url, line_number); |
| 155 | if (bpt == NULL) { |
| 156 | return Api::NewError("%s: could not set breakpoint at line %" Pd |
| 157 | " in '%s'" , |
| 158 | CURRENT_FUNC, line_number, script_url.ToCString()); |
| 159 | } |
| 160 | } |
| 161 | return Dart_NewInteger(bpt->id()); |
| 162 | } |
| 163 | |
| 164 | DART_EXPORT Dart_Handle Dart_EvaluateStaticExpr(Dart_Handle lib_handle, |
| 165 | Dart_Handle expr_in) { |
| 166 | DARTSCOPE(Thread::Current()); |
| 167 | CHECK_DEBUGGER(T->isolate()); |
| 168 | |
| 169 | const Object& target = Object::Handle(Z, Api::UnwrapHandle(lib_handle)); |
| 170 | if (target.IsError()) return lib_handle; |
| 171 | if (target.IsNull()) { |
| 172 | return Api::NewError("%s expects argument 'target' to be non-null" , |
| 173 | CURRENT_FUNC); |
| 174 | } |
| 175 | const Library& lib = Library::Cast(target); |
| 176 | UNWRAP_AND_CHECK_PARAM(String, expr, expr_in); |
| 177 | |
| 178 | if (!KernelIsolate::IsRunning()) { |
| 179 | UNREACHABLE(); |
| 180 | } else { |
| 181 | Dart_KernelCompilationResult compilation_result = |
| 182 | KernelIsolate::CompileExpressionToKernel( |
| 183 | /* platform_kernel= */ nullptr, /* platform_kernel_size= */ 0, |
| 184 | expr.ToCString(), |
| 185 | /* definitions= */ Array::empty_array(), |
| 186 | /* type_defintions= */ Array::empty_array(), |
| 187 | String::Handle(lib.url()).ToCString(), |
| 188 | /* klass= */ nullptr, |
| 189 | /* is_static= */ true); |
| 190 | if (compilation_result.status != Dart_KernelCompilationStatus_Ok) { |
| 191 | return Api::NewError("Failed to compile expression." ); |
| 192 | } |
| 193 | |
| 194 | const ExternalTypedData& kernel_buffer = |
| 195 | ExternalTypedData::Handle(ExternalTypedData::NewFinalizeWithFree( |
| 196 | const_cast<uint8_t*>(compilation_result.kernel), |
| 197 | compilation_result.kernel_size)); |
| 198 | |
| 199 | Dart_Handle result = Api::NewHandle( |
| 200 | T, |
| 201 | lib.EvaluateCompiledExpression(kernel_buffer, |
| 202 | /* type_definitions= */ |
| 203 | Array::empty_array(), |
| 204 | /* param_values= */ |
| 205 | Array::empty_array(), |
| 206 | /* type_param_values= */ |
| 207 | TypeArguments::null_type_arguments())); |
| 208 | return result; |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | DART_EXPORT Dart_Handle Dart_LibraryId(Dart_Handle library, |
| 213 | intptr_t* library_id) { |
| 214 | DARTSCOPE(Thread::Current()); |
| 215 | const Library& lib = Api::UnwrapLibraryHandle(Z, library); |
| 216 | if (lib.IsNull()) { |
| 217 | RETURN_TYPE_ERROR(Z, library, Library); |
| 218 | } |
| 219 | if (library_id == NULL) { |
| 220 | RETURN_NULL_ERROR(library_id); |
| 221 | } |
| 222 | *library_id = lib.index(); |
| 223 | return Api::Success(); |
| 224 | } |
| 225 | |
| 226 | DART_EXPORT Dart_Handle Dart_GetLibraryDebuggable(intptr_t library_id, |
| 227 | bool* is_debuggable) { |
| 228 | DARTSCOPE(Thread::Current()); |
| 229 | CHECK_NOT_NULL(is_debuggable); |
| 230 | const Library& lib = Library::Handle(Library::GetLibrary(library_id)); |
| 231 | if (lib.IsNull()) { |
| 232 | return Api::NewError("%s: %" Pd " is not a valid library id" , CURRENT_FUNC, |
| 233 | library_id); |
| 234 | } |
| 235 | *is_debuggable = lib.IsDebuggable(); |
| 236 | return Api::Success(); |
| 237 | } |
| 238 | |
| 239 | DART_EXPORT Dart_Handle Dart_SetLibraryDebuggable(intptr_t library_id, |
| 240 | bool is_debuggable) { |
| 241 | DARTSCOPE(Thread::Current()); |
| 242 | const Library& lib = Library::Handle(Z, Library::GetLibrary(library_id)); |
| 243 | if (lib.IsNull()) { |
| 244 | return Api::NewError("%s: %" Pd " is not a valid library id" , CURRENT_FUNC, |
| 245 | library_id); |
| 246 | } |
| 247 | lib.set_debuggable(is_debuggable); |
| 248 | return Api::Success(); |
| 249 | } |
| 250 | |
| 251 | #endif // !PRODUCT |
| 252 | |
| 253 | } // namespace dart |
| 254 | |