1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/accessors.h" 6 7 #include "src/api-inl.h" 8 #include "src/contexts.h" 9 #include "src/deoptimizer.h" 10 #include "src/execution.h" 11 #include "src/frames-inl.h" 12 #include "src/heap/factory.h" 13 #include "src/isolate-inl.h" 14 #include "src/messages.h" 15 #include "src/objects/api-callbacks.h" 16 #include "src/objects/js-array-inl.h" 17 #include "src/objects/module-inl.h" 18 #include "src/property-details.h" 19 #include "src/prototype.h" 20 21 namespace v8 { 22 namespace internal { 23 24 Handle<AccessorInfo> Accessors::MakeAccessor( 25 Isolate* isolate, Handle<Name> name, AccessorNameGetterCallback getter, 26 AccessorNameBooleanSetterCallback setter) { 27 Factory* factory = isolate->factory(); 28 Handle<AccessorInfo> info = factory->NewAccessorInfo(); 29 info->set_all_can_read(false); 30 info->set_all_can_write(false); 31 info->set_is_special_data_property(true); 32 info->set_is_sloppy(false); 33 info->set_replace_on_access(false); 34 info->set_has_no_side_effect(false); 35 name = factory->InternalizeName(name); 36 info->set_name(*name); 37 Handle<Object> get = v8::FromCData(isolate, getter); 38 if (setter == nullptr) setter = &ReconfigureToDataProperty; 39 Handle<Object> set = v8::FromCData(isolate, setter); 40 info->set_getter(*get); 41 info->set_setter(*set); 42 Address redirected = info->redirected_getter(); 43 if (redirected != kNullAddress) { 44 Handle<Object> js_get = v8::FromCData(isolate, redirected); 45 info->set_js_getter(*js_get); 46 } 47 return info; 48 } 49 50 static V8_INLINE bool CheckForName(Isolate* isolate, Handle<Name> name, 51 Handle<String> property_name, int offset, 52 FieldIndex::Encoding encoding, 53 FieldIndex* index) { 54 if (Name::Equals(isolate, name, property_name)) { 55 *index = FieldIndex::ForInObjectOffset(offset, encoding); 56 return true; 57 } 58 return false; 59 } 60 61 62 // Returns true for properties that are accessors to object fields. 63 // If true, *object_offset contains offset of object field. 64 bool Accessors::IsJSObjectFieldAccessor(Isolate* isolate, Handle<Map> map, 65 Handle<Name> name, FieldIndex* index) { 66 switch (map->instance_type()) { 67 case JS_ARRAY_TYPE: 68 return CheckForName(isolate, name, isolate->factory()->length_string(), 69 JSArray::kLengthOffset, FieldIndex::kTagged, index); 70 default: 71 if (map->instance_type() < FIRST_NONSTRING_TYPE) { 72 return CheckForName(isolate, name, isolate->factory()->length_string(), 73 String::kLengthOffset, FieldIndex::kTagged, index); 74 } 75 76 return false; 77 } 78 } 79 80 V8_WARN_UNUSED_RESULT MaybeHandle<Object> 81 Accessors::ReplaceAccessorWithDataProperty(Handle<Object> receiver, 82 Handle<JSObject> holder, 83 Handle<Name> name, 84 Handle<Object> value) { 85 LookupIterator it(receiver, name, holder, 86 LookupIterator::OWN_SKIP_INTERCEPTOR); 87 // Skip any access checks we might hit. This accessor should never hit in a 88 // situation where the caller does not have access. 89 if (it.state() == LookupIterator::ACCESS_CHECK) { 90 CHECK(it.HasAccess()); 91 it.Next(); 92 } 93 DCHECK(holder.is_identical_to(it.GetHolder<JSObject>())); 94 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); 95 it.ReconfigureDataProperty(value, it.property_attributes()); 96 return value; 97 } 98 99 100 // 101 // Accessors::ReconfigureToDataProperty 102 // 103 void Accessors::ReconfigureToDataProperty( 104 v8::Local<v8::Name> key, v8::Local<v8::Value> val, 105 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 106 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 107 RuntimeCallTimerScope stats_scope( 108 isolate, RuntimeCallCounterId::kReconfigureToDataProperty); 109 HandleScope scope(isolate); 110 Handle<Object> receiver = Utils::OpenHandle(*info.This()); 111 Handle<JSObject> holder = 112 Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder())); 113 Handle<Name> name = Utils::OpenHandle(*key); 114 Handle<Object> value = Utils::OpenHandle(*val); 115 MaybeHandle<Object> result = 116 Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name, value); 117 if (result.is_null()) { 118 isolate->OptionalRescheduleException(false); 119 } else { 120 info.GetReturnValue().Set(true); 121 } 122 } 123 124 125 // 126 // Accessors::ArgumentsIterator 127 // 128 129 130 void Accessors::ArgumentsIteratorGetter( 131 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 132 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 133 DisallowHeapAllocation no_allocation; 134 HandleScope scope(isolate); 135 Object* result = isolate->native_context()->array_values_iterator(); 136 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate))); 137 } 138 139 Handle<AccessorInfo> Accessors::MakeArgumentsIteratorInfo(Isolate* isolate) { 140 Handle<Name> name = isolate->factory()->iterator_symbol(); 141 return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr); 142 } 143 144 145 // 146 // Accessors::ArrayLength 147 // 148 149 150 void Accessors::ArrayLengthGetter( 151 v8::Local<v8::Name> name, 152 const v8::PropertyCallbackInfo<v8::Value>& info) { 153 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 154 RuntimeCallTimerScope timer(isolate, 155 RuntimeCallCounterId::kArrayLengthGetter); 156 DisallowHeapAllocation no_allocation; 157 HandleScope scope(isolate); 158 JSArray* holder = JSArray::cast(*Utils::OpenHandle(*info.Holder())); 159 Object* result = holder->length(); 160 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate))); 161 } 162 163 void Accessors::ArrayLengthSetter( 164 v8::Local<v8::Name> name, v8::Local<v8::Value> val, 165 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 166 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 167 RuntimeCallTimerScope timer(isolate, 168 RuntimeCallCounterId::kArrayLengthSetter); 169 HandleScope scope(isolate); 170 171 DCHECK(Utils::OpenHandle(*name)->SameValue( 172 ReadOnlyRoots(isolate).length_string())); 173 174 Handle<JSReceiver> object = Utils::OpenHandle(*info.Holder()); 175 Handle<JSArray> array = Handle<JSArray>::cast(object); 176 Handle<Object> length_obj = Utils::OpenHandle(*val); 177 178 bool was_readonly = JSArray::HasReadOnlyLength(array); 179 180 uint32_t length = 0; 181 if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) { 182 isolate->OptionalRescheduleException(false); 183 return; 184 } 185 186 if (!was_readonly && V8_UNLIKELY(JSArray::HasReadOnlyLength(array)) && 187 length != array->length()->Number()) { 188 // AnythingToArrayLength() may have called setter re-entrantly and modified 189 // its property descriptor. Don't perform this check if "length" was 190 // previously readonly, as this may have been called during 191 // DefineOwnPropertyIgnoreAttributes(). 192 if (info.ShouldThrowOnError()) { 193 Factory* factory = isolate->factory(); 194 isolate->Throw(*factory->NewTypeError( 195 MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name), 196 i::Object::TypeOf(isolate, object), object)); 197 isolate->OptionalRescheduleException(false); 198 } else { 199 info.GetReturnValue().Set(false); 200 } 201 return; 202 } 203 204 JSArray::SetLength(array, length); 205 206 uint32_t actual_new_len = 0; 207 CHECK(array->length()->ToArrayLength(&actual_new_len)); 208 // Fail if there were non-deletable elements. 209 if (actual_new_len != length) { 210 if (info.ShouldThrowOnError()) { 211 Factory* factory = isolate->factory(); 212 isolate->Throw(*factory->NewTypeError( 213 MessageTemplate::kStrictDeleteProperty, 214 factory->NewNumberFromUint(actual_new_len - 1), array)); 215 isolate->OptionalRescheduleException(false); 216 } else { 217 info.GetReturnValue().Set(false); 218 } 219 } else { 220 info.GetReturnValue().Set(true); 221 } 222 } 223 224 Handle<AccessorInfo> Accessors::MakeArrayLengthInfo(Isolate* isolate) { 225 return MakeAccessor(isolate, isolate->factory()->length_string(), 226 &ArrayLengthGetter, &ArrayLengthSetter); 227 } 228 229 // 230 // Accessors::ModuleNamespaceEntry 231 // 232 233 void Accessors::ModuleNamespaceEntryGetter( 234 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 235 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 236 HandleScope scope(isolate); 237 JSModuleNamespace* holder = 238 JSModuleNamespace::cast(*Utils::OpenHandle(*info.Holder())); 239 Handle<Object> result; 240 if (!holder 241 ->GetExport(isolate, Handle<String>::cast(Utils::OpenHandle(*name))) 242 .ToHandle(&result)) { 243 isolate->OptionalRescheduleException(false); 244 } else { 245 info.GetReturnValue().Set(Utils::ToLocal(result)); 246 } 247 } 248 249 void Accessors::ModuleNamespaceEntrySetter( 250 v8::Local<v8::Name> name, v8::Local<v8::Value> val, 251 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 252 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 253 HandleScope scope(isolate); 254 Factory* factory = isolate->factory(); 255 Handle<JSModuleNamespace> holder = 256 Handle<JSModuleNamespace>::cast(Utils::OpenHandle(*info.Holder())); 257 258 if (info.ShouldThrowOnError()) { 259 isolate->Throw(*factory->NewTypeError( 260 MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name), 261 i::Object::TypeOf(isolate, holder), holder)); 262 isolate->OptionalRescheduleException(false); 263 } else { 264 info.GetReturnValue().Set(false); 265 } 266 } 267 268 Handle<AccessorInfo> Accessors::MakeModuleNamespaceEntryInfo( 269 Isolate* isolate, Handle<String> name) { 270 return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter, 271 &ModuleNamespaceEntrySetter); 272 } 273 274 275 // 276 // Accessors::StringLength 277 // 278 279 void Accessors::StringLengthGetter( 280 v8::Local<v8::Name> name, 281 const v8::PropertyCallbackInfo<v8::Value>& info) { 282 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 283 RuntimeCallTimerScope timer(isolate, 284 RuntimeCallCounterId::kStringLengthGetter); 285 DisallowHeapAllocation no_allocation; 286 HandleScope scope(isolate); 287 288 // We have a slight impedance mismatch between the external API and the way we 289 // use callbacks internally: Externally, callbacks can only be used with 290 // v8::Object, but internally we have callbacks on entities which are higher 291 // in the hierarchy, in this case for String values. 292 293 Object* value = *Utils::OpenHandle(*v8::Local<v8::Value>(info.This())); 294 if (!value->IsString()) { 295 // Not a string value. That means that we either got a String wrapper or 296 // a Value with a String wrapper in its prototype chain. 297 value = JSValue::cast(*Utils::OpenHandle(*info.Holder()))->value(); 298 } 299 Object* result = Smi::FromInt(String::cast(value)->length()); 300 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate))); 301 } 302 303 Handle<AccessorInfo> Accessors::MakeStringLengthInfo(Isolate* isolate) { 304 return MakeAccessor(isolate, isolate->factory()->length_string(), 305 &StringLengthGetter, nullptr); 306 } 307 308 // 309 // Accessors::FunctionPrototype 310 // 311 312 static Handle<Object> GetFunctionPrototype(Isolate* isolate, 313 Handle<JSFunction> function) { 314 if (!function->has_prototype()) { 315 Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function); 316 JSFunction::SetPrototype(function, proto); 317 } 318 return Handle<Object>(function->prototype(), isolate); 319 } 320 321 void Accessors::FunctionPrototypeGetter( 322 v8::Local<v8::Name> name, 323 const v8::PropertyCallbackInfo<v8::Value>& info) { 324 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 325 RuntimeCallTimerScope timer(isolate, 326 RuntimeCallCounterId::kFunctionPrototypeGetter); 327 HandleScope scope(isolate); 328 Handle<JSFunction> function = 329 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 330 DCHECK(function->has_prototype_property()); 331 Handle<Object> result = GetFunctionPrototype(isolate, function); 332 info.GetReturnValue().Set(Utils::ToLocal(result)); 333 } 334 335 void Accessors::FunctionPrototypeSetter( 336 v8::Local<v8::Name> name, v8::Local<v8::Value> val, 337 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 338 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 339 RuntimeCallTimerScope timer(isolate, 340 RuntimeCallCounterId::kFunctionPrototypeSetter); 341 HandleScope scope(isolate); 342 Handle<Object> value = Utils::OpenHandle(*val); 343 Handle<JSFunction> object = 344 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 345 DCHECK(object->has_prototype_property()); 346 JSFunction::SetPrototype(object, value); 347 info.GetReturnValue().Set(true); 348 } 349 350 Handle<AccessorInfo> Accessors::MakeFunctionPrototypeInfo(Isolate* isolate) { 351 return MakeAccessor(isolate, isolate->factory()->prototype_string(), 352 &FunctionPrototypeGetter, &FunctionPrototypeSetter); 353 } 354 355 356 // 357 // Accessors::FunctionLength 358 // 359 360 361 void Accessors::FunctionLengthGetter( 362 v8::Local<v8::Name> name, 363 const v8::PropertyCallbackInfo<v8::Value>& info) { 364 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 365 RuntimeCallTimerScope timer(isolate, 366 RuntimeCallCounterId::kFunctionLengthGetter); 367 HandleScope scope(isolate); 368 Handle<JSFunction> function = 369 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 370 int length = 0; 371 if (!JSFunction::GetLength(isolate, function).To(&length)) { 372 isolate->OptionalRescheduleException(false); 373 } 374 Handle<Object> result(Smi::FromInt(length), isolate); 375 info.GetReturnValue().Set(Utils::ToLocal(result)); 376 } 377 378 Handle<AccessorInfo> Accessors::MakeFunctionLengthInfo(Isolate* isolate) { 379 return MakeAccessor(isolate, isolate->factory()->length_string(), 380 &FunctionLengthGetter, &ReconfigureToDataProperty); 381 } 382 383 384 // 385 // Accessors::FunctionName 386 // 387 388 389 void Accessors::FunctionNameGetter( 390 v8::Local<v8::Name> name, 391 const v8::PropertyCallbackInfo<v8::Value>& info) { 392 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 393 HandleScope scope(isolate); 394 Handle<JSFunction> function = 395 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 396 Handle<Object> result = JSFunction::GetName(isolate, function); 397 info.GetReturnValue().Set(Utils::ToLocal(result)); 398 } 399 400 Handle<AccessorInfo> Accessors::MakeFunctionNameInfo(Isolate* isolate) { 401 return MakeAccessor(isolate, isolate->factory()->name_string(), 402 &FunctionNameGetter, &ReconfigureToDataProperty); 403 } 404 405 406 // 407 // Accessors::FunctionArguments 408 // 409 410 namespace { 411 412 Handle<JSObject> ArgumentsForInlinedFunction(JavaScriptFrame* frame, 413 int inlined_frame_index) { 414 Isolate* isolate = frame->isolate(); 415 Factory* factory = isolate->factory(); 416 417 TranslatedState translated_values(frame); 418 translated_values.Prepare(frame->fp()); 419 420 int argument_count = 0; 421 TranslatedFrame* translated_frame = 422 translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index, 423 &argument_count); 424 TranslatedFrame::iterator iter = translated_frame->begin(); 425 426 // Materialize the function. 427 bool should_deoptimize = iter->IsMaterializedObject(); 428 Handle<JSFunction> function = Handle<JSFunction>::cast(iter->GetValue()); 429 iter++; 430 431 // Skip the receiver. 432 iter++; 433 argument_count--; 434 435 Handle<JSObject> arguments = 436 factory->NewArgumentsObject(function, argument_count); 437 Handle<FixedArray> array = factory->NewFixedArray(argument_count); 438 for (int i = 0; i < argument_count; ++i) { 439 // If we materialize any object, we should deoptimize the frame because we 440 // might alias an object that was eliminated by escape analysis. 441 should_deoptimize = should_deoptimize || iter->IsMaterializedObject(); 442 Handle<Object> value = iter->GetValue(); 443 array->set(i, *value); 444 iter++; 445 } 446 arguments->set_elements(*array); 447 448 if (should_deoptimize) { 449 translated_values.StoreMaterializedValuesAndDeopt(frame); 450 } 451 452 // Return the freshly allocated arguments object. 453 return arguments; 454 } 455 456 int FindFunctionInFrame(JavaScriptFrame* frame, Handle<JSFunction> function) { 457 std::vector<FrameSummary> frames; 458 frame->Summarize(&frames); 459 for (size_t i = frames.size(); i != 0; i--) { 460 if (*frames[i - 1].AsJavaScript().function() == *function) { 461 return static_cast<int>(i) - 1; 462 } 463 } 464 return -1; 465 } 466 467 Handle<JSObject> GetFrameArguments(Isolate* isolate, 468 JavaScriptFrameIterator* it, 469 int function_index) { 470 JavaScriptFrame* frame = it->frame(); 471 472 if (function_index > 0) { 473 // The function in question was inlined. Inlined functions have the 474 // correct number of arguments and no allocated arguments object, so 475 // we can construct a fresh one by interpreting the function's 476 // deoptimization input data. 477 return ArgumentsForInlinedFunction(frame, function_index); 478 } 479 480 // Find the frame that holds the actual arguments passed to the function. 481 if (it->frame()->has_adapted_arguments()) { 482 it->AdvanceOneFrame(); 483 DCHECK(it->frame()->is_arguments_adaptor()); 484 } 485 frame = it->frame(); 486 487 // Get the number of arguments and construct an arguments object 488 // mirror for the right frame and the underlying function. 489 const int length = frame->ComputeParametersCount(); 490 Handle<JSFunction> function(frame->function(), isolate); 491 Handle<JSObject> arguments = 492 isolate->factory()->NewArgumentsObject(function, length); 493 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); 494 495 // Copy the parameters to the arguments object. 496 DCHECK(array->length() == length); 497 for (int i = 0; i < length; i++) { 498 Object* value = frame->GetParameter(i); 499 if (value->IsTheHole(isolate)) { 500 // Generators currently use holes as dummy arguments when resuming. We 501 // must not leak those. 502 DCHECK(IsResumableFunction(function->shared()->kind())); 503 value = ReadOnlyRoots(isolate).undefined_value(); 504 } 505 array->set(i, value); 506 } 507 arguments->set_elements(*array); 508 509 // Return the freshly allocated arguments object. 510 return arguments; 511 } 512 513 } // namespace 514 515 Handle<JSObject> Accessors::FunctionGetArguments(JavaScriptFrame* frame, 516 int inlined_jsframe_index) { 517 Isolate* isolate = frame->isolate(); 518 Address requested_frame_fp = frame->fp(); 519 // Forward a frame iterator to the requested frame. This is needed because we 520 // potentially need for advance it to the arguments adaptor frame later. 521 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { 522 if (it.frame()->fp() != requested_frame_fp) continue; 523 return GetFrameArguments(isolate, &it, inlined_jsframe_index); 524 } 525 UNREACHABLE(); // Requested frame not found. 526 return Handle<JSObject>(); 527 } 528 529 530 void Accessors::FunctionArgumentsGetter( 531 v8::Local<v8::Name> name, 532 const v8::PropertyCallbackInfo<v8::Value>& info) { 533 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 534 HandleScope scope(isolate); 535 Handle<JSFunction> function = 536 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 537 Handle<Object> result = isolate->factory()->null_value(); 538 if (!function->shared()->native()) { 539 // Find the top invocation of the function by traversing frames. 540 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { 541 JavaScriptFrame* frame = it.frame(); 542 int function_index = FindFunctionInFrame(frame, function); 543 if (function_index >= 0) { 544 result = GetFrameArguments(isolate, &it, function_index); 545 break; 546 } 547 } 548 } 549 info.GetReturnValue().Set(Utils::ToLocal(result)); 550 } 551 552 Handle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo(Isolate* isolate) { 553 return MakeAccessor(isolate, isolate->factory()->arguments_string(), 554 &FunctionArgumentsGetter, nullptr); 555 } 556 557 558 // 559 // Accessors::FunctionCaller 560 // 561 562 563 static inline bool AllowAccessToFunction(Context* current_context, 564 JSFunction* function) { 565 return current_context->HasSameSecurityTokenAs(function->context()); 566 } 567 568 569 class FrameFunctionIterator { 570 public: 571 explicit FrameFunctionIterator(Isolate* isolate) 572 : isolate_(isolate), frame_iterator_(isolate), inlined_frame_index_(-1) { 573 GetFrames(); 574 } 575 576 // Iterate through functions until the first occurrence of 'function'. 577 // Returns true if one is found, and false if the iterator ends before. 578 bool Find(Handle<JSFunction> function) { 579 do { 580 if (!next().ToHandle(&function_)) return false; 581 } while (!function_.is_identical_to(function)); 582 return true; 583 } 584 585 // Iterate through functions until the next non-toplevel one is found. 586 // Returns true if one is found, and false if the iterator ends before. 587 bool FindNextNonTopLevel() { 588 do { 589 if (!next().ToHandle(&function_)) return false; 590 } while (function_->shared()->is_toplevel()); 591 return true; 592 } 593 594 // Iterate through function until the first native or user-provided function 595 // is found. Functions not defined in user-provided scripts are not visible 596 // unless directly exposed, in which case the native flag is set on them. 597 // Returns true if one is found, and false if the iterator ends before. 598 bool FindFirstNativeOrUserJavaScript() { 599 while (!function_->shared()->native() && 600 !function_->shared()->IsUserJavaScript()) { 601 if (!next().ToHandle(&function_)) return false; 602 } 603 return true; 604 } 605 606 // In case of inlined frames the function could have been materialized from 607 // deoptimization information. If that is the case we need to make sure that 608 // subsequent call will see the same function, since we are about to hand out 609 // the value to JavaScript. Make sure to store the materialized value and 610 // trigger a deoptimization of the underlying frame. 611 Handle<JSFunction> MaterializeFunction() { 612 if (inlined_frame_index_ == 0) return function_; 613 614 JavaScriptFrame* frame = frame_iterator_.frame(); 615 TranslatedState translated_values(frame); 616 translated_values.Prepare(frame->fp()); 617 618 TranslatedFrame* translated_frame = 619 translated_values.GetFrameFromJSFrameIndex(inlined_frame_index_); 620 TranslatedFrame::iterator iter = translated_frame->begin(); 621 622 // First value is the function. 623 bool should_deoptimize = iter->IsMaterializedObject(); 624 Handle<Object> value = iter->GetValue(); 625 if (should_deoptimize) { 626 translated_values.StoreMaterializedValuesAndDeopt(frame); 627 } 628 629 return Handle<JSFunction>::cast(value); 630 } 631 632 private: 633 MaybeHandle<JSFunction> next() { 634 while (true) { 635 if (inlined_frame_index_ <= 0) { 636 if (!frame_iterator_.done()) { 637 frame_iterator_.Advance(); 638 frames_.clear(); 639 inlined_frame_index_ = -1; 640 GetFrames(); 641 } 642 if (inlined_frame_index_ == -1) return MaybeHandle<JSFunction>(); 643 } 644 645 --inlined_frame_index_; 646 Handle<JSFunction> next_function = 647 frames_[inlined_frame_index_].AsJavaScript().function(); 648 // Skip functions from other origins. 649 if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue; 650 return next_function; 651 } 652 } 653 void GetFrames() { 654 DCHECK_EQ(-1, inlined_frame_index_); 655 if (frame_iterator_.done()) return; 656 JavaScriptFrame* frame = frame_iterator_.frame(); 657 frame->Summarize(&frames_); 658 inlined_frame_index_ = static_cast<int>(frames_.size()); 659 DCHECK_LT(0, inlined_frame_index_); 660 } 661 Isolate* isolate_; 662 Handle<JSFunction> function_; 663 JavaScriptFrameIterator frame_iterator_; 664 std::vector<FrameSummary> frames_; 665 int inlined_frame_index_; 666 }; 667 668 669 MaybeHandle<JSFunction> FindCaller(Isolate* isolate, 670 Handle<JSFunction> function) { 671 FrameFunctionIterator it(isolate); 672 if (function->shared()->native()) { 673 return MaybeHandle<JSFunction>(); 674 } 675 // Find the function from the frames. Return null in case no frame 676 // corresponding to the given function was found. 677 if (!it.Find(function)) { 678 return MaybeHandle<JSFunction>(); 679 } 680 // Find previously called non-toplevel function. 681 if (!it.FindNextNonTopLevel()) { 682 return MaybeHandle<JSFunction>(); 683 } 684 // Find the first user-land JavaScript function (or the entry point into 685 // native JavaScript builtins in case such a builtin was the caller). 686 if (!it.FindFirstNativeOrUserJavaScript()) { 687 return MaybeHandle<JSFunction>(); 688 } 689 690 // Materialize the function that the iterator is currently sitting on. Note 691 // that this might trigger deoptimization in case the function was actually 692 // materialized. Identity of the function must be preserved because we are 693 // going to return it to JavaScript after this point. 694 Handle<JSFunction> caller = it.MaterializeFunction(); 695 696 // Censor if the caller is not a sloppy mode function. 697 // Change from ES5, which used to throw, see: 698 // https://bugs.ecmascript.org/show_bug.cgi?id=310 699 if (is_strict(caller->shared()->language_mode())) { 700 return MaybeHandle<JSFunction>(); 701 } 702 // Don't return caller from another security context. 703 if (!AllowAccessToFunction(isolate->context(), *caller)) { 704 return MaybeHandle<JSFunction>(); 705 } 706 return caller; 707 } 708 709 710 void Accessors::FunctionCallerGetter( 711 v8::Local<v8::Name> name, 712 const v8::PropertyCallbackInfo<v8::Value>& info) { 713 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 714 HandleScope scope(isolate); 715 Handle<JSFunction> function = 716 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 717 Handle<Object> result; 718 MaybeHandle<JSFunction> maybe_caller; 719 maybe_caller = FindCaller(isolate, function); 720 Handle<JSFunction> caller; 721 if (maybe_caller.ToHandle(&caller)) { 722 result = caller; 723 } else { 724 result = isolate->factory()->null_value(); 725 } 726 info.GetReturnValue().Set(Utils::ToLocal(result)); 727 } 728 729 Handle<AccessorInfo> Accessors::MakeFunctionCallerInfo(Isolate* isolate) { 730 return MakeAccessor(isolate, isolate->factory()->caller_string(), 731 &FunctionCallerGetter, nullptr); 732 } 733 734 735 // 736 // Accessors::BoundFunctionLength 737 // 738 739 void Accessors::BoundFunctionLengthGetter( 740 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 741 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 742 RuntimeCallTimerScope timer(isolate, 743 RuntimeCallCounterId::kBoundFunctionLengthGetter); 744 HandleScope scope(isolate); 745 Handle<JSBoundFunction> function = 746 Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder())); 747 748 int length = 0; 749 if (!JSBoundFunction::GetLength(isolate, function).To(&length)) { 750 isolate->OptionalRescheduleException(false); 751 return; 752 } 753 Handle<Object> result(Smi::FromInt(length), isolate); 754 info.GetReturnValue().Set(Utils::ToLocal(result)); 755 } 756 757 Handle<AccessorInfo> Accessors::MakeBoundFunctionLengthInfo(Isolate* isolate) { 758 return MakeAccessor(isolate, isolate->factory()->length_string(), 759 &BoundFunctionLengthGetter, &ReconfigureToDataProperty); 760 } 761 762 // 763 // Accessors::BoundFunctionName 764 // 765 766 void Accessors::BoundFunctionNameGetter( 767 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 768 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 769 RuntimeCallTimerScope timer(isolate, 770 RuntimeCallCounterId::kBoundFunctionNameGetter); 771 HandleScope scope(isolate); 772 Handle<JSBoundFunction> function = 773 Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder())); 774 Handle<Object> result; 775 if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) { 776 isolate->OptionalRescheduleException(false); 777 return; 778 } 779 info.GetReturnValue().Set(Utils::ToLocal(result)); 780 } 781 782 Handle<AccessorInfo> Accessors::MakeBoundFunctionNameInfo(Isolate* isolate) { 783 return MakeAccessor(isolate, isolate->factory()->name_string(), 784 &BoundFunctionNameGetter, &ReconfigureToDataProperty); 785 } 786 787 // 788 // Accessors::ErrorStack 789 // 790 791 namespace { 792 793 MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate, 794 Handle<JSObject> error) { 795 RETURN_ON_EXCEPTION( 796 isolate, 797 JSReceiver::SetProperty( 798 isolate, error, isolate->factory()->stack_trace_symbol(), 799 isolate->factory()->undefined_value(), LanguageMode::kStrict), 800 JSReceiver); 801 return error; 802 } 803 804 bool IsAccessor(Handle<Object> receiver, Handle<Name> name, 805 Handle<JSObject> holder) { 806 LookupIterator it(receiver, name, holder, 807 LookupIterator::OWN_SKIP_INTERCEPTOR); 808 // Skip any access checks we might hit. This accessor should never hit in a 809 // situation where the caller does not have access. 810 if (it.state() == LookupIterator::ACCESS_CHECK) { 811 CHECK(it.HasAccess()); 812 it.Next(); 813 } 814 return (it.state() == LookupIterator::ACCESSOR); 815 } 816 817 } // namespace 818 819 void Accessors::ErrorStackGetter( 820 v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) { 821 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 822 HandleScope scope(isolate); 823 Handle<JSObject> holder = 824 Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder())); 825 826 // Retrieve the structured stack trace. 827 828 Handle<Object> stack_trace; 829 Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol(); 830 MaybeHandle<Object> maybe_stack_trace = 831 JSObject::GetProperty(isolate, holder, stack_trace_symbol); 832 if (!maybe_stack_trace.ToHandle(&stack_trace) || 833 stack_trace->IsUndefined(isolate)) { 834 Handle<Object> result = isolate->factory()->undefined_value(); 835 info.GetReturnValue().Set(Utils::ToLocal(result)); 836 return; 837 } 838 839 // Format it, clear the internal structured trace and reconfigure as a data 840 // property. 841 842 Handle<Object> formatted_stack_trace; 843 if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace) 844 .ToHandle(&formatted_stack_trace)) { 845 isolate->OptionalRescheduleException(false); 846 return; 847 } 848 849 MaybeHandle<Object> result = ClearInternalStackTrace(isolate, holder); 850 if (result.is_null()) { 851 isolate->OptionalRescheduleException(false); 852 return; 853 } 854 855 // If stack is still an accessor (this could have changed in the meantime 856 // since FormatStackTrace can execute arbitrary JS), replace it with a data 857 // property. 858 Handle<Object> receiver = 859 Utils::OpenHandle(*v8::Local<v8::Value>(info.This())); 860 Handle<Name> name = Utils::OpenHandle(*key); 861 if (IsAccessor(receiver, name, holder)) { 862 result = Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name, 863 formatted_stack_trace); 864 if (result.is_null()) { 865 isolate->OptionalRescheduleException(false); 866 return; 867 } 868 } else { 869 // The stack property has been modified in the meantime. 870 if (!JSObject::GetProperty(isolate, holder, name) 871 .ToHandle(&formatted_stack_trace)) { 872 isolate->OptionalRescheduleException(false); 873 return; 874 } 875 } 876 877 v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace); 878 info.GetReturnValue().Set(value); 879 } 880 881 void Accessors::ErrorStackSetter( 882 v8::Local<v8::Name> name, v8::Local<v8::Value> val, 883 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 884 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 885 HandleScope scope(isolate); 886 Handle<JSObject> obj = Handle<JSObject>::cast( 887 Utils::OpenHandle(*v8::Local<v8::Value>(info.This()))); 888 889 // Clear internal properties to avoid memory leaks. 890 Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol(); 891 if (JSReceiver::HasOwnProperty(obj, stack_trace_symbol).FromMaybe(false)) { 892 ClearInternalStackTrace(isolate, obj); 893 } 894 895 Accessors::ReconfigureToDataProperty(name, val, info); 896 } 897 898 Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) { 899 return MakeAccessor(isolate, isolate->factory()->stack_string(), 900 &ErrorStackGetter, &ErrorStackSetter); 901 } 902 903 } // namespace internal 904 } // namespace v8 905