OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/messages.h" | 5 #include "src/messages.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/execution.h" | 10 #include "src/execution.h" |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 Handle<Object> arg = Handle<Object>(message->argument(), isolate); | 157 Handle<Object> arg = Handle<Object>(message->argument(), isolate); |
158 return MessageTemplate::FormatMessage(isolate, message->type(), arg); | 158 return MessageTemplate::FormatMessage(isolate, message->type(), arg); |
159 } | 159 } |
160 | 160 |
161 std::unique_ptr<char[]> MessageHandler::GetLocalizedMessage( | 161 std::unique_ptr<char[]> MessageHandler::GetLocalizedMessage( |
162 Isolate* isolate, Handle<Object> data) { | 162 Isolate* isolate, Handle<Object> data) { |
163 HandleScope scope(isolate); | 163 HandleScope scope(isolate); |
164 return GetMessage(isolate, data)->ToCString(DISALLOW_NULLS); | 164 return GetMessage(isolate, data)->ToCString(DISALLOW_NULLS); |
165 } | 165 } |
166 | 166 |
167 | |
168 CallSite::CallSite(Isolate* isolate, Handle<JSObject> call_site_obj) | |
169 : isolate_(isolate) { | |
170 Handle<Object> maybe_function = JSObject::GetDataProperty( | |
171 call_site_obj, isolate->factory()->call_site_function_symbol()); | |
172 if (maybe_function->IsJSFunction()) { | |
173 // javascript | |
174 fun_ = Handle<JSFunction>::cast(maybe_function); | |
175 receiver_ = JSObject::GetDataProperty( | |
176 call_site_obj, isolate->factory()->call_site_receiver_symbol()); | |
177 } else { | |
178 Handle<Object> maybe_wasm_func_index = JSObject::GetDataProperty( | |
179 call_site_obj, isolate->factory()->call_site_wasm_func_index_symbol()); | |
180 if (!maybe_wasm_func_index->IsSmi()) { | |
181 // invalid: neither javascript nor wasm | |
182 return; | |
183 } | |
184 // wasm | |
185 wasm_obj_ = Handle<JSObject>::cast(JSObject::GetDataProperty( | |
186 call_site_obj, isolate->factory()->call_site_wasm_obj_symbol())); | |
187 wasm_func_index_ = Smi::cast(*maybe_wasm_func_index)->value(); | |
188 DCHECK(static_cast<int>(wasm_func_index_) >= 0); | |
189 } | |
190 | |
191 CHECK(JSObject::GetDataProperty( | |
192 call_site_obj, isolate->factory()->call_site_position_symbol()) | |
193 ->ToInt32(&pos_)); | |
194 } | |
195 | |
196 | |
197 Handle<Object> CallSite::GetFileName() { | |
198 if (!IsJavaScript()) return isolate_->factory()->null_value(); | |
199 Object* script = fun_->shared()->script(); | |
200 if (!script->IsScript()) return isolate_->factory()->null_value(); | |
201 return Handle<Object>(Script::cast(script)->name(), isolate_); | |
202 } | |
203 | |
204 | |
205 Handle<Object> CallSite::GetFunctionName() { | |
206 if (IsWasm()) { | |
207 return wasm::GetWasmFunctionNameOrNull(isolate_, wasm_obj_, | |
208 wasm_func_index_); | |
209 } | |
210 Handle<String> result = JSFunction::GetName(fun_); | |
211 if (result->length() != 0) return result; | |
212 | |
213 Handle<Object> script(fun_->shared()->script(), isolate_); | |
214 if (script->IsScript() && | |
215 Handle<Script>::cast(script)->compilation_type() == | |
216 Script::COMPILATION_TYPE_EVAL) { | |
217 return isolate_->factory()->eval_string(); | |
218 } | |
219 return isolate_->factory()->null_value(); | |
220 } | |
221 | |
222 Handle<Object> CallSite::GetScriptNameOrSourceUrl() { | |
223 if (!IsJavaScript()) return isolate_->factory()->null_value(); | |
224 Object* script_obj = fun_->shared()->script(); | |
225 if (!script_obj->IsScript()) return isolate_->factory()->null_value(); | |
226 Handle<Script> script(Script::cast(script_obj), isolate_); | |
227 Object* source_url = script->source_url(); | |
228 if (source_url->IsString()) return Handle<Object>(source_url, isolate_); | |
229 return Handle<Object>(script->name(), isolate_); | |
230 } | |
231 | |
232 bool CheckMethodName(Isolate* isolate, Handle<JSObject> obj, Handle<Name> name, | |
233 Handle<JSFunction> fun, | |
234 LookupIterator::Configuration config) { | |
235 LookupIterator iter = | |
236 LookupIterator::PropertyOrElement(isolate, obj, name, config); | |
237 if (iter.state() == LookupIterator::DATA) { | |
238 return iter.GetDataValue().is_identical_to(fun); | |
239 } else if (iter.state() == LookupIterator::ACCESSOR) { | |
240 Handle<Object> accessors = iter.GetAccessors(); | |
241 if (accessors->IsAccessorPair()) { | |
242 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(accessors); | |
243 return pair->getter() == *fun || pair->setter() == *fun; | |
244 } | |
245 } | |
246 return false; | |
247 } | |
248 | |
249 | |
250 Handle<Object> CallSite::GetMethodName() { | |
251 if (!IsJavaScript() || receiver_->IsNull(isolate_) || | |
252 receiver_->IsUndefined(isolate_)) { | |
253 return isolate_->factory()->null_value(); | |
254 } | |
255 Handle<JSReceiver> receiver = | |
256 Object::ToObject(isolate_, receiver_).ToHandleChecked(); | |
257 if (!receiver->IsJSObject()) { | |
258 return isolate_->factory()->null_value(); | |
259 } | |
260 | |
261 Handle<JSObject> obj = Handle<JSObject>::cast(receiver); | |
262 Handle<Object> function_name(fun_->shared()->name(), isolate_); | |
263 if (function_name->IsString()) { | |
264 Handle<String> name = Handle<String>::cast(function_name); | |
265 // ES2015 gives getters and setters name prefixes which must | |
266 // be stripped to find the property name. | |
267 if (name->IsUtf8EqualTo(CStrVector("get "), true) || | |
268 name->IsUtf8EqualTo(CStrVector("set "), true)) { | |
269 name = isolate_->factory()->NewProperSubString(name, 4, name->length()); | |
270 } | |
271 if (CheckMethodName(isolate_, obj, name, fun_, | |
272 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR)) { | |
273 return name; | |
274 } | |
275 } | |
276 | |
277 HandleScope outer_scope(isolate_); | |
278 Handle<Object> result; | |
279 for (PrototypeIterator iter(isolate_, obj, kStartAtReceiver); !iter.IsAtEnd(); | |
280 iter.Advance()) { | |
281 Handle<Object> current = PrototypeIterator::GetCurrent(iter); | |
282 if (!current->IsJSObject()) break; | |
283 Handle<JSObject> current_obj = Handle<JSObject>::cast(current); | |
284 if (current_obj->IsAccessCheckNeeded()) break; | |
285 Handle<FixedArray> keys = | |
286 KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, current_obj); | |
287 for (int i = 0; i < keys->length(); i++) { | |
288 HandleScope inner_scope(isolate_); | |
289 if (!keys->get(i)->IsName()) continue; | |
290 Handle<Name> name_key(Name::cast(keys->get(i)), isolate_); | |
291 if (!CheckMethodName(isolate_, current_obj, name_key, fun_, | |
292 LookupIterator::OWN_SKIP_INTERCEPTOR)) | |
293 continue; | |
294 // Return null in case of duplicates to avoid confusion. | |
295 if (!result.is_null()) return isolate_->factory()->null_value(); | |
296 result = inner_scope.CloseAndEscape(name_key); | |
297 } | |
298 } | |
299 | |
300 if (!result.is_null()) return outer_scope.CloseAndEscape(result); | |
301 return isolate_->factory()->null_value(); | |
302 } | |
303 | |
304 Handle<Object> CallSite::GetTypeName() { | |
305 // TODO(jgruber): Check for strict/constructor here as in | |
306 // CallSitePrototypeGetThis. | |
307 | |
308 if (receiver_->IsNull(isolate_) || receiver_->IsUndefined(isolate_)) | |
309 return isolate_->factory()->null_value(); | |
310 | |
311 if (receiver_->IsJSProxy()) return isolate_->factory()->Proxy_string(); | |
312 | |
313 Handle<JSReceiver> receiver_object = | |
314 Object::ToObject(isolate_, receiver_).ToHandleChecked(); | |
315 return JSReceiver::GetConstructorName(receiver_object); | |
316 } | |
317 | |
318 namespace { | 167 namespace { |
319 | 168 |
320 Object* EvalFromFunctionName(Isolate* isolate, Handle<Script> script) { | 169 MaybeHandle<Object> ConstructCallSite(Isolate* isolate, |
321 if (script->eval_from_shared()->IsUndefined(isolate)) | 170 Handle<StackTraceFrame> frame) { |
322 return *isolate->factory()->undefined_value(); | 171 // Create the JS object. |
323 | 172 |
324 Handle<SharedFunctionInfo> shared( | 173 Handle<JSFunction> target = |
325 SharedFunctionInfo::cast(script->eval_from_shared())); | 174 handle(isolate->native_context()->callsite_function(), isolate); |
326 // Find the name of the function calling eval. | |
327 if (shared->name()->BooleanValue()) { | |
328 return shared->name(); | |
329 } | |
330 | 175 |
331 return shared->inferred_name(); | 176 Handle<JSObject> obj; |
| 177 ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, JSObject::New(target, target), |
| 178 Object); |
| 179 |
| 180 RETURN_ON_EXCEPTION( |
| 181 isolate, |
| 182 JSObject::SetOwnPropertyIgnoreAttributes( |
| 183 obj, isolate->factory()->call_site_frame_symbol(), frame, DONT_ENUM), |
| 184 Object); |
| 185 |
| 186 return obj; |
332 } | 187 } |
333 | 188 |
334 Object* EvalFromScript(Isolate* isolate, Handle<Script> script) { | |
335 if (script->eval_from_shared()->IsUndefined(isolate)) | |
336 return *isolate->factory()->undefined_value(); | |
337 | |
338 Handle<SharedFunctionInfo> eval_from_shared( | |
339 SharedFunctionInfo::cast(script->eval_from_shared())); | |
340 return eval_from_shared->script()->IsScript() | |
341 ? eval_from_shared->script() | |
342 : *isolate->factory()->undefined_value(); | |
343 } | |
344 | |
345 MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) { | |
346 Handle<Object> sourceURL = Script::GetNameOrSourceURL(script); | |
347 if (!sourceURL->IsUndefined(isolate)) { | |
348 DCHECK(sourceURL->IsString()); | |
349 return Handle<String>::cast(sourceURL); | |
350 } | |
351 | |
352 IncrementalStringBuilder builder(isolate); | |
353 builder.AppendCString("eval at "); | |
354 | |
355 Handle<Object> eval_from_function_name = | |
356 handle(EvalFromFunctionName(isolate, script), isolate); | |
357 if (eval_from_function_name->BooleanValue()) { | |
358 Handle<String> str; | |
359 ASSIGN_RETURN_ON_EXCEPTION( | |
360 isolate, str, Object::ToString(isolate, eval_from_function_name), | |
361 String); | |
362 builder.AppendString(str); | |
363 } else { | |
364 builder.AppendCString("<anonymous>"); | |
365 } | |
366 | |
367 Handle<Object> eval_from_script_obj = | |
368 handle(EvalFromScript(isolate, script), isolate); | |
369 if (eval_from_script_obj->IsScript()) { | |
370 Handle<Script> eval_from_script = | |
371 Handle<Script>::cast(eval_from_script_obj); | |
372 builder.AppendCString(" ("); | |
373 if (eval_from_script->compilation_type() == Script::COMPILATION_TYPE_EVAL) { | |
374 // Eval script originated from another eval. | |
375 Handle<String> str; | |
376 ASSIGN_RETURN_ON_EXCEPTION( | |
377 isolate, str, FormatEvalOrigin(isolate, eval_from_script), String); | |
378 builder.AppendString(str); | |
379 } else { | |
380 DCHECK(eval_from_script->compilation_type() != | |
381 Script::COMPILATION_TYPE_EVAL); | |
382 // eval script originated from "real" source. | |
383 Handle<Object> name_obj = handle(eval_from_script->name(), isolate); | |
384 if (eval_from_script->name()->IsString()) { | |
385 builder.AppendString(Handle<String>::cast(name_obj)); | |
386 | |
387 Script::PositionInfo info; | |
388 if (eval_from_script->GetPositionInfo(script->GetEvalPosition(), &info, | |
389 Script::NO_OFFSET)) { | |
390 builder.AppendCString(":"); | |
391 | |
392 Handle<String> str = isolate->factory()->NumberToString( | |
393 handle(Smi::FromInt(info.line + 1), isolate)); | |
394 builder.AppendString(str); | |
395 | |
396 builder.AppendCString(":"); | |
397 | |
398 str = isolate->factory()->NumberToString( | |
399 handle(Smi::FromInt(info.column + 1), isolate)); | |
400 builder.AppendString(str); | |
401 } | |
402 } else { | |
403 DCHECK(!eval_from_script->name()->IsString()); | |
404 builder.AppendCString("unknown source"); | |
405 } | |
406 } | |
407 builder.AppendCString(")"); | |
408 } | |
409 | |
410 Handle<String> result; | |
411 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String); | |
412 return result; | |
413 } | |
414 | |
415 } // namespace | |
416 | |
417 Handle<Object> CallSite::GetEvalOrigin() { | |
418 if (IsWasm()) return isolate_->factory()->undefined_value(); | |
419 DCHECK(IsJavaScript()); | |
420 | |
421 Handle<Object> script = handle(fun_->shared()->script(), isolate_); | |
422 if (!script->IsScript()) return isolate_->factory()->undefined_value(); | |
423 | |
424 return FormatEvalOrigin(isolate_, Handle<Script>::cast(script)) | |
425 .ToHandleChecked(); | |
426 } | |
427 | |
428 int CallSite::GetLineNumber() { | |
429 if (pos_ >= 0 && IsJavaScript()) { | |
430 Handle<Object> script_obj(fun_->shared()->script(), isolate_); | |
431 if (script_obj->IsScript()) { | |
432 Handle<Script> script = Handle<Script>::cast(script_obj); | |
433 return Script::GetLineNumber(script, pos_) + 1; | |
434 } | |
435 } | |
436 return -1; | |
437 } | |
438 | |
439 | |
440 int CallSite::GetColumnNumber() { | |
441 if (pos_ >= 0 && IsJavaScript()) { | |
442 Handle<Object> script_obj(fun_->shared()->script(), isolate_); | |
443 if (script_obj->IsScript()) { | |
444 Handle<Script> script = Handle<Script>::cast(script_obj); | |
445 return Script::GetColumnNumber(script, pos_) + 1; | |
446 } | |
447 } | |
448 return -1; | |
449 } | |
450 | |
451 | |
452 bool CallSite::IsNative() { | |
453 if (!IsJavaScript()) return false; | |
454 Handle<Object> script(fun_->shared()->script(), isolate_); | |
455 return script->IsScript() && | |
456 Handle<Script>::cast(script)->type() == Script::TYPE_NATIVE; | |
457 } | |
458 | |
459 | |
460 bool CallSite::IsToplevel() { | |
461 if (IsWasm()) return false; | |
462 return receiver_->IsJSGlobalProxy() || receiver_->IsNull(isolate_) || | |
463 receiver_->IsUndefined(isolate_); | |
464 } | |
465 | |
466 | |
467 bool CallSite::IsEval() { | |
468 if (!IsJavaScript()) return false; | |
469 Handle<Object> script(fun_->shared()->script(), isolate_); | |
470 return script->IsScript() && | |
471 Handle<Script>::cast(script)->compilation_type() == | |
472 Script::COMPILATION_TYPE_EVAL; | |
473 } | |
474 | |
475 | |
476 bool CallSite::IsConstructor() { | |
477 // Builtin exit frames mark constructors by passing a special symbol as the | |
478 // receiver. | |
479 Object* ctor_symbol = isolate_->heap()->call_site_constructor_symbol(); | |
480 if (*receiver_ == ctor_symbol) return true; | |
481 if (!IsJavaScript() || !receiver_->IsJSObject()) return false; | |
482 Handle<Object> constructor = | |
483 JSReceiver::GetDataProperty(Handle<JSObject>::cast(receiver_), | |
484 isolate_->factory()->constructor_string()); | |
485 return constructor.is_identical_to(fun_); | |
486 } | |
487 | |
488 namespace { | |
489 | |
490 // Convert the raw frames as written by Isolate::CaptureSimpleStackTrace into | 189 // Convert the raw frames as written by Isolate::CaptureSimpleStackTrace into |
491 // a vector of JS CallSite objects. | 190 // a vector of StackTraceFrame objects. |
492 MaybeHandle<FixedArray> GetStackFrames(Isolate* isolate, | 191 Handle<FixedArray> ToStackTraceFrames(Isolate* isolate, |
493 Handle<Object> raw_stack) { | 192 Handle<Object> raw_stack) { |
494 DCHECK(raw_stack->IsJSArray()); | 193 DCHECK(raw_stack->IsJSArray()); |
495 Handle<JSArray> raw_stack_array = Handle<JSArray>::cast(raw_stack); | 194 Handle<JSArray> raw_stack_array = Handle<JSArray>::cast(raw_stack); |
496 | 195 |
497 DCHECK(raw_stack_array->elements()->IsFixedArray()); | 196 DCHECK(raw_stack_array->elements()->IsFixedArray()); |
498 Handle<FixedArray> raw_stack_elements = | 197 Handle<FixedArray> elements = |
499 handle(FixedArray::cast(raw_stack_array->elements()), isolate); | 198 handle(FixedArray::cast(raw_stack_array->elements()), isolate); |
500 | 199 |
501 const int raw_stack_len = raw_stack_elements->length(); | 200 const int raw_stack_len = elements->length(); |
502 DCHECK(raw_stack_len % 4 == 1); // Multiples of 4 plus sloppy frames count. | 201 DCHECK_EQ(0, raw_stack_len % EncodedStackTraceFrame::kElementsPerFrame); |
503 const int frame_count = (raw_stack_len - 1) / 4; | 202 const int frame_count = |
504 | 203 raw_stack_len / EncodedStackTraceFrame::kElementsPerFrame; |
505 Handle<Object> sloppy_frames_obj = | |
506 FixedArray::get(*raw_stack_elements, 0, isolate); | |
507 int sloppy_frames = Handle<Smi>::cast(sloppy_frames_obj)->value(); | |
508 | 204 |
509 int dst_ix = 0; | 205 int dst_ix = 0; |
510 Handle<FixedArray> frames = isolate->factory()->NewFixedArray(frame_count); | 206 Handle<FixedArray> frames = isolate->factory()->NewFixedArray(frame_count); |
511 for (int i = 1; i < raw_stack_len; i += 4) { | 207 for (int i = 0; i < raw_stack_len; |
512 Handle<Object> recv = FixedArray::get(*raw_stack_elements, i, isolate); | 208 i += EncodedStackTraceFrame::kElementsPerFrame) { |
513 Handle<Object> fun = FixedArray::get(*raw_stack_elements, i + 1, isolate); | 209 Handle<StackTraceFrame> frame = isolate->factory()->NewStackTraceFrame(); |
514 Handle<AbstractCode> code = Handle<AbstractCode>::cast( | |
515 FixedArray::get(*raw_stack_elements, i + 2, isolate)); | |
516 Handle<Smi> pc = | |
517 Handle<Smi>::cast(FixedArray::get(*raw_stack_elements, i + 3, isolate)); | |
518 | 210 |
519 Handle<Object> pos = | 211 using ESTF = EncodedStackTraceFrame; |
520 (fun->IsSmi() && pc->value() < 0) | |
521 ? handle(Smi::FromInt(-1 - pc->value()), isolate) | |
522 : handle(Smi::FromInt(code->SourcePosition(pc->value())), isolate); | |
523 | 212 |
524 sloppy_frames--; | 213 AbstractCode* code = |
525 Handle<Object> strict = isolate->factory()->ToBoolean(sloppy_frames < 0); | 214 AbstractCode::cast(elements->get(i + ESTF::kCodeOffset)); |
| 215 const int offset = |
| 216 Smi::cast(elements->get(i + ESTF::kOffsetOffset))->value(); |
| 217 const int flags = Smi::cast(elements->get(i + ESTF::kFlagsOffset))->value(); |
526 | 218 |
527 Handle<Object> callsite; | 219 frame->set_flags(flags); |
528 ASSIGN_RETURN_ON_EXCEPTION( | 220 frame->set_abstract_code(code); |
529 isolate, callsite, | 221 frame->set_offset(offset); |
530 CallSiteUtils::Construct(isolate, recv, fun, pos, strict), FixedArray); | |
531 | 222 |
532 frames->set(dst_ix++, *callsite); | 223 if (frame->IsWasmFrame()) { |
| 224 Object* wasm_object = elements->get(i + ESTF::kWasmObjectOffset); |
| 225 Object* wasm_function_index = |
| 226 elements->get(i + ESTF::kWasmFunctionIndexOffset); |
| 227 |
| 228 frame->set_wasm_object(wasm_object); |
| 229 frame->set_wasm_function_index(Smi::cast(wasm_function_index)->value()); |
| 230 } else { |
| 231 DCHECK(frame->IsJavaScriptFrame()); |
| 232 Object* recv = elements->get(i + ESTF::kReceiverOffset); |
| 233 Object* fun = elements->get(i + ESTF::kFunctionOffset); |
| 234 |
| 235 frame->set_receiver(recv); |
| 236 frame->set_function(JSFunction::cast(fun)); |
| 237 } |
| 238 |
| 239 frames->set(dst_ix++, *frame); |
533 } | 240 } |
534 | 241 |
535 DCHECK_EQ(frame_count, dst_ix); | 242 DCHECK_EQ(frame_count, dst_ix); |
536 return frames; | 243 return frames; |
537 } | 244 } |
538 | 245 |
| 246 // Convert StackTraceFrames into JS CallSite objects. |
| 247 MaybeHandle<JSArray> ToCallSites(Isolate* isolate, |
| 248 Handle<FixedArray> elements) { |
| 249 const int frame_count = elements->length(); |
| 250 Handle<FixedArray> frames = isolate->factory()->NewFixedArray(frame_count); |
| 251 |
| 252 for (int i = 0; i < frame_count; i++) { |
| 253 auto frame = |
| 254 Handle<StackTraceFrame>::cast(FixedArray::get(*elements, i, isolate)); |
| 255 |
| 256 Handle<Object> callsite; |
| 257 ASSIGN_RETURN_ON_EXCEPTION(isolate, callsite, |
| 258 ConstructCallSite(isolate, frame), JSArray); |
| 259 |
| 260 frames->set(i, *callsite); |
| 261 } |
| 262 |
| 263 return isolate->factory()->NewJSArrayWithElements(frames); |
| 264 } |
| 265 |
539 MaybeHandle<Object> AppendErrorString(Isolate* isolate, Handle<Object> error, | 266 MaybeHandle<Object> AppendErrorString(Isolate* isolate, Handle<Object> error, |
540 IncrementalStringBuilder* builder) { | 267 IncrementalStringBuilder* builder) { |
541 MaybeHandle<String> err_str = | 268 MaybeHandle<String> err_str = |
542 ErrorUtils::ToString(isolate, Handle<Object>::cast(error)); | 269 ErrorUtils::ToString(isolate, Handle<Object>::cast(error)); |
543 if (err_str.is_null()) { | 270 if (err_str.is_null()) { |
544 // Error.toString threw. Try to return a string representation of the thrown | 271 // Error.toString threw. Try to return a string representation of the thrown |
545 // exception instead. | 272 // exception instead. |
546 | 273 |
547 DCHECK(isolate->has_pending_exception()); | 274 DCHECK(isolate->has_pending_exception()); |
548 Handle<Object> pending_exception = | 275 Handle<Object> pending_exception = |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
583 | 310 |
584 DISALLOW_COPY_AND_ASSIGN(PrepareStackTraceScope); | 311 DISALLOW_COPY_AND_ASSIGN(PrepareStackTraceScope); |
585 }; | 312 }; |
586 | 313 |
587 } // namespace | 314 } // namespace |
588 | 315 |
589 // static | 316 // static |
590 MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate, | 317 MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate, |
591 Handle<JSObject> error, | 318 Handle<JSObject> error, |
592 Handle<Object> raw_stack) { | 319 Handle<Object> raw_stack) { |
593 // Create JS CallSite objects from the raw stack frame array. | 320 Handle<FixedArray> frames = ToStackTraceFrames(isolate, raw_stack); |
594 | |
595 Handle<FixedArray> frames; | |
596 ASSIGN_RETURN_ON_EXCEPTION(isolate, frames, | |
597 GetStackFrames(isolate, raw_stack), Object); | |
598 | 321 |
599 // If there's a user-specified "prepareStackFrames" function, call it on the | 322 // If there's a user-specified "prepareStackFrames" function, call it on the |
600 // frames and use its result. | 323 // frames and use its result. |
601 | 324 |
602 Handle<JSFunction> global_error = isolate->error_function(); | 325 Handle<JSFunction> global_error = isolate->error_function(); |
603 Handle<Object> prepare_stack_trace; | 326 Handle<Object> prepare_stack_trace; |
604 ASSIGN_RETURN_ON_EXCEPTION( | 327 ASSIGN_RETURN_ON_EXCEPTION( |
605 isolate, prepare_stack_trace, | 328 isolate, prepare_stack_trace, |
606 JSFunction::GetProperty(isolate, global_error, "prepareStackTrace"), | 329 JSFunction::GetProperty(isolate, global_error, "prepareStackTrace"), |
607 Object); | 330 Object); |
608 | 331 |
609 const bool in_recursion = isolate->formatting_stack_trace(); | 332 const bool in_recursion = isolate->formatting_stack_trace(); |
610 if (prepare_stack_trace->IsJSFunction() && !in_recursion) { | 333 if (prepare_stack_trace->IsJSFunction() && !in_recursion) { |
611 PrepareStackTraceScope scope(isolate); | 334 PrepareStackTraceScope scope(isolate); |
612 Handle<JSArray> array = isolate->factory()->NewJSArrayWithElements(frames); | 335 |
| 336 // Create JS CallSite objects from the raw stack frame array. |
| 337 |
| 338 Handle<JSArray> call_sites; |
| 339 ASSIGN_RETURN_ON_EXCEPTION(isolate, call_sites, |
| 340 ToCallSites(isolate, frames), Object); |
613 | 341 |
614 const int argc = 2; | 342 const int argc = 2; |
615 ScopedVector<Handle<Object>> argv(argc); | 343 ScopedVector<Handle<Object>> argv(argc); |
616 argv[0] = error; | 344 argv[0] = error; |
617 argv[1] = array; | 345 argv[1] = call_sites; |
618 | 346 |
619 Handle<Object> result; | 347 Handle<Object> result; |
620 ASSIGN_RETURN_ON_EXCEPTION( | 348 ASSIGN_RETURN_ON_EXCEPTION( |
621 isolate, result, Execution::Call(isolate, prepare_stack_trace, | 349 isolate, result, Execution::Call(isolate, prepare_stack_trace, |
622 global_error, argc, argv.start()), | 350 global_error, argc, argv.start()), |
623 Object); | 351 Object); |
624 | 352 |
625 return result; | 353 return result; |
| 354 } else { |
| 355 IncrementalStringBuilder builder(isolate); |
| 356 |
| 357 RETURN_ON_EXCEPTION(isolate, AppendErrorString(isolate, error, &builder), |
| 358 Object); |
| 359 |
| 360 for (int i = 0; i < frames->length(); i++) { |
| 361 auto frame = |
| 362 Handle<StackTraceFrame>::cast(FixedArray::get(*frames, i, isolate)); |
| 363 |
| 364 builder.AppendCString("\n at "); |
| 365 builder.AppendString(frame->ToString()); |
| 366 } |
| 367 |
| 368 RETURN_RESULT(isolate, builder.Finish(), Object); |
626 } | 369 } |
627 | |
628 IncrementalStringBuilder builder(isolate); | |
629 | |
630 RETURN_ON_EXCEPTION(isolate, AppendErrorString(isolate, error, &builder), | |
631 Object); | |
632 | |
633 for (int i = 0; i < frames->length(); i++) { | |
634 builder.AppendCString("\n at "); | |
635 | |
636 Handle<Object> frame = FixedArray::get(*frames, i, isolate); | |
637 MaybeHandle<String> maybe_frame_string = | |
638 CallSiteUtils::ToString(isolate, frame); | |
639 if (maybe_frame_string.is_null()) { | |
640 // CallSite.toString threw. Try to return a string representation of the | |
641 // thrown exception instead. | |
642 | |
643 DCHECK(isolate->has_pending_exception()); | |
644 Handle<Object> pending_exception = | |
645 handle(isolate->pending_exception(), isolate); | |
646 isolate->clear_pending_exception(); | |
647 | |
648 maybe_frame_string = ErrorUtils::ToString(isolate, pending_exception); | |
649 if (maybe_frame_string.is_null()) { | |
650 // Formatting the thrown exception threw again, give up. | |
651 | |
652 builder.AppendCString("<error>"); | |
653 } else { | |
654 // Formatted thrown exception successfully, append it. | |
655 builder.AppendCString("<error: "); | |
656 builder.AppendString(maybe_frame_string.ToHandleChecked()); | |
657 builder.AppendCString("<error>"); | |
658 } | |
659 } else { | |
660 // CallSite.toString completed without throwing. | |
661 builder.AppendString(maybe_frame_string.ToHandleChecked()); | |
662 } | |
663 } | |
664 | |
665 RETURN_RESULT(isolate, builder.Finish(), Object); | |
666 } | 370 } |
667 | 371 |
668 Handle<String> MessageTemplate::FormatMessage(Isolate* isolate, | 372 Handle<String> MessageTemplate::FormatMessage(Isolate* isolate, |
669 int template_index, | 373 int template_index, |
670 Handle<Object> arg) { | 374 Handle<Object> arg) { |
671 Factory* factory = isolate->factory(); | 375 Factory* factory = isolate->factory(); |
672 Handle<String> result_string = Object::NoSideEffectsToString(isolate, arg); | 376 Handle<String> result_string = Object::NoSideEffectsToString(isolate, arg); |
673 MaybeHandle<String> maybe_result_string = MessageTemplate::FormatMessage( | 377 MaybeHandle<String> maybe_result_string = MessageTemplate::FormatMessage( |
674 template_index, result_string, factory->empty_string(), | 378 template_index, result_string, factory->empty_string(), |
675 factory->empty_string()); | 379 factory->empty_string()); |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
895 } | 599 } |
896 | 600 |
897 DCHECK(mode != SKIP_UNTIL_SEEN); | 601 DCHECK(mode != SKIP_UNTIL_SEEN); |
898 | 602 |
899 Handle<Object> no_caller; | 603 Handle<Object> no_caller; |
900 Handle<String> msg = FormatMessage(isolate, template_index, arg0, arg1, arg2); | 604 Handle<String> msg = FormatMessage(isolate, template_index, arg0, arg1, arg2); |
901 return ErrorUtils::Construct(isolate, constructor, constructor, msg, mode, | 605 return ErrorUtils::Construct(isolate, constructor, constructor, msg, mode, |
902 no_caller, false); | 606 no_caller, false); |
903 } | 607 } |
904 | 608 |
905 #define SET_CALLSITE_PROPERTY(target, key, value) \ | |
906 RETURN_ON_EXCEPTION( \ | |
907 isolate, JSObject::SetOwnPropertyIgnoreAttributes( \ | |
908 target, isolate->factory()->key(), value, DONT_ENUM), \ | |
909 Object) | |
910 | |
911 MaybeHandle<Object> CallSiteUtils::Construct(Isolate* isolate, | |
912 Handle<Object> receiver, | |
913 Handle<Object> fun, | |
914 Handle<Object> pos, | |
915 Handle<Object> strict_mode) { | |
916 // Create the JS object. | |
917 | |
918 Handle<JSFunction> target = | |
919 handle(isolate->native_context()->callsite_function(), isolate); | |
920 | |
921 Handle<JSObject> obj; | |
922 ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, JSObject::New(target, target), | |
923 Object); | |
924 | |
925 // For wasm frames, receiver is the wasm object and fun is the function index | |
926 // instead of an actual function. | |
927 const bool is_wasm_object = | |
928 receiver->IsJSObject() && wasm::IsWasmObject(JSObject::cast(*receiver)); | |
929 if (!fun->IsJSFunction() && !is_wasm_object) { | |
930 THROW_NEW_ERROR(isolate, | |
931 NewTypeError(MessageTemplate::kCallSiteExpectsFunction, | |
932 Object::TypeOf(isolate, receiver), | |
933 Object::TypeOf(isolate, fun)), | |
934 Object); | |
935 } | |
936 | |
937 if (is_wasm_object) { | |
938 DCHECK(fun->IsSmi()); | |
939 DCHECK(wasm::GetNumberOfFunctions(JSObject::cast(*receiver)) > | |
940 Smi::cast(*fun)->value()); | |
941 | |
942 SET_CALLSITE_PROPERTY(obj, call_site_wasm_obj_symbol, receiver); | |
943 SET_CALLSITE_PROPERTY(obj, call_site_wasm_func_index_symbol, fun); | |
944 } else { | |
945 DCHECK(fun->IsJSFunction()); | |
946 SET_CALLSITE_PROPERTY(obj, call_site_receiver_symbol, receiver); | |
947 SET_CALLSITE_PROPERTY(obj, call_site_function_symbol, fun); | |
948 } | |
949 | |
950 DCHECK(pos->IsSmi()); | |
951 SET_CALLSITE_PROPERTY(obj, call_site_position_symbol, pos); | |
952 SET_CALLSITE_PROPERTY( | |
953 obj, call_site_strict_symbol, | |
954 isolate->factory()->ToBoolean(strict_mode->BooleanValue())); | |
955 | |
956 return obj; | |
957 } | |
958 | |
959 #undef SET_CALLSITE_PROPERTY | |
960 | |
961 namespace { | |
962 | |
963 bool IsNonEmptyString(Handle<Object> object) { | |
964 return (object->IsString() && String::cast(*object)->length() > 0); | |
965 } | |
966 | |
967 MaybeHandle<JSObject> AppendWasmToString(Isolate* isolate, | |
968 Handle<JSObject> recv, | |
969 CallSite* call_site, | |
970 IncrementalStringBuilder* builder) { | |
971 Handle<Object> name = call_site->GetFunctionName(); | |
972 if (name->IsNull(isolate)) { | |
973 builder->AppendCString("<WASM UNNAMED>"); | |
974 } else { | |
975 DCHECK(name->IsString()); | |
976 builder->AppendString(Handle<String>::cast(name)); | |
977 } | |
978 | |
979 builder->AppendCString(" (<WASM>["); | |
980 | |
981 Handle<String> ix = isolate->factory()->NumberToString( | |
982 handle(Smi::FromInt(call_site->wasm_func_index()), isolate)); | |
983 builder->AppendString(ix); | |
984 | |
985 builder->AppendCString("]+"); | |
986 | |
987 Handle<Object> pos; | |
988 ASSIGN_RETURN_ON_EXCEPTION( | |
989 isolate, pos, JSObject::GetProperty( | |
990 recv, isolate->factory()->call_site_position_symbol()), | |
991 JSObject); | |
992 DCHECK(pos->IsNumber()); | |
993 builder->AppendString(isolate->factory()->NumberToString(pos)); | |
994 builder->AppendCString(")"); | |
995 | |
996 return recv; | |
997 } | |
998 | |
999 MaybeHandle<JSObject> AppendFileLocation(Isolate* isolate, | |
1000 Handle<JSObject> recv, | |
1001 CallSite* call_site, | |
1002 IncrementalStringBuilder* builder) { | |
1003 if (call_site->IsNative()) { | |
1004 builder->AppendCString("native"); | |
1005 return recv; | |
1006 } | |
1007 | |
1008 Handle<Object> file_name = call_site->GetScriptNameOrSourceUrl(); | |
1009 if (!file_name->IsString() && call_site->IsEval()) { | |
1010 Handle<Object> eval_origin = call_site->GetEvalOrigin(); | |
1011 DCHECK(eval_origin->IsString()); | |
1012 builder->AppendString(Handle<String>::cast(eval_origin)); | |
1013 builder->AppendCString(", "); // Expecting source position to follow. | |
1014 } | |
1015 | |
1016 if (IsNonEmptyString(file_name)) { | |
1017 builder->AppendString(Handle<String>::cast(file_name)); | |
1018 } else { | |
1019 // Source code does not originate from a file and is not native, but we | |
1020 // can still get the source position inside the source string, e.g. in | |
1021 // an eval string. | |
1022 builder->AppendCString("<anonymous>"); | |
1023 } | |
1024 | |
1025 int line_number = call_site->GetLineNumber(); | |
1026 if (line_number != -1) { | |
1027 builder->AppendCharacter(':'); | |
1028 Handle<String> line_string = isolate->factory()->NumberToString( | |
1029 handle(Smi::FromInt(line_number), isolate), isolate); | |
1030 builder->AppendString(line_string); | |
1031 | |
1032 int column_number = call_site->GetColumnNumber(); | |
1033 if (column_number != -1) { | |
1034 builder->AppendCharacter(':'); | |
1035 Handle<String> column_string = isolate->factory()->NumberToString( | |
1036 handle(Smi::FromInt(column_number), isolate), isolate); | |
1037 builder->AppendString(column_string); | |
1038 } | |
1039 } | |
1040 | |
1041 return recv; | |
1042 } | |
1043 | |
1044 int StringIndexOf(Isolate* isolate, Handle<String> subject, | |
1045 Handle<String> pattern) { | |
1046 if (pattern->length() > subject->length()) return -1; | |
1047 return String::IndexOf(isolate, subject, pattern, 0); | |
1048 } | |
1049 | |
1050 // Returns true iff | |
1051 // 1. the subject ends with '.' + pattern, or | |
1052 // 2. subject == pattern. | |
1053 bool StringEndsWithMethodName(Isolate* isolate, Handle<String> subject, | |
1054 Handle<String> pattern) { | |
1055 if (String::Equals(subject, pattern)) return true; | |
1056 | |
1057 FlatStringReader subject_reader(isolate, String::Flatten(subject)); | |
1058 FlatStringReader pattern_reader(isolate, String::Flatten(pattern)); | |
1059 | |
1060 int pattern_index = pattern_reader.length() - 1; | |
1061 int subject_index = subject_reader.length() - 1; | |
1062 for (int i = 0; i <= pattern_reader.length(); i++) { // Iterate over len + 1. | |
1063 if (subject_index < 0) { | |
1064 return false; | |
1065 } | |
1066 | |
1067 const uc32 subject_char = subject_reader.Get(subject_index); | |
1068 if (i == pattern_reader.length()) { | |
1069 if (subject_char != '.') return false; | |
1070 } else if (subject_char != pattern_reader.Get(pattern_index)) { | |
1071 return false; | |
1072 } | |
1073 | |
1074 pattern_index--; | |
1075 subject_index--; | |
1076 } | |
1077 | |
1078 return true; | |
1079 } | |
1080 | |
1081 MaybeHandle<JSObject> AppendMethodCall(Isolate* isolate, Handle<JSObject> recv, | |
1082 CallSite* call_site, | |
1083 IncrementalStringBuilder* builder) { | |
1084 Handle<Object> type_name = call_site->GetTypeName(); | |
1085 Handle<Object> method_name = call_site->GetMethodName(); | |
1086 Handle<Object> function_name = call_site->GetFunctionName(); | |
1087 | |
1088 if (IsNonEmptyString(function_name)) { | |
1089 Handle<String> function_string = Handle<String>::cast(function_name); | |
1090 if (IsNonEmptyString(type_name)) { | |
1091 Handle<String> type_string = Handle<String>::cast(type_name); | |
1092 bool starts_with_type_name = | |
1093 (StringIndexOf(isolate, function_string, type_string) == 0); | |
1094 if (!starts_with_type_name) { | |
1095 builder->AppendString(type_string); | |
1096 builder->AppendCharacter('.'); | |
1097 } | |
1098 } | |
1099 builder->AppendString(function_string); | |
1100 | |
1101 if (IsNonEmptyString(method_name)) { | |
1102 Handle<String> method_string = Handle<String>::cast(method_name); | |
1103 if (!StringEndsWithMethodName(isolate, function_string, method_string)) { | |
1104 builder->AppendCString(" [as "); | |
1105 builder->AppendString(method_string); | |
1106 builder->AppendCharacter(']'); | |
1107 } | |
1108 } | |
1109 } else { | |
1110 builder->AppendString(Handle<String>::cast(type_name)); | |
1111 builder->AppendCharacter('.'); | |
1112 if (IsNonEmptyString(method_name)) { | |
1113 builder->AppendString(Handle<String>::cast(method_name)); | |
1114 } else { | |
1115 builder->AppendCString("<anonymous>"); | |
1116 } | |
1117 } | |
1118 | |
1119 return recv; | |
1120 } | |
1121 | |
1122 } // namespace | |
1123 | |
1124 MaybeHandle<String> CallSiteUtils::ToString(Isolate* isolate, | |
1125 Handle<Object> receiver) { | |
1126 if (!receiver->IsJSObject()) { | |
1127 THROW_NEW_ERROR( | |
1128 isolate, | |
1129 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | |
1130 isolate->factory()->NewStringFromAsciiChecked("toString"), | |
1131 receiver), | |
1132 String); | |
1133 } | |
1134 Handle<JSObject> recv = Handle<JSObject>::cast(receiver); | |
1135 | |
1136 if (!JSReceiver::HasOwnProperty( | |
1137 recv, isolate->factory()->call_site_position_symbol()) | |
1138 .FromMaybe(false)) { | |
1139 THROW_NEW_ERROR( | |
1140 isolate, | |
1141 NewTypeError(MessageTemplate::kCallSiteMethod, | |
1142 isolate->factory()->NewStringFromAsciiChecked("toString")), | |
1143 String); | |
1144 } | |
1145 | |
1146 IncrementalStringBuilder builder(isolate); | |
1147 | |
1148 CallSite call_site(isolate, recv); | |
1149 if (call_site.IsWasm()) { | |
1150 RETURN_ON_EXCEPTION(isolate, | |
1151 AppendWasmToString(isolate, recv, &call_site, &builder), | |
1152 String); | |
1153 RETURN_RESULT(isolate, builder.Finish(), String); | |
1154 } | |
1155 | |
1156 DCHECK(!call_site.IsWasm()); | |
1157 Handle<Object> function_name = call_site.GetFunctionName(); | |
1158 | |
1159 const bool is_toplevel = call_site.IsToplevel(); | |
1160 const bool is_constructor = call_site.IsConstructor(); | |
1161 const bool is_method_call = !(is_toplevel || is_constructor); | |
1162 | |
1163 if (is_method_call) { | |
1164 RETURN_ON_EXCEPTION( | |
1165 isolate, AppendMethodCall(isolate, recv, &call_site, &builder), String); | |
1166 } else if (is_constructor) { | |
1167 builder.AppendCString("new "); | |
1168 if (IsNonEmptyString(function_name)) { | |
1169 builder.AppendString(Handle<String>::cast(function_name)); | |
1170 } else { | |
1171 builder.AppendCString("<anonymous>"); | |
1172 } | |
1173 } else if (IsNonEmptyString(function_name)) { | |
1174 builder.AppendString(Handle<String>::cast(function_name)); | |
1175 } else { | |
1176 RETURN_ON_EXCEPTION(isolate, | |
1177 AppendFileLocation(isolate, recv, &call_site, &builder), | |
1178 String); | |
1179 RETURN_RESULT(isolate, builder.Finish(), String); | |
1180 } | |
1181 | |
1182 builder.AppendCString(" ("); | |
1183 RETURN_ON_EXCEPTION( | |
1184 isolate, AppendFileLocation(isolate, recv, &call_site, &builder), String); | |
1185 builder.AppendCString(")"); | |
1186 | |
1187 RETURN_RESULT(isolate, builder.Finish(), String); | |
1188 } | |
1189 | |
1190 } // namespace internal | 609 } // namespace internal |
1191 } // namespace v8 | 610 } // namespace v8 |
OLD | NEW |