@@ -1275,80 +1275,120 @@ ssize_t DecodeWrite(char *buf,
12751275 return StringBytes::Write (buf, buflen, val, encoding, NULL );
12761276}
12771277
1278- void DisplayExceptionLine (Handle<Message> message) {
1279- // Prevent re-entry into this function. For example, if there is
1280- // a throw from a program in vm.runInThisContext(code, filename, true),
1281- // then we want to show the original failure, not the secondary one.
1282- static bool displayed_error = false ;
1283-
1284- if (displayed_error)
1278+ void AppendExceptionLine (Environment* env,
1279+ Handle<Value> er,
1280+ Handle<Message> message) {
1281+ if (message.IsEmpty ())
12851282 return ;
1286- displayed_error = true ;
12871283
1288- uv_tty_reset_mode ();
1284+ HandleScope scope (env->isolate ());
1285+ Local<Object> err_obj;
1286+ if (!er.IsEmpty () && er->IsObject ()) {
1287+ err_obj = er.As <Object>();
12891288
1290- fprintf (stderr, " \n " );
1291-
1292- if (!message.IsEmpty ()) {
1293- // Print (filename):(line number): (message).
1294- String::Utf8Value filename (message->GetScriptResourceName ());
1295- const char * filename_string = *filename;
1296- int linenum = message->GetLineNumber ();
1297- fprintf (stderr, " %s:%i\n " , filename_string, linenum);
1298- // Print line of source code.
1299- String::Utf8Value sourceline (message->GetSourceLine ());
1300- const char * sourceline_string = *sourceline;
1301-
1302- // Because of how node modules work, all scripts are wrapped with a
1303- // "function (module, exports, __filename, ...) {"
1304- // to provide script local variables.
1305- //
1306- // When reporting errors on the first line of a script, this wrapper
1307- // function is leaked to the user. There used to be a hack here to
1308- // truncate off the first 62 characters, but it caused numerous other
1309- // problems when vm.runIn*Context() methods were used for non-module
1310- // code.
1311- //
1312- // If we ever decide to re-instate such a hack, the following steps
1313- // must be taken:
1314- //
1315- // 1. Pass a flag around to say "this code was wrapped"
1316- // 2. Update the stack frame output so that it is also correct.
1317- //
1318- // It would probably be simpler to add a line rather than add some
1319- // number of characters to the first line, since V8 truncates the
1320- // sourceline to 78 characters, and we end up not providing very much
1321- // useful debugging info to the user if we remove 62 characters.
1322-
1323- int start = message->GetStartColumn ();
1324- int end = message->GetEndColumn ();
1325-
1326- fprintf (stderr, " %s\n " , sourceline_string);
1327- // Print wavy underline (GetUnderline is deprecated).
1328- for (int i = 0 ; i < start; i++) {
1329- fputc ((sourceline_string[i] == ' \t ' ) ? ' \t ' : ' ' , stderr);
1330- }
1331- for (int i = start; i < end; i++) {
1332- fputc (' ^' , stderr);
1333- }
1334- fputc (' \n ' , stderr);
1289+ // Do it only once per message
1290+ if (!err_obj->GetHiddenValue (env->processed_string ()).IsEmpty ())
1291+ return ;
1292+ err_obj->SetHiddenValue (env->processed_string (), True (env->isolate ()));
13351293 }
1294+
1295+ static char arrow[1024 ];
1296+
1297+ // Print (filename):(line number): (message).
1298+ String::Utf8Value filename (message->GetScriptResourceName ());
1299+ const char * filename_string = *filename;
1300+ int linenum = message->GetLineNumber ();
1301+ // Print line of source code.
1302+ String::Utf8Value sourceline (message->GetSourceLine ());
1303+ const char * sourceline_string = *sourceline;
1304+
1305+ // Because of how node modules work, all scripts are wrapped with a
1306+ // "function (module, exports, __filename, ...) {"
1307+ // to provide script local variables.
1308+ //
1309+ // When reporting errors on the first line of a script, this wrapper
1310+ // function is leaked to the user. There used to be a hack here to
1311+ // truncate off the first 62 characters, but it caused numerous other
1312+ // problems when vm.runIn*Context() methods were used for non-module
1313+ // code.
1314+ //
1315+ // If we ever decide to re-instate such a hack, the following steps
1316+ // must be taken:
1317+ //
1318+ // 1. Pass a flag around to say "this code was wrapped"
1319+ // 2. Update the stack frame output so that it is also correct.
1320+ //
1321+ // It would probably be simpler to add a line rather than add some
1322+ // number of characters to the first line, since V8 truncates the
1323+ // sourceline to 78 characters, and we end up not providing very much
1324+ // useful debugging info to the user if we remove 62 characters.
1325+
1326+ int start = message->GetStartColumn ();
1327+ int end = message->GetEndColumn ();
1328+
1329+ int off = snprintf (arrow,
1330+ sizeof (arrow),
1331+ " %s:%i\n %s\n " ,
1332+ filename_string,
1333+ linenum,
1334+ sourceline_string);
1335+ assert (off >= 0 );
1336+
1337+ // Print wavy underline (GetUnderline is deprecated).
1338+ for (int i = 0 ; i < start; i++) {
1339+ assert (static_cast <size_t >(off) < sizeof (arrow));
1340+ arrow[off++] = (sourceline_string[i] == ' \t ' ) ? ' \t ' : ' ' ;
1341+ }
1342+ for (int i = start; i < end; i++) {
1343+ assert (static_cast <size_t >(off) < sizeof (arrow));
1344+ arrow[off++] = ' ^' ;
1345+ }
1346+ assert (static_cast <size_t >(off) < sizeof (arrow) - 1 );
1347+ arrow[off++] = ' \n ' ;
1348+ arrow[off] = ' \0 ' ;
1349+
1350+ Local<String> arrow_str = String::NewFromUtf8 (env->isolate (), arrow);
1351+ Local<Value> msg;
1352+ Local<Value> stack;
1353+
1354+ // Allocation failed, just print it out
1355+ if (arrow_str.IsEmpty () || err_obj.IsEmpty () || !err_obj->IsNativeError ())
1356+ goto print;
1357+
1358+ msg = err_obj->Get (env->message_string ());
1359+ stack = err_obj->Get (env->stack_string ());
1360+
1361+ if (msg.IsEmpty () || stack.IsEmpty ())
1362+ goto print;
1363+
1364+ err_obj->Set (env->message_string (),
1365+ String::Concat (arrow_str, msg->ToString ()));
1366+ err_obj->Set (env->stack_string (),
1367+ String::Concat (arrow_str, stack->ToString ()));
1368+ return ;
1369+
1370+ print:
1371+ if (env->printed_error ())
1372+ return ;
1373+ env->set_printed_error (true );
1374+ uv_tty_reset_mode ();
1375+ fprintf (stderr, " \n %s" , arrow);
13361376}
13371377
13381378
1339- static void ReportException (Handle<Value> er, Handle<Message> message) {
1340- HandleScope scope (node_isolate);
1379+ static void ReportException (Environment* env,
1380+ Handle<Value> er,
1381+ Handle<Message> message) {
1382+ HandleScope scope (env->isolate ());
13411383
1342- DisplayExceptionLine ( message);
1384+ AppendExceptionLine (env, er, message);
13431385
13441386 Local<Value> trace_value;
13451387
1346- if (er->IsUndefined () || er->IsNull ()) {
1347- trace_value = Undefined (node_isolate);
1348- } else {
1349- trace_value =
1350- er->ToObject ()->Get (FIXED_ONE_BYTE_STRING (node_isolate, " stack" ));
1351- }
1388+ if (er->IsUndefined () || er->IsNull ())
1389+ trace_value = Undefined (env->isolate ());
1390+ else
1391+ trace_value = er->ToObject ()->Get (env->stack_string ());
13521392
13531393 String::Utf8Value trace (trace_value);
13541394
@@ -1364,8 +1404,8 @@ static void ReportException(Handle<Value> er, Handle<Message> message) {
13641404
13651405 if (er->IsObject ()) {
13661406 Local<Object> err_obj = er.As <Object>();
1367- message = err_obj->Get (FIXED_ONE_BYTE_STRING (node_isolate, " message " ));
1368- name = err_obj->Get (FIXED_ONE_BYTE_STRING (node_isolate , " name" ));
1407+ message = err_obj->Get (env-> message_string ( ));
1408+ name = err_obj->Get (FIXED_ONE_BYTE_STRING (env-> isolate () , " name" ));
13691409 }
13701410
13711411 if (message.IsEmpty () ||
@@ -1386,14 +1426,16 @@ static void ReportException(Handle<Value> er, Handle<Message> message) {
13861426}
13871427
13881428
1389- static void ReportException (const TryCatch& try_catch) {
1390- ReportException (try_catch.Exception (), try_catch.Message ());
1429+ static void ReportException (Environment* env, const TryCatch& try_catch) {
1430+ ReportException (env, try_catch.Exception (), try_catch.Message ());
13911431}
13921432
13931433
13941434// Executes a str within the current v8 context.
1395- Local<Value> ExecuteString (Handle<String> source, Handle<Value> filename) {
1396- HandleScope scope (node_isolate);
1435+ static Local<Value> ExecuteString (Environment* env,
1436+ Handle<String> source,
1437+ Handle<Value> filename) {
1438+ HandleScope scope (env->isolate ());
13971439 TryCatch try_catch;
13981440
13991441 // try_catch must be nonverbose to disable FatalException() handler,
@@ -1402,13 +1444,13 @@ Local<Value> ExecuteString(Handle<String> source, Handle<Value> filename) {
14021444
14031445 Local<v8::Script> script = v8::Script::Compile (source, filename);
14041446 if (script.IsEmpty ()) {
1405- ReportException (try_catch);
1447+ ReportException (env, try_catch);
14061448 exit (3 );
14071449 }
14081450
14091451 Local<Value> result = script->Run ();
14101452 if (result.IsEmpty ()) {
1411- ReportException (try_catch);
1453+ ReportException (env, try_catch);
14121454 exit (4 );
14131455 }
14141456
@@ -2025,7 +2067,7 @@ void FatalException(Handle<Value> error, Handle<Message> message) {
20252067 if (!fatal_exception_function->IsFunction ()) {
20262068 // failed before the process._fatalException function was added!
20272069 // this is probably pretty bad. Nothing to do but report and exit.
2028- ReportException (error, message);
2070+ ReportException (env, error, message);
20292071 exit (6 );
20302072 }
20312073
@@ -2040,12 +2082,12 @@ void FatalException(Handle<Value> error, Handle<Message> message) {
20402082
20412083 if (fatal_try_catch.HasCaught ()) {
20422084 // the fatal exception function threw, so we must exit
2043- ReportException (fatal_try_catch);
2085+ ReportException (env, fatal_try_catch);
20442086 exit (7 );
20452087 }
20462088
20472089 if (false == caught->BooleanValue ()) {
2048- ReportException (error, message);
2090+ ReportException (env, error, message);
20492091 exit (1 );
20502092 }
20512093}
@@ -2705,10 +2747,10 @@ void Load(Environment* env) {
27052747 // are not safe to ignore.
27062748 try_catch.SetVerbose (false );
27072749
2708- Local<String> script_name = FIXED_ONE_BYTE_STRING (node_isolate , " node.js" );
2709- Local<Value> f_value = ExecuteString (MainSource (), script_name);
2750+ Local<String> script_name = FIXED_ONE_BYTE_STRING (env-> isolate () , " node.js" );
2751+ Local<Value> f_value = ExecuteString (env, MainSource (), script_name);
27102752 if (try_catch.HasCaught ()) {
2711- ReportException (try_catch);
2753+ ReportException (env, try_catch);
27122754 exit (10 );
27132755 }
27142756 assert (f_value->IsFunction ());
0 commit comments