Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(642)

Side by Side Diff: samples/lineprocessor.cc

Issue 503022: Add locker support to DebugMessageDispatchHandler (Closed)
Patch Set: make compilable with debugger support off Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/v8-debug.h ('k') | src/api.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <v8.h>
29 #include <v8-debug.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 /**
36 * This sample program should demonstrate certain aspects of debugging
37 * standalone V8-based application.
38 *
39 * The program reads input stream, processes it line by line and print
40 * the result to output. The actual processing is done by custom JavaScript
41 * script. The script is specified in command line parameters.
42 *
43 * Main cycle of the program should sequentially read lines from standard input
44 * and processes them and print to standard output until input closes.
45 * There are 2 possible configuration in regard to main cycle.
46 *
47 * 1. Main cycle is on C++ side. Program should be run with --main-cycle-in-cpp
48 * option. Script gets run once for initialization and should declare global
49 * function "ProcessLine" in return. Main cycle in C++ reads line and calls
50 * this function for processing every time.
51 * This is a slightly over-complicated sample script:
52
53 var Processor = function() {
54 this.prefix = ">>>";
55 this.suffix = "<<<";
56 }
57 Processor.prototype.process = function(input_line) {
58 return this.prefix + input_line + this.suffix;
59 }
60 var default_processor = new Processor();
61 function ProcessLine(input_line) {
62 return default_processor.process(input_line);
63 }
64
65 *
66 * 2. Main cycle is on JavaScript side. Program should be run with
67 * --main-cycle-in-js option. Script gets run one time at all and gets
68 * API of 2 global functions: "read_line" and "print". It should read input
69 * and print converted lines to output itself. This a sample script:
70
71 while (true) {
72 var line = read_line();
73 if (!line) {
74 break;
75 }
76 var res = line + " | " + line;
77 print(res);
78 }
79
80 *
81 * When run with "-p" argument, the program starts V8 Debugger Agent and
82 * allows remote debugger to attach and debug JavaScript code.
83 *
84 * Interesting aspects:
85 * 1. Wait for remote debugger to attach
86 * Normally the program compiles custom script and immediately runs it.
87 * If programmer needs to debug script from the very beginning, he should
88 * run this sample program with "--wait-for-connection" command line parameter.
89 * This way V8 will suspend on the first statement and wait for
90 * debugger to attach.
91 *
92 * 2. Unresponsive V8
93 * V8 Debugger Agent holds a connection with remote debugger, but it does
94 * respond only when V8 is running some script. In particular, when this program
95 * is waiting for input, all requests from debugger get deferred until V8
96 * is called again. See how "--callback" command-line parameter in this sample
97 * fixes this issue.
98 */
99
100 enum MainCycleType {
101 CycleInCpp,
102 CycleInJs
103 };
104
105 const char* ToCString(const v8::String::Utf8Value& value);
106 void ReportException(v8::TryCatch* handler);
107 v8::Handle<v8::String> ReadFile(const char* name);
108 v8::Handle<v8::String> ReadLine();
109
110 v8::Handle<v8::Value> Print(const v8::Arguments& args);
111 v8::Handle<v8::Value> ReadLine(const v8::Arguments& args);
112 bool RunCppCycle(v8::Handle<v8::Script> script, v8::Local<v8::Context> context,
113 bool report_exceptions);
114
115
116 void DispatchDebugMessages() {
117 v8::Locker lock;
118 v8::Debug::ProcessDebuggerCommands();
119 }
120
121
122 int RunMain(int argc, char* argv[]) {
123 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
124 v8::HandleScope handle_scope;
125
126 v8::Handle<v8::String> script_source(NULL);
127 v8::Handle<v8::Value> script_name(NULL);
128 int script_param_counter = 0;
129
130 int port_number = -1;
131 bool wait_for_connection = false;
132 bool support_callback = true;
133 MainCycleType cycle_type = CycleInCpp;
134
135 for (int i = 1; i < argc; i++) {
136 const char* str = argv[i];
137 if (strcmp(str, "-f") == 0) {
138 // Ignore any -f flags for compatibility with the other stand-
139 // alone JavaScript engines.
140 continue;
141 } else if (strcmp(str, "--callback") == 0) {
142 // TODO(548): implement this.
143 printf("Error: debugger agent callback is not supported yet.\n");
144 return 1;
145 } else if (strcmp(str, "--wait-for-connection") == 0) {
146 wait_for_connection = true;
147 } else if (strcmp(str, "--main-cycle-in-cpp") == 0) {
148 cycle_type = CycleInCpp;
149 } else if (strcmp(str, "--main-cycle-in-js") == 0) {
150 cycle_type = CycleInJs;
151 } else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
152 port_number = atoi(argv[i + 1]);
153 i++;
154 } else if (strncmp(str, "--", 2) == 0) {
155 printf("Warning: unknown flag %s.\nTry --help for options\n", str);
156 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
157 script_source = v8::String::New(argv[i + 1]);
158 script_name = v8::String::New("unnamed");
159 i++;
160 script_param_counter++;
161 } else {
162 // Use argument as a name of file to load.
163 script_source = ReadFile(str);
164 script_name = v8::String::New(str);
165 if (script_source.IsEmpty()) {
166 printf("Error reading '%s'\n", str);
167 return 1;
168 }
169 script_param_counter++;
170 }
171 }
172
173 if (script_param_counter == 0) {
174 printf("Script is not specified\n");
175 return 1;
176 }
177 if (script_param_counter != 1) {
178 printf("Only one script may be specified\n");
179 return 1;
180 }
181
182 // Create a template for the global object.
183 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
184
185 // Bind the global 'print' function to the C++ Print callback.
186 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
187
188 if (cycle_type == CycleInJs) {
189 // Bind the global 'read_line' function to the C++ Print callback.
190 global->Set(v8::String::New("read_line"),
191 v8::FunctionTemplate::New(ReadLine));
192 }
193
194 // Create a new execution environment containing the built-in
195 // functions
196 v8::Handle<v8::Context> context = v8::Context::New(NULL, global);
197 // Enter the newly created execution environment.
198 v8::Context::Scope context_scope(context);
199
200 v8::Locker locker;
201
202 if (support_callback) {
203 v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages);
204 }
205
206 if (port_number != -1) {
207 v8::Debug::EnableAgent("lineprocessor", port_number, wait_for_connection);
208 }
209
210 bool report_exceptions = true;
211
212 v8::Handle<v8::Script> script;
213 {
214 // Compile script in try/catch context.
215 v8::TryCatch try_catch;
216 script = v8::Script::Compile(script_source, script_name);
217 if (script.IsEmpty()) {
218 // Print errors that happened during compilation.
219 if (report_exceptions)
220 ReportException(&try_catch);
221 return 1;
222 }
223 }
224
225 {
226 v8::TryCatch try_catch;
227
228 script->Run();
229 if (try_catch.HasCaught()) {
230 if (report_exceptions)
231 ReportException(&try_catch);
232 return 1;
233 }
234 }
235
236 if (cycle_type == CycleInCpp) {
237 bool res = RunCppCycle(script, v8::Context::GetCurrent(),
238 report_exceptions);
239 return !res;
240 } else {
241 // All is already done.
242 }
243 return 0;
244 }
245
246
247 bool RunCppCycle(v8::Handle<v8::Script> script, v8::Local<v8::Context> context,
248 bool report_exceptions) {
249 v8::Locker lock;
250
251 v8::Handle<v8::String> fun_name = v8::String::New("ProcessLine");
252 v8::Handle<v8::Value> process_val =
253 v8::Context::GetCurrent()->Global()->Get(fun_name);
254
255 // If there is no Process function, or if it is not a function,
256 // bail out
257 if (!process_val->IsFunction()) {
258 printf("Error: Script does not declare 'ProcessLine' global function.\n");
259 return 1;
260 }
261
262 // It is a function; cast it to a Function
263 v8::Handle<v8::Function> process_fun =
264 v8::Handle<v8::Function>::Cast(process_val);
265
266
267 while (!feof(stdin)) {
268 v8::HandleScope handle_scope;
269
270 v8::Handle<v8::String> input_line = ReadLine();
271 if (input_line == v8::Undefined()) {
272 continue;
273 }
274
275 const int argc = 1;
276 v8::Handle<v8::Value> argv[argc] = { input_line };
277
278 v8::Handle<v8::Value> result;
279 {
280 v8::TryCatch try_catch;
281 result = process_fun->Call(v8::Context::GetCurrent()->Global(),
282 argc, argv);
283 if (try_catch.HasCaught()) {
284 if (report_exceptions)
285 ReportException(&try_catch);
286 return false;
287 }
288 }
289 v8::String::Utf8Value str(result);
290 const char* cstr = ToCString(str);
291 printf("%s\n", cstr);
292 }
293
294 return true;
295 }
296
297 int main(int argc, char* argv[]) {
298 int result = RunMain(argc, argv);
299 v8::V8::Dispose();
300 return result;
301 }
302
303
304 // Extracts a C string from a V8 Utf8Value.
305 const char* ToCString(const v8::String::Utf8Value& value) {
306 return *value ? *value : "<string conversion failed>";
307 }
308
309
310 // Reads a file into a v8 string.
311 v8::Handle<v8::String> ReadFile(const char* name) {
312 FILE* file = fopen(name, "rb");
313 if (file == NULL) return v8::Handle<v8::String>();
314
315 fseek(file, 0, SEEK_END);
316 int size = ftell(file);
317 rewind(file);
318
319 char* chars = new char[size + 1];
320 chars[size] = '\0';
321 for (int i = 0; i < size;) {
322 int read = fread(&chars[i], 1, size - i, file);
323 i += read;
324 }
325 fclose(file);
326 v8::Handle<v8::String> result = v8::String::New(chars, size);
327 delete[] chars;
328 return result;
329 }
330
331
332 void ReportException(v8::TryCatch* try_catch) {
333 v8::HandleScope handle_scope;
334 v8::String::Utf8Value exception(try_catch->Exception());
335 const char* exception_string = ToCString(exception);
336 v8::Handle<v8::Message> message = try_catch->Message();
337 if (message.IsEmpty()) {
338 // V8 didn't provide any extra information about this error; just
339 // print the exception.
340 printf("%s\n", exception_string);
341 } else {
342 // Print (filename):(line number): (message).
343 v8::String::Utf8Value filename(message->GetScriptResourceName());
344 const char* filename_string = ToCString(filename);
345 int linenum = message->GetLineNumber();
346 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
347 // Print line of source code.
348 v8::String::Utf8Value sourceline(message->GetSourceLine());
349 const char* sourceline_string = ToCString(sourceline);
350 printf("%s\n", sourceline_string);
351 // Print wavy underline (GetUnderline is deprecated).
352 int start = message->GetStartColumn();
353 for (int i = 0; i < start; i++) {
354 printf(" ");
355 }
356 int end = message->GetEndColumn();
357 for (int i = start; i < end; i++) {
358 printf("^");
359 }
360 printf("\n");
361 }
362 }
363
364
365 // The callback that is invoked by v8 whenever the JavaScript 'print'
366 // function is called. Prints its arguments on stdout separated by
367 // spaces and ending with a newline.
368 v8::Handle<v8::Value> Print(const v8::Arguments& args) {
369 bool first = true;
370 for (int i = 0; i < args.Length(); i++) {
371 v8::HandleScope handle_scope;
372 if (first) {
373 first = false;
374 } else {
375 printf(" ");
376 }
377 v8::String::Utf8Value str(args[i]);
378 const char* cstr = ToCString(str);
379 printf("%s", cstr);
380 }
381 printf("\n");
382 fflush(stdout);
383 return v8::Undefined();
384 }
385
386
387 // The callback that is invoked by v8 whenever the JavaScript 'print'
388 // function is called. Prints its arguments on stdout separated by
389 // spaces and ending with a newline.
390 v8::Handle<v8::Value> ReadLine(const v8::Arguments& args) {
391 if (args.Length() > 0) {
392 return v8::ThrowException(v8::String::New("Unexpected arguments"));
393 }
394 return ReadLine();
395 }
396
397 v8::Handle<v8::String> ReadLine() {
398 const int buffer_size = 1024 + 1;
399 char buffer[buffer_size];
400
401 char* res;
402 {
403 v8::Unlocker unlocker;
404 res = fgets(buffer, buffer_size, stdin);
405 }
406 if (res == NULL) {
407 v8::Handle<v8::Primitive> t = v8::Undefined();
408 return reinterpret_cast<v8::Handle<v8::String>&>(t);
409 }
410 // remove newline char
411 for (char* pos = buffer; *pos != '\0'; pos++) {
412 if (*pos == '\n') {
413 *pos = '\0';
414 break;
415 }
416 }
417 return v8::String::New(buffer);
418 }
OLDNEW
« no previous file with comments | « include/v8-debug.h ('k') | src/api.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698