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