| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/report.h" | 5 #include "vm/report.h" |
| 6 | 6 |
| 7 #include "vm/code_patcher.h" | 7 #include "vm/code_patcher.h" |
| 8 #include "vm/exceptions.h" | 8 #include "vm/exceptions.h" |
| 9 #include "vm/flags.h" | 9 #include "vm/flags.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| 11 #include "vm/object.h" | 11 #include "vm/object.h" |
| 12 #include "vm/stack_frame.h" | 12 #include "vm/stack_frame.h" |
| 13 #include "vm/symbols.h" | 13 #include "vm/symbols.h" |
| 14 | 14 |
| 15 namespace dart { | 15 namespace dart { |
| 16 | 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."); | 17 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."); | 18 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); |
| 23 | 19 |
| 24 DECLARE_FLAG(bool, always_megamorphic_calls); | |
| 25 | |
| 26 RawString* Report::PrependSnippet(Kind kind, | 20 RawString* Report::PrependSnippet(Kind kind, |
| 27 const Script& script, | 21 const Script& script, |
| 28 TokenPosition token_pos, | 22 TokenPosition token_pos, |
| 29 bool report_after_token, | 23 bool report_after_token, |
| 30 const String& message) { | 24 const String& message) { |
| 31 const char* message_header; | 25 const char* message_header; |
| 32 switch (kind) { | 26 switch (kind) { |
| 33 case kWarning: message_header = "warning"; break; | 27 case kWarning: message_header = "warning"; break; |
| 34 case kJSWarning: message_header = "javascript compatibility warning"; break; | |
| 35 case kError: message_header = "error"; break; | 28 case kError: message_header = "error"; break; |
| 36 case kMalformedType: message_header = "malformed type"; break; | 29 case kMalformedType: message_header = "malformed type"; break; |
| 37 case kMalboundedType: message_header = "malbounded type"; break; | 30 case kMalboundedType: message_header = "malbounded type"; break; |
| 38 case kBailout: message_header = "bailout"; break; | 31 case kBailout: message_header = "bailout"; break; |
| 39 default: message_header = ""; UNREACHABLE(); | 32 default: message_header = ""; UNREACHABLE(); |
| 40 } | 33 } |
| 41 String& result = String::Handle(); | 34 String& result = String::Handle(); |
| 42 if (!script.IsNull()) { | 35 if (!script.IsNull()) { |
| 43 const String& script_url = String::Handle(script.url()); | 36 const String& script_url = String::Handle(script.url()); |
| 44 if (token_pos.IsReal()) { | 37 if (token_pos.IsReal()) { |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 if (kind < kError) { | 145 if (kind < kError) { |
| 153 // Reporting a warning. | 146 // Reporting a warning. |
| 154 if (FLAG_silent_warnings) { | 147 if (FLAG_silent_warnings) { |
| 155 return; | 148 return; |
| 156 } | 149 } |
| 157 if (!FLAG_warning_as_error) { | 150 if (!FLAG_warning_as_error) { |
| 158 const String& msg = String::Handle(String::NewFormattedV(format, args)); | 151 const String& msg = String::Handle(String::NewFormattedV(format, args)); |
| 159 const String& snippet_msg = String::Handle( | 152 const String& snippet_msg = String::Handle( |
| 160 PrependSnippet(kind, script, token_pos, report_after_token, msg)); | 153 PrependSnippet(kind, script, token_pos, report_after_token, msg)); |
| 161 OS::Print("%s", snippet_msg.ToCString()); | 154 OS::Print("%s", snippet_msg.ToCString()); |
| 162 if (kind == kJSWarning) { | |
| 163 TraceJSWarning(script, token_pos, msg); | |
| 164 // Do not print stacktrace if we have not executed Dart code yet. | |
| 165 if (Thread::Current()->top_exit_frame_info() != 0) { | |
| 166 const Stacktrace& stacktrace = | |
| 167 Stacktrace::Handle(Exceptions::CurrentStacktrace()); | |
| 168 intptr_t idx = 0; | |
| 169 OS::Print("%s", stacktrace.ToCStringInternal( | |
| 170 &idx, FLAG_stacktrace_depth_on_warning)); | |
| 171 } | |
| 172 } | |
| 173 return; | 155 return; |
| 174 } | 156 } |
| 175 } | 157 } |
| 176 // Reporting an error (or a warning as error). | 158 // Reporting an error (or a warning as error). |
| 177 const Error& error = Error::Handle( | 159 const Error& error = Error::Handle( |
| 178 LanguageError::NewFormattedV(Error::Handle(), // No previous error. | 160 LanguageError::NewFormattedV(Error::Handle(), // No previous error. |
| 179 script, token_pos, report_after_token, | 161 script, token_pos, report_after_token, |
| 180 kind, Heap::kNew, | 162 kind, Heap::kNew, |
| 181 format, args)); | 163 format, args)); |
| 182 if (kind == kJSWarning) { | |
| 183 Exceptions::ThrowJavascriptCompatibilityError(error.ToErrorCString()); | |
| 184 UNREACHABLE(); | |
| 185 } | |
| 186 LongJump(error); | 164 LongJump(error); |
| 187 UNREACHABLE(); | 165 UNREACHABLE(); |
| 188 } | 166 } |
| 189 | 167 |
| 190 | |
| 191 void Report::JSWarningFromNative(bool is_static_native, const char* msg) { | |
| 192 DartFrameIterator iterator; | |
| 193 iterator.NextFrame(); // Skip native call. | |
| 194 StackFrame* caller_frame = iterator.NextFrame(); | |
| 195 ASSERT(caller_frame != NULL); | |
| 196 const Code& caller_code = Code::Handle(caller_frame->LookupDartCode()); | |
| 197 ASSERT(!caller_code.IsNull()); | |
| 198 const uword caller_pc = caller_frame->pc(); | |
| 199 ICData& ic_data = ICData::Handle(); | |
| 200 if (is_static_native) { | |
| 201 // Assume an unoptimized static call. Optimization was prevented. | |
| 202 CodePatcher::GetUnoptimizedStaticCallAt(caller_pc, caller_code, &ic_data); | |
| 203 } else { | |
| 204 if (FLAG_always_megamorphic_calls) { | |
| 205 Report::JSWarningFromFrame(caller_frame, msg); | |
| 206 return; | |
| 207 } else { | |
| 208 // Assume an instance call. | |
| 209 CodePatcher::GetInstanceCallAt(caller_pc, caller_code, &ic_data); | |
| 210 } | |
| 211 } | |
| 212 ASSERT(!ic_data.IsNull()); | |
| 213 // Report warning only if not already reported at this location. | |
| 214 if (!ic_data.IssuedJSWarning()) { | |
| 215 ic_data.SetIssuedJSWarning(); | |
| 216 Report::JSWarningFromFrame(caller_frame, msg); | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 | |
| 221 void Report::JSWarningFromIC(const ICData& ic_data, const char* msg) { | |
| 222 DartFrameIterator iterator; | |
| 223 StackFrame* caller_frame = iterator.NextFrame(); | |
| 224 ASSERT(caller_frame != NULL); | |
| 225 // Report warning only if not already reported at this location. | |
| 226 if (!ic_data.IssuedJSWarning()) { | |
| 227 ic_data.SetIssuedJSWarning(); | |
| 228 JSWarningFromFrame(caller_frame, msg); | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 | |
| 233 void Report::JSWarningFromFrame(StackFrame* caller_frame, const char* msg) { | |
| 234 ASSERT(caller_frame != NULL); | |
| 235 ASSERT(FLAG_warn_on_javascript_compatibility); | |
| 236 if (FLAG_silent_warnings) return; | |
| 237 Zone* zone = Thread::Current()->zone(); | |
| 238 const Code& caller_code = Code::Handle(zone, | |
| 239 caller_frame->LookupDartCode()); | |
| 240 ASSERT(!caller_code.IsNull()); | |
| 241 const uword caller_pc = caller_frame->pc(); | |
| 242 const TokenPosition token_pos = caller_code.GetTokenIndexOfPC(caller_pc); | |
| 243 const Function& caller = Function::Handle(zone, caller_code.function()); | |
| 244 const Script& script = Script::Handle(zone, caller.script()); | |
| 245 MessageF(kJSWarning, script, token_pos, Report::AtLocation, "%s", msg); | |
| 246 } | |
| 247 | |
| 248 | |
| 249 void Report::TraceJSWarning(const Script& script, | |
| 250 TokenPosition token_pos, | |
| 251 const String& message) { | |
| 252 if (!FLAG_support_service) { | |
| 253 return; | |
| 254 } | |
| 255 const int64_t micros = OS::GetCurrentTimeMicros(); | |
| 256 Isolate* isolate = Isolate::Current(); | |
| 257 TraceBuffer* trace_buffer = isolate->trace_buffer(); | |
| 258 if (trace_buffer == NULL) { | |
| 259 TraceBuffer::Init(isolate); | |
| 260 trace_buffer = isolate->trace_buffer(); | |
| 261 } | |
| 262 JSONStream js; | |
| 263 { | |
| 264 JSONObject trace_warning(&js); | |
| 265 trace_warning.AddProperty("type", "JSCompatibilityWarning"); | |
| 266 trace_warning.AddProperty("script", script); | |
| 267 trace_warning.AddProperty("tokenPos", token_pos); | |
| 268 trace_warning.AddProperty("message", message); | |
| 269 } | |
| 270 trace_buffer->Trace(micros, js.ToCString(), true); // Already escaped. | |
| 271 } | |
| 272 | |
| 273 } // namespace dart | 168 } // namespace dart |
| 274 | 169 |
| OLD | NEW |