| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2014, 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 "vm/report.h" |
| 6 |
| 7 #include "vm/code_patcher.h" |
| 8 #include "vm/exceptions.h" |
| 9 #include "vm/flags.h" |
| 10 #include "vm/longjump.h" |
| 11 #include "vm/object.h" |
| 12 #include "vm/stack_frame.h" |
| 13 #include "vm/symbols.h" |
| 14 |
| 15 namespace dart { |
| 16 |
| 17 DEFINE_FLAG(int, stacktrace_depth_on_warning, 5, |
| 18 "Maximal number of stack frames to print after a runtime warning."); |
| 19 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); |
| 20 DEFINE_FLAG(bool, warn_on_javascript_compatibility, false, |
| 21 "Warn on incompatibilities between vm and dart2js."); |
| 22 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); |
| 23 |
| 24 |
| 25 RawString* Report::PrependSnippet(Kind kind, |
| 26 const Script& script, |
| 27 intptr_t token_pos, |
| 28 const String& message) { |
| 29 const char* message_header; |
| 30 switch (kind) { |
| 31 case kWarning: message_header = "warning"; break; |
| 32 case kJSWarning: message_header = "javascript compatibility warning"; break; |
| 33 case kError: message_header = "error"; break; |
| 34 case kMalformedType: message_header = "malformed type"; break; |
| 35 case kMalboundedType: message_header = "malbounded type"; break; |
| 36 case kBailout: message_header = "bailout"; break; |
| 37 default: message_header = ""; UNREACHABLE(); |
| 38 } |
| 39 String& result = String::Handle(); |
| 40 if (!script.IsNull()) { |
| 41 const String& script_url = String::Handle(script.url()); |
| 42 if (token_pos >= 0) { |
| 43 intptr_t line, column; |
| 44 script.GetTokenLocation(token_pos, &line, &column); |
| 45 // Only report the line position if we have the original source. We still |
| 46 // need to get a valid column so that we can report the ^ mark below the |
| 47 // snippet. |
| 48 if (script.HasSource()) { |
| 49 result = String::NewFormatted("'%s': %s: line %" Pd " pos %" Pd ": ", |
| 50 script_url.ToCString(), |
| 51 message_header, |
| 52 line, |
| 53 column); |
| 54 } else { |
| 55 result = String::NewFormatted("'%s': %s: line %" Pd ": ", |
| 56 script_url.ToCString(), |
| 57 message_header, |
| 58 line); |
| 59 } |
| 60 // Append the formatted error or warning message. |
| 61 result = String::Concat(result, message); |
| 62 // Append the source line. |
| 63 const String& script_line = String::Handle(script.GetLine(line)); |
| 64 ASSERT(!script_line.IsNull()); |
| 65 result = String::Concat(result, Symbols::NewLine()); |
| 66 result = String::Concat(result, script_line); |
| 67 result = String::Concat(result, Symbols::NewLine()); |
| 68 // Append the column marker. |
| 69 const String& column_line = String::Handle( |
| 70 String::NewFormatted("%*s\n", static_cast<int>(column), "^")); |
| 71 result = String::Concat(result, column_line); |
| 72 } else { |
| 73 // Token position is unknown. |
| 74 result = String::NewFormatted("'%s': %s: ", |
| 75 script_url.ToCString(), |
| 76 message_header); |
| 77 result = String::Concat(result, message); |
| 78 } |
| 79 } else { |
| 80 // Script is unknown. |
| 81 // Append the formatted error or warning message. |
| 82 result = String::NewFormatted("%s: ", message_header); |
| 83 result = String::Concat(result, message); |
| 84 } |
| 85 return result.raw(); |
| 86 } |
| 87 |
| 88 |
| 89 void Report::LongJump(const Error& error) { |
| 90 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 91 UNREACHABLE(); |
| 92 } |
| 93 |
| 94 |
| 95 void Report::LongJumpF(const Error& prev_error, |
| 96 const Script& script, intptr_t token_pos, |
| 97 const char* format, ...) { |
| 98 va_list args; |
| 99 va_start(args, format); |
| 100 LongJumpV(prev_error, script, token_pos, format, args); |
| 101 va_end(args); |
| 102 UNREACHABLE(); |
| 103 } |
| 104 |
| 105 |
| 106 void Report::LongJumpV(const Error& prev_error, |
| 107 const Script& script, intptr_t token_pos, |
| 108 const char* format, va_list args) { |
| 109 const Error& error = Error::Handle(LanguageError::NewFormattedV( |
| 110 prev_error, script, token_pos, |
| 111 kError, Heap::kNew, |
| 112 format, args)); |
| 113 LongJump(error); |
| 114 UNREACHABLE(); |
| 115 } |
| 116 |
| 117 |
| 118 void Report::MessageF(Kind kind, const Script& script, intptr_t token_pos, |
| 119 const char* format, ...) { |
| 120 va_list args; |
| 121 va_start(args, format); |
| 122 MessageV(kind, script, token_pos, format, args); |
| 123 va_end(args); |
| 124 } |
| 125 |
| 126 |
| 127 void Report::MessageV(Kind kind, const Script& script, intptr_t token_pos, |
| 128 const char* format, va_list args) { |
| 129 if (kind < kError) { |
| 130 // Reporting a warning. |
| 131 if (FLAG_silent_warnings) { |
| 132 return; |
| 133 } |
| 134 if (!FLAG_warning_as_error) { |
| 135 const String& msg = String::Handle(String::NewFormattedV(format, args)); |
| 136 const String& snippet_msg = String::Handle( |
| 137 PrependSnippet(kind, script, token_pos, msg)); |
| 138 OS::Print("%s", snippet_msg.ToCString()); |
| 139 if (kind == kJSWarning) { |
| 140 TraceJSWarning(script, token_pos, msg); |
| 141 // Do not print stacktrace if we have not executed Dart code yet. |
| 142 if (Isolate::Current()->top_exit_frame_info() != 0) { |
| 143 const Stacktrace& stacktrace = |
| 144 Stacktrace::Handle(Exceptions::CurrentStacktrace()); |
| 145 intptr_t idx = 0; |
| 146 OS::Print("%s", stacktrace.ToCStringInternal( |
| 147 &idx, FLAG_stacktrace_depth_on_warning)); |
| 148 } |
| 149 } |
| 150 return; |
| 151 } |
| 152 } |
| 153 // Reporting an error (or a warning as error). |
| 154 const Error& error = Error::Handle( |
| 155 LanguageError::NewFormattedV(Error::Handle(), // No previous error. |
| 156 script, token_pos, |
| 157 kind, Heap::kNew, |
| 158 format, args)); |
| 159 if (kind == kJSWarning) { |
| 160 Exceptions::ThrowJavascriptCompatibilityError(error.ToErrorCString()); |
| 161 UNREACHABLE(); |
| 162 } |
| 163 LongJump(error); |
| 164 UNREACHABLE(); |
| 165 } |
| 166 |
| 167 |
| 168 void Report::JSWarningFromNative(bool is_static_native, const char* msg) { |
| 169 DartFrameIterator iterator; |
| 170 iterator.NextFrame(); // Skip native call. |
| 171 StackFrame* caller_frame = iterator.NextFrame(); |
| 172 ASSERT(caller_frame != NULL); |
| 173 const Code& caller_code = Code::Handle(caller_frame->LookupDartCode()); |
| 174 ASSERT(!caller_code.IsNull()); |
| 175 const uword caller_pc = caller_frame->pc(); |
| 176 ICData& ic_data = ICData::Handle(); |
| 177 if (is_static_native) { |
| 178 // Assume an unoptimized static call. Optimization was prevented. |
| 179 CodePatcher::GetUnoptimizedStaticCallAt(caller_pc, caller_code, &ic_data); |
| 180 } else { |
| 181 // Assume an instance call. |
| 182 CodePatcher::GetInstanceCallAt(caller_pc, caller_code, &ic_data); |
| 183 } |
| 184 ASSERT(!ic_data.IsNull()); |
| 185 // Report warning only if not already reported at this location. |
| 186 if (!ic_data.IssuedJSWarning()) { |
| 187 ic_data.SetIssuedJSWarning(); |
| 188 Report::JSWarningFromFrame(caller_frame, msg); |
| 189 } |
| 190 } |
| 191 |
| 192 |
| 193 void Report::JSWarningFromIC(const ICData& ic_data, const char* msg) { |
| 194 DartFrameIterator iterator; |
| 195 StackFrame* caller_frame = iterator.NextFrame(); |
| 196 ASSERT(caller_frame != NULL); |
| 197 // Report warning only if not already reported at this location. |
| 198 if (!ic_data.IssuedJSWarning()) { |
| 199 ic_data.SetIssuedJSWarning(); |
| 200 JSWarningFromFrame(caller_frame, msg); |
| 201 } |
| 202 } |
| 203 |
| 204 |
| 205 void Report::JSWarningFromFrame(StackFrame* caller_frame, const char* msg) { |
| 206 ASSERT(caller_frame != NULL); |
| 207 ASSERT(FLAG_warn_on_javascript_compatibility); |
| 208 if (FLAG_silent_warnings) return; |
| 209 Isolate* isolate = Isolate::Current(); |
| 210 const Code& caller_code = Code::Handle(isolate, |
| 211 caller_frame->LookupDartCode()); |
| 212 ASSERT(!caller_code.IsNull()); |
| 213 const uword caller_pc = caller_frame->pc(); |
| 214 const intptr_t token_pos = caller_code.GetTokenIndexOfPC(caller_pc); |
| 215 const Function& caller = Function::Handle(isolate, caller_code.function()); |
| 216 const Script& script = Script::Handle(isolate, caller.script()); |
| 217 MessageF(kJSWarning, script, token_pos, "%s", msg); |
| 218 } |
| 219 |
| 220 |
| 221 void Report::TraceJSWarning(const Script& script, |
| 222 intptr_t token_pos, |
| 223 const String& message) { |
| 224 const int64_t micros = OS::GetCurrentTimeMicros(); |
| 225 Isolate* isolate = Isolate::Current(); |
| 226 TraceBuffer* trace_buffer = isolate->trace_buffer(); |
| 227 if (trace_buffer == NULL) { |
| 228 TraceBuffer::Init(isolate); |
| 229 trace_buffer = isolate->trace_buffer(); |
| 230 } |
| 231 JSONStream js; |
| 232 { |
| 233 JSONObject trace_warning(&js); |
| 234 trace_warning.AddProperty("type", "JSCompatibilityWarning"); |
| 235 trace_warning.AddProperty("script", script); |
| 236 trace_warning.AddProperty("tokenPos", token_pos); |
| 237 trace_warning.AddProperty("message", message); |
| 238 } |
| 239 trace_buffer->Trace(micros, js.ToCString(), true); // Already escaped. |
| 240 } |
| 241 |
| 242 } // namespace dart |
| 243 |
| OLD | NEW |