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
18namespace 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
62DART_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
71DART_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
86DART_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
96DART_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
121DART_EXPORT Dart_Handle
122Dart_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
144DART_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
164DART_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
212DART_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
226DART_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
239DART_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