blob: 23deb1afebaacfee3d641b75c3fd7d38e612bda1 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/messages.h"
Steve Blocka7e24c12009-10-30 11:49:00 +00006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/api.h"
8#include "src/execution.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/isolate-inl.h"
10#include "src/string-builder.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000011
12namespace v8 {
13namespace internal {
14
15
16// If no message listeners have been registered this one is called
17// by default.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018void MessageHandler::DefaultMessageReport(Isolate* isolate,
19 const MessageLocation* loc,
Steve Blocka7e24c12009-10-30 11:49:00 +000020 Handle<Object> message_obj) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021 base::SmartArrayPointer<char> str = GetLocalizedMessage(isolate, message_obj);
Steve Blocka7e24c12009-10-30 11:49:00 +000022 if (loc == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023 PrintF("%s\n", str.get());
Steve Blocka7e24c12009-10-30 11:49:00 +000024 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000025 HandleScope scope(isolate);
26 Handle<Object> data(loc->script()->name(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027 base::SmartArrayPointer<char> data_str;
Steve Blocka7e24c12009-10-30 11:49:00 +000028 if (data->IsString())
29 data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 PrintF("%s:%i: %s\n", data_str.get() ? data_str.get() : "<unknown>",
31 loc->start_pos(), str.get());
Steve Blocka7e24c12009-10-30 11:49:00 +000032 }
33}
34
35
Steve Block1e0659c2011-05-24 12:43:12 +010036Handle<JSMessageObject> MessageHandler::MakeMessageObject(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037 Isolate* isolate, MessageTemplate::Template message,
38 MessageLocation* location, Handle<Object> argument,
Ben Murdoch3bec4d22010-07-22 14:51:16 +010039 Handle<JSArray> stack_frames) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040 Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +000041
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042 int start = -1;
43 int end = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044 Handle<Object> script_handle = factory->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045 if (location != NULL) {
46 start = location->start_pos();
47 end = location->end_pos();
48 script_handle = Script::GetWrapper(location->script());
49 } else {
50 script_handle = Script::GetWrapper(isolate->factory()->empty_script());
Steve Blocka7e24c12009-10-30 11:49:00 +000051 }
Steve Blocka7e24c12009-10-30 11:49:00 +000052
Steve Block1e0659c2011-05-24 12:43:12 +010053 Handle<Object> stack_frames_handle = stack_frames.is_null()
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 ? Handle<Object>::cast(factory->undefined_value())
Steve Block1e0659c2011-05-24 12:43:12 +010055 : Handle<Object>::cast(stack_frames);
Steve Blocka7e24c12009-10-30 11:49:00 +000056
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057 Handle<JSMessageObject> message_obj = factory->NewJSMessageObject(
58 message, argument, start, end, script_handle, stack_frames_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +000059
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060 return message_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000061}
62
63
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000064void MessageHandler::ReportMessage(Isolate* isolate, MessageLocation* loc,
65 Handle<JSMessageObject> message) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010066 // We are calling into embedder's code which can throw exceptions.
67 // Thus we need to save current exception state, reset it to the clean one
68 // and ignore scheduled exceptions callbacks can throw.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000069
70 // We pass the exception object into the message handler callback though.
71 Object* exception_object = isolate->heap()->undefined_value();
72 if (isolate->has_pending_exception()) {
73 exception_object = isolate->pending_exception();
74 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000075 Handle<Object> exception(exception_object, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076
Ben Murdoch8b112d22011-06-08 16:22:53 +010077 Isolate::ExceptionScope exception_scope(isolate);
78 isolate->clear_pending_exception();
79 isolate->set_external_caught_exception(false);
80
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 // Turn the exception on the message into a string if it is an object.
82 if (message->argument()->IsJSObject()) {
83 HandleScope scope(isolate);
84 Handle<Object> argument(message->argument(), isolate);
85
86 MaybeHandle<Object> maybe_stringified;
87 Handle<Object> stringified;
88 // Make sure we don't leak uncaught internally generated Error objects.
89 if (Object::IsErrorObject(isolate, argument)) {
90 Handle<Object> args[] = {argument};
91 maybe_stringified = Execution::TryCall(
92 isolate, isolate->no_side_effects_to_string_fun(),
93 isolate->factory()->undefined_value(), arraysize(args), args);
94 } else {
95 v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
96 catcher.SetVerbose(false);
97 catcher.SetCaptureMessage(false);
98
99 maybe_stringified = Object::ToString(isolate, argument);
100 }
101
102 if (!maybe_stringified.ToHandle(&stringified)) {
103 stringified = isolate->factory()->NewStringFromAsciiChecked("exception");
104 }
105 message->set_argument(*stringified);
106 }
107
Steve Blocka7e24c12009-10-30 11:49:00 +0000108 v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109 v8::Local<v8::Value> api_exception_obj = v8::Utils::ToLocal(exception);
Steve Blocka7e24c12009-10-30 11:49:00 +0000110
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 v8::NeanderArray global_listeners(isolate->factory()->message_listeners());
Steve Blocka7e24c12009-10-30 11:49:00 +0000112 int global_length = global_listeners.length();
113 if (global_length == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 DefaultMessageReport(isolate, loc, message);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100115 if (isolate->has_scheduled_exception()) {
116 isolate->clear_scheduled_exception();
117 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 } else {
119 for (int i = 0; i < global_length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 if (global_listeners.get(i)->IsUndefined()) continue;
122 v8::NeanderObject listener(JSObject::cast(global_listeners.get(i)));
Ben Murdoch257744e2011-11-30 15:57:28 +0000123 Handle<Foreign> callback_obj(Foreign::cast(listener.get(0)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 v8::MessageCallback callback =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100125 FUNCTION_CAST<v8::MessageCallback>(callback_obj->foreign_address());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 Handle<Object> callback_data(listener.get(1), isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100127 {
128 // Do not allow exceptions to propagate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 callback(api_message_obj, callback_data->IsUndefined()
131 ? api_exception_obj
132 : v8::Utils::ToLocal(callback_data));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100133 }
134 if (isolate->has_scheduled_exception()) {
135 isolate->clear_scheduled_exception();
136 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000137 }
138 }
139}
140
141
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142Handle<String> MessageHandler::GetMessage(Isolate* isolate,
143 Handle<Object> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 Handle<JSMessageObject> message = Handle<JSMessageObject>::cast(data);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 Handle<Object> arg = Handle<Object>(message->argument(), isolate);
146 return MessageTemplate::FormatMessage(isolate, message->type(), arg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000147}
148
149
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150base::SmartArrayPointer<char> MessageHandler::GetLocalizedMessage(
151 Isolate* isolate, Handle<Object> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 HandleScope scope(isolate);
153 return GetMessage(isolate, data)->ToCString(DISALLOW_NULLS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000154}
155
156
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000157CallSite::CallSite(Isolate* isolate, Handle<JSObject> call_site_obj)
158 : isolate_(isolate) {
159 Handle<Object> maybe_function = JSObject::GetDataProperty(
160 call_site_obj, isolate->factory()->call_site_function_symbol());
161 if (!maybe_function->IsJSFunction()) return;
162
163 fun_ = Handle<JSFunction>::cast(maybe_function);
164 receiver_ = JSObject::GetDataProperty(
165 call_site_obj, isolate->factory()->call_site_receiver_symbol());
166 CHECK(JSObject::GetDataProperty(
167 call_site_obj, isolate->factory()->call_site_position_symbol())
168 ->ToInt32(&pos_));
169}
170
171
172Handle<Object> CallSite::GetFileName() {
173 Handle<Object> script(fun_->shared()->script(), isolate_);
174 if (script->IsScript()) {
175 return Handle<Object>(Handle<Script>::cast(script)->name(), isolate_);
176 }
177 return isolate_->factory()->null_value();
178}
179
180
181Handle<Object> CallSite::GetFunctionName() {
182 Handle<String> result = JSFunction::GetName(fun_);
183 if (result->length() != 0) return result;
184
185 Handle<Object> script(fun_->shared()->script(), isolate_);
186 if (script->IsScript() &&
187 Handle<Script>::cast(script)->compilation_type() ==
188 Script::COMPILATION_TYPE_EVAL) {
189 return isolate_->factory()->eval_string();
190 }
191 return isolate_->factory()->null_value();
192}
193
194
195Handle<Object> CallSite::GetScriptNameOrSourceUrl() {
196 Handle<Object> script_obj(fun_->shared()->script(), isolate_);
197 if (script_obj->IsScript()) {
198 Handle<Script> script = Handle<Script>::cast(script_obj);
199 Object* source_url = script->source_url();
200 if (source_url->IsString()) return Handle<Object>(source_url, isolate_);
201 return Handle<Object>(script->name(), isolate_);
202 }
203 return isolate_->factory()->null_value();
204}
205
206
207bool CheckMethodName(Isolate* isolate, Handle<JSObject> obj, Handle<Name> name,
208 Handle<JSFunction> fun,
209 LookupIterator::Configuration config) {
210 LookupIterator iter =
211 LookupIterator::PropertyOrElement(isolate, obj, name, config);
212 if (iter.state() == LookupIterator::DATA) {
213 return iter.GetDataValue().is_identical_to(fun);
214 } else if (iter.state() == LookupIterator::ACCESSOR) {
215 Handle<Object> accessors = iter.GetAccessors();
216 if (accessors->IsAccessorPair()) {
217 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(accessors);
218 return pair->getter() == *fun || pair->setter() == *fun;
219 }
220 }
221 return false;
222}
223
224
225Handle<Object> CallSite::GetMethodName() {
226 MaybeHandle<JSReceiver> maybe = Object::ToObject(isolate_, receiver_);
227 Handle<JSReceiver> receiver;
228 if (!maybe.ToHandle(&receiver) || !receiver->IsJSObject()) {
229 return isolate_->factory()->null_value();
230 }
231
232 Handle<JSObject> obj = Handle<JSObject>::cast(receiver);
233 Handle<Object> function_name(fun_->shared()->name(), isolate_);
234 if (function_name->IsName()) {
235 Handle<Name> name = Handle<Name>::cast(function_name);
236 if (CheckMethodName(isolate_, obj, name, fun_,
237 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR))
238 return name;
239 }
240
241 HandleScope outer_scope(isolate_);
242 Handle<Object> result;
243 for (PrototypeIterator iter(isolate_, obj,
244 PrototypeIterator::START_AT_RECEIVER);
245 !iter.IsAtEnd(); iter.Advance()) {
246 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
247 if (!current->IsJSObject()) break;
248 Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
249 if (current_obj->IsAccessCheckNeeded()) break;
250 Handle<FixedArray> keys = JSObject::GetEnumPropertyKeys(current_obj, false);
251 for (int i = 0; i < keys->length(); i++) {
252 HandleScope inner_scope(isolate_);
253 if (!keys->get(i)->IsName()) continue;
254 Handle<Name> name_key(Name::cast(keys->get(i)), isolate_);
255 if (!CheckMethodName(isolate_, current_obj, name_key, fun_,
256 LookupIterator::OWN_SKIP_INTERCEPTOR))
257 continue;
258 // Return null in case of duplicates to avoid confusion.
259 if (!result.is_null()) return isolate_->factory()->null_value();
260 result = inner_scope.CloseAndEscape(name_key);
261 }
262 }
263
264 if (!result.is_null()) return outer_scope.CloseAndEscape(result);
265 return isolate_->factory()->null_value();
266}
267
268
269int CallSite::GetLineNumber() {
270 if (pos_ >= 0) {
271 Handle<Object> script_obj(fun_->shared()->script(), isolate_);
272 if (script_obj->IsScript()) {
273 Handle<Script> script = Handle<Script>::cast(script_obj);
274 return Script::GetLineNumber(script, pos_) + 1;
275 }
276 }
277 return -1;
278}
279
280
281int CallSite::GetColumnNumber() {
282 if (pos_ >= 0) {
283 Handle<Object> script_obj(fun_->shared()->script(), isolate_);
284 if (script_obj->IsScript()) {
285 Handle<Script> script = Handle<Script>::cast(script_obj);
286 return Script::GetColumnNumber(script, pos_) + 1;
287 }
288 }
289 return -1;
290}
291
292
293bool CallSite::IsNative() {
294 Handle<Object> script(fun_->shared()->script(), isolate_);
295 return script->IsScript() &&
296 Handle<Script>::cast(script)->type() == Script::TYPE_NATIVE;
297}
298
299
300bool CallSite::IsToplevel() {
301 return receiver_->IsJSGlobalProxy() || receiver_->IsNull() ||
302 receiver_->IsUndefined();
303}
304
305
306bool CallSite::IsEval() {
307 Handle<Object> script(fun_->shared()->script(), isolate_);
308 return script->IsScript() &&
309 Handle<Script>::cast(script)->compilation_type() ==
310 Script::COMPILATION_TYPE_EVAL;
311}
312
313
314bool CallSite::IsConstructor() {
315 if (!receiver_->IsJSObject()) return false;
316 Handle<Object> constructor =
317 JSReceiver::GetDataProperty(Handle<JSObject>::cast(receiver_),
318 isolate_->factory()->constructor_string());
319 return constructor.is_identical_to(fun_);
320}
321
322
323Handle<String> MessageTemplate::FormatMessage(Isolate* isolate,
324 int template_index,
325 Handle<Object> arg) {
326 Factory* factory = isolate->factory();
327 Handle<String> result_string;
328 if (arg->IsString()) {
329 result_string = Handle<String>::cast(arg);
330 } else {
331 Handle<JSFunction> fun = isolate->no_side_effects_to_string_fun();
332
333 MaybeHandle<Object> maybe_result =
334 Execution::TryCall(isolate, fun, factory->undefined_value(), 1, &arg);
335 Handle<Object> result;
336 if (!maybe_result.ToHandle(&result) || !result->IsString()) {
337 return factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("<error>"));
338 }
339 result_string = Handle<String>::cast(result);
340 }
341 MaybeHandle<String> maybe_result_string = MessageTemplate::FormatMessage(
342 template_index, result_string, factory->empty_string(),
343 factory->empty_string());
344 if (!maybe_result_string.ToHandle(&result_string)) {
345 return factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("<error>"));
346 }
347 // A string that has been obtained from JS code in this way is
348 // likely to be a complicated ConsString of some sort. We flatten it
349 // here to improve the efficiency of converting it to a C string and
350 // other operations that are likely to take place (see GetLocalizedMessage
351 // for example).
352 return String::Flatten(result_string);
353}
354
355
356const char* MessageTemplate::TemplateString(int template_index) {
357 switch (template_index) {
358#define CASE(NAME, STRING) \
359 case k##NAME: \
360 return STRING;
361 MESSAGE_TEMPLATES(CASE)
362#undef CASE
363 case kLastMessage:
364 default:
365 return NULL;
366 }
367}
368
369
370MaybeHandle<String> MessageTemplate::FormatMessage(int template_index,
371 Handle<String> arg0,
372 Handle<String> arg1,
373 Handle<String> arg2) {
374 Isolate* isolate = arg0->GetIsolate();
375 const char* template_string = TemplateString(template_index);
376 if (template_string == NULL) {
377 isolate->ThrowIllegalOperation();
378 return MaybeHandle<String>();
379 }
380
381 IncrementalStringBuilder builder(isolate);
382
383 unsigned int i = 0;
384 Handle<String> args[] = {arg0, arg1, arg2};
385 for (const char* c = template_string; *c != '\0'; c++) {
386 if (*c == '%') {
387 // %% results in verbatim %.
388 if (*(c + 1) == '%') {
389 c++;
390 builder.AppendCharacter('%');
391 } else {
392 DCHECK(i < arraysize(args));
393 Handle<String> arg = args[i++];
394 builder.AppendString(arg);
395 }
396 } else {
397 builder.AppendCharacter(*c);
398 }
399 }
400
401 return builder.Finish();
402}
403
404
405} // namespace internal
406} // namespace v8