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.h" 8#include "src/contexts.h" 9#include "src/deoptimizer.h" 10#include "src/execution.h" 11#include "src/factory.h" 12#include "src/frames-inl.h" 13#include "src/isolate-inl.h" 14#include "src/list-inl.h" 15#include "src/messages.h" 16#include "src/property-details.h" 17#include "src/prototype.h" 18 19namespace v8 { 20namespace internal { 21 22 23Handle<AccessorInfo> Accessors::MakeAccessor( 24 Isolate* isolate, 25 Handle<Name> name, 26 AccessorNameGetterCallback getter, 27 AccessorNameSetterCallback setter, 28 PropertyAttributes attributes) { 29 Factory* factory = isolate->factory(); 30 Handle<AccessorInfo> info = factory->NewAccessorInfo(); 31 info->set_property_attributes(attributes); 32 info->set_all_can_read(false); 33 info->set_all_can_write(false); 34 info->set_is_special_data_property(true); 35 info->set_is_sloppy(false); 36 name = factory->InternalizeName(name); 37 info->set_name(*name); 38 Handle<Object> get = v8::FromCData(isolate, getter); 39 if (setter == nullptr) setter = &ReconfigureToDataProperty; 40 Handle<Object> set = v8::FromCData(isolate, setter); 41 info->set_getter(*get); 42 info->set_setter(*set); 43 Address redirected = info->redirected_getter(); 44 if (redirected != nullptr) { 45 Handle<Object> js_get = v8::FromCData(isolate, redirected); 46 info->set_js_getter(*js_get); 47 } 48 return info; 49} 50 51 52static V8_INLINE bool CheckForName(Handle<Name> name, 53 Handle<String> property_name, 54 int offset, 55 int* object_offset) { 56 if (Name::Equals(name, property_name)) { 57 *object_offset = offset; 58 return true; 59 } 60 return false; 61} 62 63 64// Returns true for properties that are accessors to object fields. 65// If true, *object_offset contains offset of object field. 66bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name, 67 int* object_offset) { 68 Isolate* isolate = name->GetIsolate(); 69 70 switch (map->instance_type()) { 71 case JS_ARRAY_TYPE: 72 return 73 CheckForName(name, isolate->factory()->length_string(), 74 JSArray::kLengthOffset, object_offset); 75 case JS_ARRAY_BUFFER_TYPE: 76 return CheckForName(name, isolate->factory()->byte_length_string(), 77 JSArrayBuffer::kByteLengthOffset, object_offset); 78 default: 79 if (map->instance_type() < FIRST_NONSTRING_TYPE) { 80 return CheckForName(name, isolate->factory()->length_string(), 81 String::kLengthOffset, object_offset); 82 } 83 84 return false; 85 } 86} 87 88 89namespace { 90 91MUST_USE_RESULT MaybeHandle<Object> ReplaceAccessorWithDataProperty( 92 Isolate* isolate, Handle<Object> receiver, Handle<JSObject> holder, 93 Handle<Name> name, Handle<Object> value) { 94 LookupIterator it(receiver, name, holder, 95 LookupIterator::OWN_SKIP_INTERCEPTOR); 96 // Skip any access checks we might hit. This accessor should never hit in a 97 // situation where the caller does not have access. 98 if (it.state() == LookupIterator::ACCESS_CHECK) { 99 CHECK(it.HasAccess()); 100 it.Next(); 101 } 102 DCHECK(holder.is_identical_to(it.GetHolder<JSObject>())); 103 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); 104 it.ReconfigureDataProperty(value, it.property_attributes()); 105 return value; 106} 107 108} // namespace 109 110void Accessors::ReconfigureToDataProperty( 111 v8::Local<v8::Name> key, v8::Local<v8::Value> val, 112 const v8::PropertyCallbackInfo<void>& info) { 113 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 114 HandleScope scope(isolate); 115 Handle<Object> receiver = Utils::OpenHandle(*info.This()); 116 Handle<JSObject> holder = 117 Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder())); 118 Handle<Name> name = Utils::OpenHandle(*key); 119 Handle<Object> value = Utils::OpenHandle(*val); 120 MaybeHandle<Object> result = 121 ReplaceAccessorWithDataProperty(isolate, receiver, holder, name, value); 122 if (result.is_null()) isolate->OptionalRescheduleException(false); 123} 124 125// 126// Accessors::ArgumentsIterator 127// 128 129 130void 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 140Handle<AccessorInfo> Accessors::ArgumentsIteratorInfo( 141 Isolate* isolate, PropertyAttributes attributes) { 142 Handle<Name> name = isolate->factory()->iterator_symbol(); 143 return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr, 144 attributes); 145} 146 147 148// 149// Accessors::ArrayLength 150// 151 152 153void Accessors::ArrayLengthGetter( 154 v8::Local<v8::Name> name, 155 const v8::PropertyCallbackInfo<v8::Value>& info) { 156 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 157 DisallowHeapAllocation no_allocation; 158 HandleScope scope(isolate); 159 JSArray* holder = JSArray::cast(*Utils::OpenHandle(*info.Holder())); 160 Object* result = holder->length(); 161 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate))); 162} 163 164 165void Accessors::ArrayLengthSetter( 166 v8::Local<v8::Name> name, 167 v8::Local<v8::Value> val, 168 const v8::PropertyCallbackInfo<void>& info) { 169 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 170 HandleScope scope(isolate); 171 172 Handle<JSReceiver> object = Utils::OpenHandle(*info.Holder()); 173 Handle<JSArray> array = Handle<JSArray>::cast(object); 174 Handle<Object> length_obj = Utils::OpenHandle(*val); 175 176 uint32_t length = 0; 177 if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) { 178 isolate->OptionalRescheduleException(false); 179 return; 180 } 181 182 JSArray::SetLength(array, length); 183 184 if (info.ShouldThrowOnError()) { 185 uint32_t actual_new_len = 0; 186 CHECK(array->length()->ToArrayLength(&actual_new_len)); 187 // Throw TypeError if there were non-deletable elements. 188 if (actual_new_len != length) { 189 Factory* factory = isolate->factory(); 190 isolate->Throw(*factory->NewTypeError( 191 MessageTemplate::kStrictDeleteProperty, 192 factory->NewNumberFromUint(actual_new_len - 1), array)); 193 isolate->OptionalRescheduleException(false); 194 } 195 } 196} 197 198 199Handle<AccessorInfo> Accessors::ArrayLengthInfo( 200 Isolate* isolate, PropertyAttributes attributes) { 201 return MakeAccessor(isolate, 202 isolate->factory()->length_string(), 203 &ArrayLengthGetter, 204 &ArrayLengthSetter, 205 attributes); 206} 207 208 209// 210// Accessors::StringLength 211// 212 213void Accessors::StringLengthGetter( 214 v8::Local<v8::Name> name, 215 const v8::PropertyCallbackInfo<v8::Value>& info) { 216 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 217 DisallowHeapAllocation no_allocation; 218 HandleScope scope(isolate); 219 220 // We have a slight impedance mismatch between the external API and the way we 221 // use callbacks internally: Externally, callbacks can only be used with 222 // v8::Object, but internally we have callbacks on entities which are higher 223 // in the hierarchy, in this case for String values. 224 225 Object* value = *Utils::OpenHandle(*v8::Local<v8::Value>(info.This())); 226 if (!value->IsString()) { 227 // Not a string value. That means that we either got a String wrapper or 228 // a Value with a String wrapper in its prototype chain. 229 value = JSValue::cast(*Utils::OpenHandle(*info.Holder()))->value(); 230 } 231 Object* result = Smi::FromInt(String::cast(value)->length()); 232 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate))); 233} 234 235 236Handle<AccessorInfo> Accessors::StringLengthInfo( 237 Isolate* isolate, PropertyAttributes attributes) { 238 return MakeAccessor(isolate, isolate->factory()->length_string(), 239 &StringLengthGetter, nullptr, attributes); 240} 241 242 243// 244// Accessors::ScriptColumnOffset 245// 246 247 248void Accessors::ScriptColumnOffsetGetter( 249 v8::Local<v8::Name> name, 250 const v8::PropertyCallbackInfo<v8::Value>& info) { 251 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 252 DisallowHeapAllocation no_allocation; 253 HandleScope scope(isolate); 254 Object* object = *Utils::OpenHandle(*info.Holder()); 255 Object* res = Smi::FromInt( 256 Script::cast(JSValue::cast(object)->value())->column_offset()); 257 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); 258} 259 260 261Handle<AccessorInfo> Accessors::ScriptColumnOffsetInfo( 262 Isolate* isolate, PropertyAttributes attributes) { 263 Handle<String> name(isolate->factory()->InternalizeOneByteString( 264 STATIC_CHAR_VECTOR("column_offset"))); 265 return MakeAccessor(isolate, name, &ScriptColumnOffsetGetter, nullptr, 266 attributes); 267} 268 269 270// 271// Accessors::ScriptId 272// 273 274 275void Accessors::ScriptIdGetter( 276 v8::Local<v8::Name> name, 277 const v8::PropertyCallbackInfo<v8::Value>& info) { 278 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 279 DisallowHeapAllocation no_allocation; 280 HandleScope scope(isolate); 281 Object* object = *Utils::OpenHandle(*info.Holder()); 282 Object* id = Smi::FromInt(Script::cast(JSValue::cast(object)->value())->id()); 283 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(id, isolate))); 284} 285 286 287Handle<AccessorInfo> Accessors::ScriptIdInfo( 288 Isolate* isolate, PropertyAttributes attributes) { 289 Handle<String> name( 290 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("id"))); 291 return MakeAccessor(isolate, name, &ScriptIdGetter, nullptr, attributes); 292} 293 294 295// 296// Accessors::ScriptName 297// 298 299 300void Accessors::ScriptNameGetter( 301 v8::Local<v8::Name> name, 302 const v8::PropertyCallbackInfo<v8::Value>& info) { 303 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 304 DisallowHeapAllocation no_allocation; 305 HandleScope scope(isolate); 306 Object* object = *Utils::OpenHandle(*info.Holder()); 307 Object* source = Script::cast(JSValue::cast(object)->value())->name(); 308 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate))); 309} 310 311 312Handle<AccessorInfo> Accessors::ScriptNameInfo( 313 Isolate* isolate, PropertyAttributes attributes) { 314 return MakeAccessor(isolate, isolate->factory()->name_string(), 315 &ScriptNameGetter, nullptr, attributes); 316} 317 318 319// 320// Accessors::ScriptSource 321// 322 323 324void Accessors::ScriptSourceGetter( 325 v8::Local<v8::Name> name, 326 const v8::PropertyCallbackInfo<v8::Value>& info) { 327 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 328 DisallowHeapAllocation no_allocation; 329 HandleScope scope(isolate); 330 Object* object = *Utils::OpenHandle(*info.Holder()); 331 Object* source = Script::cast(JSValue::cast(object)->value())->source(); 332 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate))); 333} 334 335 336Handle<AccessorInfo> Accessors::ScriptSourceInfo( 337 Isolate* isolate, PropertyAttributes attributes) { 338 return MakeAccessor(isolate, isolate->factory()->source_string(), 339 &ScriptSourceGetter, nullptr, attributes); 340} 341 342 343// 344// Accessors::ScriptLineOffset 345// 346 347 348void Accessors::ScriptLineOffsetGetter( 349 v8::Local<v8::Name> name, 350 const v8::PropertyCallbackInfo<v8::Value>& info) { 351 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 352 DisallowHeapAllocation no_allocation; 353 HandleScope scope(isolate); 354 Object* object = *Utils::OpenHandle(*info.Holder()); 355 Object* res = 356 Smi::FromInt(Script::cast(JSValue::cast(object)->value())->line_offset()); 357 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); 358} 359 360 361Handle<AccessorInfo> Accessors::ScriptLineOffsetInfo( 362 Isolate* isolate, PropertyAttributes attributes) { 363 Handle<String> name(isolate->factory()->InternalizeOneByteString( 364 STATIC_CHAR_VECTOR("line_offset"))); 365 return MakeAccessor(isolate, name, &ScriptLineOffsetGetter, nullptr, 366 attributes); 367} 368 369 370// 371// Accessors::ScriptType 372// 373 374 375void Accessors::ScriptTypeGetter( 376 v8::Local<v8::Name> name, 377 const v8::PropertyCallbackInfo<v8::Value>& info) { 378 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 379 DisallowHeapAllocation no_allocation; 380 HandleScope scope(isolate); 381 Object* object = *Utils::OpenHandle(*info.Holder()); 382 Object* res = 383 Smi::FromInt(Script::cast(JSValue::cast(object)->value())->type()); 384 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); 385} 386 387 388Handle<AccessorInfo> Accessors::ScriptTypeInfo( 389 Isolate* isolate, PropertyAttributes attributes) { 390 Handle<String> name( 391 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("type"))); 392 return MakeAccessor(isolate, name, &ScriptTypeGetter, nullptr, attributes); 393} 394 395 396// 397// Accessors::ScriptCompilationType 398// 399 400 401void Accessors::ScriptCompilationTypeGetter( 402 v8::Local<v8::Name> name, 403 const v8::PropertyCallbackInfo<v8::Value>& info) { 404 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 405 DisallowHeapAllocation no_allocation; 406 HandleScope scope(isolate); 407 Object* object = *Utils::OpenHandle(*info.Holder()); 408 Object* res = Smi::FromInt( 409 Script::cast(JSValue::cast(object)->value())->compilation_type()); 410 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); 411} 412 413 414Handle<AccessorInfo> Accessors::ScriptCompilationTypeInfo( 415 Isolate* isolate, PropertyAttributes attributes) { 416 Handle<String> name(isolate->factory()->InternalizeOneByteString( 417 STATIC_CHAR_VECTOR("compilation_type"))); 418 return MakeAccessor(isolate, name, &ScriptCompilationTypeGetter, nullptr, 419 attributes); 420} 421 422 423// 424// Accessors::ScriptGetLineEnds 425// 426 427 428void Accessors::ScriptLineEndsGetter( 429 v8::Local<v8::Name> name, 430 const v8::PropertyCallbackInfo<v8::Value>& info) { 431 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 432 HandleScope scope(isolate); 433 Handle<Object> object = Utils::OpenHandle(*info.Holder()); 434 Handle<Script> script( 435 Script::cast(Handle<JSValue>::cast(object)->value()), isolate); 436 Script::InitLineEnds(script); 437 DCHECK(script->line_ends()->IsFixedArray()); 438 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends())); 439 // We do not want anyone to modify this array from JS. 440 DCHECK(*line_ends == isolate->heap()->empty_fixed_array() || 441 line_ends->map() == isolate->heap()->fixed_cow_array_map()); 442 Handle<JSArray> js_array = 443 isolate->factory()->NewJSArrayWithElements(line_ends); 444 info.GetReturnValue().Set(Utils::ToLocal(js_array)); 445} 446 447 448Handle<AccessorInfo> Accessors::ScriptLineEndsInfo( 449 Isolate* isolate, PropertyAttributes attributes) { 450 Handle<String> name(isolate->factory()->InternalizeOneByteString( 451 STATIC_CHAR_VECTOR("line_ends"))); 452 return MakeAccessor(isolate, name, &ScriptLineEndsGetter, nullptr, 453 attributes); 454} 455 456 457// 458// Accessors::ScriptSourceUrl 459// 460 461 462void Accessors::ScriptSourceUrlGetter( 463 v8::Local<v8::Name> name, 464 const v8::PropertyCallbackInfo<v8::Value>& info) { 465 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 466 DisallowHeapAllocation no_allocation; 467 HandleScope scope(isolate); 468 Object* object = *Utils::OpenHandle(*info.Holder()); 469 Object* url = Script::cast(JSValue::cast(object)->value())->source_url(); 470 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(url, isolate))); 471} 472 473 474Handle<AccessorInfo> Accessors::ScriptSourceUrlInfo( 475 Isolate* isolate, PropertyAttributes attributes) { 476 return MakeAccessor(isolate, isolate->factory()->source_url_string(), 477 &ScriptSourceUrlGetter, nullptr, attributes); 478} 479 480 481// 482// Accessors::ScriptSourceMappingUrl 483// 484 485 486void Accessors::ScriptSourceMappingUrlGetter( 487 v8::Local<v8::Name> name, 488 const v8::PropertyCallbackInfo<v8::Value>& info) { 489 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 490 DisallowHeapAllocation no_allocation; 491 HandleScope scope(isolate); 492 Object* object = *Utils::OpenHandle(*info.Holder()); 493 Object* url = 494 Script::cast(JSValue::cast(object)->value())->source_mapping_url(); 495 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(url, isolate))); 496} 497 498 499Handle<AccessorInfo> Accessors::ScriptSourceMappingUrlInfo( 500 Isolate* isolate, PropertyAttributes attributes) { 501 return MakeAccessor(isolate, isolate->factory()->source_mapping_url_string(), 502 &ScriptSourceMappingUrlGetter, nullptr, attributes); 503} 504 505 506// 507// Accessors::ScriptIsEmbedderDebugScript 508// 509 510 511void Accessors::ScriptIsEmbedderDebugScriptGetter( 512 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 513 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 514 DisallowHeapAllocation no_allocation; 515 HandleScope scope(isolate); 516 Object* object = *Utils::OpenHandle(*info.Holder()); 517 bool is_embedder_debug_script = Script::cast(JSValue::cast(object)->value()) 518 ->origin_options() 519 .IsEmbedderDebugScript(); 520 Object* res = *isolate->factory()->ToBoolean(is_embedder_debug_script); 521 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); 522} 523 524 525Handle<AccessorInfo> Accessors::ScriptIsEmbedderDebugScriptInfo( 526 Isolate* isolate, PropertyAttributes attributes) { 527 Handle<String> name(isolate->factory()->InternalizeOneByteString( 528 STATIC_CHAR_VECTOR("is_debugger_script"))); 529 return MakeAccessor(isolate, name, &ScriptIsEmbedderDebugScriptGetter, 530 nullptr, attributes); 531} 532 533 534// 535// Accessors::ScriptGetContextData 536// 537 538 539void Accessors::ScriptContextDataGetter( 540 v8::Local<v8::Name> name, 541 const v8::PropertyCallbackInfo<v8::Value>& info) { 542 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 543 DisallowHeapAllocation no_allocation; 544 HandleScope scope(isolate); 545 Object* object = *Utils::OpenHandle(*info.Holder()); 546 Object* res = Script::cast(JSValue::cast(object)->value())->context_data(); 547 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate))); 548} 549 550 551Handle<AccessorInfo> Accessors::ScriptContextDataInfo( 552 Isolate* isolate, PropertyAttributes attributes) { 553 Handle<String> name(isolate->factory()->InternalizeOneByteString( 554 STATIC_CHAR_VECTOR("context_data"))); 555 return MakeAccessor(isolate, name, &ScriptContextDataGetter, nullptr, 556 attributes); 557} 558 559 560// 561// Accessors::ScriptGetEvalFromScript 562// 563 564 565void Accessors::ScriptEvalFromScriptGetter( 566 v8::Local<v8::Name> name, 567 const v8::PropertyCallbackInfo<v8::Value>& info) { 568 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 569 HandleScope scope(isolate); 570 Handle<Object> object = Utils::OpenHandle(*info.Holder()); 571 Handle<Script> script( 572 Script::cast(Handle<JSValue>::cast(object)->value()), isolate); 573 Handle<Object> result = isolate->factory()->undefined_value(); 574 if (!script->eval_from_shared()->IsUndefined(isolate)) { 575 Handle<SharedFunctionInfo> eval_from_shared( 576 SharedFunctionInfo::cast(script->eval_from_shared())); 577 if (eval_from_shared->script()->IsScript()) { 578 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script())); 579 result = Script::GetWrapper(eval_from_script); 580 } 581 } 582 583 info.GetReturnValue().Set(Utils::ToLocal(result)); 584} 585 586 587Handle<AccessorInfo> Accessors::ScriptEvalFromScriptInfo( 588 Isolate* isolate, PropertyAttributes attributes) { 589 Handle<String> name(isolate->factory()->InternalizeOneByteString( 590 STATIC_CHAR_VECTOR("eval_from_script"))); 591 return MakeAccessor(isolate, name, &ScriptEvalFromScriptGetter, nullptr, 592 attributes); 593} 594 595 596// 597// Accessors::ScriptGetEvalFromScriptPosition 598// 599 600 601void Accessors::ScriptEvalFromScriptPositionGetter( 602 v8::Local<v8::Name> name, 603 const v8::PropertyCallbackInfo<v8::Value>& info) { 604 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 605 HandleScope scope(isolate); 606 Handle<Object> object = Utils::OpenHandle(*info.Holder()); 607 Handle<Script> script( 608 Script::cast(Handle<JSValue>::cast(object)->value()), isolate); 609 Handle<Object> result = isolate->factory()->undefined_value(); 610 if (script->compilation_type() == Script::COMPILATION_TYPE_EVAL) { 611 result = Handle<Object>(Smi::FromInt(script->GetEvalPosition()), isolate); 612 } 613 info.GetReturnValue().Set(Utils::ToLocal(result)); 614} 615 616 617Handle<AccessorInfo> Accessors::ScriptEvalFromScriptPositionInfo( 618 Isolate* isolate, PropertyAttributes attributes) { 619 Handle<String> name(isolate->factory()->InternalizeOneByteString( 620 STATIC_CHAR_VECTOR("eval_from_script_position"))); 621 return MakeAccessor(isolate, name, &ScriptEvalFromScriptPositionGetter, 622 nullptr, attributes); 623} 624 625 626// 627// Accessors::ScriptGetEvalFromFunctionName 628// 629 630 631void Accessors::ScriptEvalFromFunctionNameGetter( 632 v8::Local<v8::Name> name, 633 const v8::PropertyCallbackInfo<v8::Value>& info) { 634 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 635 HandleScope scope(isolate); 636 Handle<Object> object = Utils::OpenHandle(*info.Holder()); 637 Handle<Script> script( 638 Script::cast(Handle<JSValue>::cast(object)->value()), isolate); 639 Handle<Object> result = isolate->factory()->undefined_value(); 640 if (!script->eval_from_shared()->IsUndefined(isolate)) { 641 Handle<SharedFunctionInfo> shared( 642 SharedFunctionInfo::cast(script->eval_from_shared())); 643 // Find the name of the function calling eval. 644 if (!shared->name()->IsUndefined(isolate)) { 645 result = Handle<Object>(shared->name(), isolate); 646 } else { 647 result = Handle<Object>(shared->inferred_name(), isolate); 648 } 649 } 650 info.GetReturnValue().Set(Utils::ToLocal(result)); 651} 652 653 654Handle<AccessorInfo> Accessors::ScriptEvalFromFunctionNameInfo( 655 Isolate* isolate, PropertyAttributes attributes) { 656 Handle<String> name(isolate->factory()->InternalizeOneByteString( 657 STATIC_CHAR_VECTOR("eval_from_function_name"))); 658 return MakeAccessor(isolate, name, &ScriptEvalFromFunctionNameGetter, nullptr, 659 attributes); 660} 661 662 663// 664// Accessors::FunctionPrototype 665// 666 667static Handle<Object> GetFunctionPrototype(Isolate* isolate, 668 Handle<JSFunction> function) { 669 if (!function->has_prototype()) { 670 Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function); 671 JSFunction::SetPrototype(function, proto); 672 } 673 return Handle<Object>(function->prototype(), isolate); 674} 675 676 677MUST_USE_RESULT static MaybeHandle<Object> SetFunctionPrototype( 678 Isolate* isolate, Handle<JSFunction> function, Handle<Object> value) { 679 JSFunction::SetPrototype(function, value); 680 DCHECK(function->prototype() == *value); 681 return function; 682} 683 684 685MaybeHandle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function, 686 Handle<Object> prototype) { 687 DCHECK(function->IsConstructor()); 688 Isolate* isolate = function->GetIsolate(); 689 return SetFunctionPrototype(isolate, function, prototype); 690} 691 692 693void Accessors::FunctionPrototypeGetter( 694 v8::Local<v8::Name> name, 695 const v8::PropertyCallbackInfo<v8::Value>& info) { 696 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 697 HandleScope scope(isolate); 698 Handle<JSFunction> function = 699 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 700 Handle<Object> result = GetFunctionPrototype(isolate, function); 701 info.GetReturnValue().Set(Utils::ToLocal(result)); 702} 703 704 705void Accessors::FunctionPrototypeSetter( 706 v8::Local<v8::Name> name, 707 v8::Local<v8::Value> val, 708 const v8::PropertyCallbackInfo<void>& info) { 709 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 710 HandleScope scope(isolate); 711 Handle<Object> value = Utils::OpenHandle(*val); 712 Handle<JSFunction> object = 713 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 714 if (SetFunctionPrototype(isolate, object, value).is_null()) { 715 isolate->OptionalRescheduleException(false); 716 } 717} 718 719 720Handle<AccessorInfo> Accessors::FunctionPrototypeInfo( 721 Isolate* isolate, PropertyAttributes attributes) { 722 return MakeAccessor(isolate, 723 isolate->factory()->prototype_string(), 724 &FunctionPrototypeGetter, 725 &FunctionPrototypeSetter, 726 attributes); 727} 728 729 730// 731// Accessors::FunctionLength 732// 733 734 735void Accessors::FunctionLengthGetter( 736 v8::Local<v8::Name> name, 737 const v8::PropertyCallbackInfo<v8::Value>& info) { 738 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 739 HandleScope scope(isolate); 740 Handle<JSFunction> function = 741 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 742 Handle<Object> result; 743 if (!JSFunction::GetLength(isolate, function).ToHandle(&result)) { 744 result = handle(Smi::FromInt(0), isolate); 745 isolate->OptionalRescheduleException(false); 746 } 747 748 info.GetReturnValue().Set(Utils::ToLocal(result)); 749} 750 751Handle<AccessorInfo> Accessors::FunctionLengthInfo( 752 Isolate* isolate, PropertyAttributes attributes) { 753 return MakeAccessor(isolate, isolate->factory()->length_string(), 754 &FunctionLengthGetter, &ReconfigureToDataProperty, 755 attributes); 756} 757 758 759// 760// Accessors::FunctionName 761// 762 763 764void Accessors::FunctionNameGetter( 765 v8::Local<v8::Name> name, 766 const v8::PropertyCallbackInfo<v8::Value>& info) { 767 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 768 HandleScope scope(isolate); 769 Handle<JSFunction> function = 770 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 771 Handle<Object> result = JSFunction::GetName(isolate, function); 772 info.GetReturnValue().Set(Utils::ToLocal(result)); 773} 774 775Handle<AccessorInfo> Accessors::FunctionNameInfo( 776 Isolate* isolate, PropertyAttributes attributes) { 777 return MakeAccessor(isolate, isolate->factory()->name_string(), 778 &FunctionNameGetter, &ReconfigureToDataProperty, 779 attributes); 780} 781 782 783// 784// Accessors::FunctionArguments 785// 786 787 788static Handle<Object> ArgumentsForInlinedFunction( 789 JavaScriptFrame* frame, 790 Handle<JSFunction> inlined_function, 791 int inlined_frame_index) { 792 Isolate* isolate = inlined_function->GetIsolate(); 793 Factory* factory = isolate->factory(); 794 795 TranslatedState translated_values(frame); 796 translated_values.Prepare(false, frame->fp()); 797 798 int argument_count = 0; 799 TranslatedFrame* translated_frame = 800 translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index, 801 &argument_count); 802 TranslatedFrame::iterator iter = translated_frame->begin(); 803 804 // Skip the function. 805 iter++; 806 807 // Skip the receiver. 808 iter++; 809 argument_count--; 810 811 Handle<JSObject> arguments = 812 factory->NewArgumentsObject(inlined_function, argument_count); 813 Handle<FixedArray> array = factory->NewFixedArray(argument_count); 814 bool should_deoptimize = false; 815 for (int i = 0; i < argument_count; ++i) { 816 // If we materialize any object, we should deopt because we might alias 817 // an object that was eliminated by escape analysis. 818 should_deoptimize = should_deoptimize || iter->IsMaterializedObject(); 819 Handle<Object> value = iter->GetValue(); 820 array->set(i, *value); 821 iter++; 822 } 823 arguments->set_elements(*array); 824 825 if (should_deoptimize) { 826 translated_values.StoreMaterializedValuesAndDeopt(); 827 } 828 829 // Return the freshly allocated arguments object. 830 return arguments; 831} 832 833 834static int FindFunctionInFrame(JavaScriptFrame* frame, 835 Handle<JSFunction> function) { 836 DisallowHeapAllocation no_allocation; 837 List<JSFunction*> functions(2); 838 frame->GetFunctions(&functions); 839 for (int i = functions.length() - 1; i >= 0; i--) { 840 if (functions[i] == *function) return i; 841 } 842 return -1; 843} 844 845 846namespace { 847 848Handle<Object> GetFunctionArguments(Isolate* isolate, 849 Handle<JSFunction> function) { 850 // Find the top invocation of the function by traversing frames. 851 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { 852 JavaScriptFrame* frame = it.frame(); 853 int function_index = FindFunctionInFrame(frame, function); 854 if (function_index < 0) continue; 855 856 if (function_index > 0) { 857 // The function in question was inlined. Inlined functions have the 858 // correct number of arguments and no allocated arguments object, so 859 // we can construct a fresh one by interpreting the function's 860 // deoptimization input data. 861 return ArgumentsForInlinedFunction(frame, function, function_index); 862 } 863 864 // Find the frame that holds the actual arguments passed to the function. 865 it.AdvanceToArgumentsFrame(); 866 frame = it.frame(); 867 868 // Get the number of arguments and construct an arguments object 869 // mirror for the right frame. 870 const int length = frame->ComputeParametersCount(); 871 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject( 872 function, length); 873 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); 874 875 // Copy the parameters to the arguments object. 876 DCHECK(array->length() == length); 877 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i)); 878 arguments->set_elements(*array); 879 880 // Return the freshly allocated arguments object. 881 return arguments; 882 } 883 884 // No frame corresponding to the given function found. Return null. 885 return isolate->factory()->null_value(); 886} 887 888} // namespace 889 890 891Handle<JSObject> Accessors::FunctionGetArguments(Handle<JSFunction> function) { 892 Handle<Object> arguments = 893 GetFunctionArguments(function->GetIsolate(), function); 894 CHECK(arguments->IsJSObject()); 895 return Handle<JSObject>::cast(arguments); 896} 897 898 899void Accessors::FunctionArgumentsGetter( 900 v8::Local<v8::Name> name, 901 const v8::PropertyCallbackInfo<v8::Value>& info) { 902 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 903 HandleScope scope(isolate); 904 Handle<JSFunction> function = 905 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 906 Handle<Object> result = 907 function->shared()->native() 908 ? Handle<Object>::cast(isolate->factory()->null_value()) 909 : GetFunctionArguments(isolate, function); 910 info.GetReturnValue().Set(Utils::ToLocal(result)); 911} 912 913 914Handle<AccessorInfo> Accessors::FunctionArgumentsInfo( 915 Isolate* isolate, PropertyAttributes attributes) { 916 return MakeAccessor(isolate, isolate->factory()->arguments_string(), 917 &FunctionArgumentsGetter, nullptr, attributes); 918} 919 920 921// 922// Accessors::FunctionCaller 923// 924 925 926static inline bool AllowAccessToFunction(Context* current_context, 927 JSFunction* function) { 928 return current_context->HasSameSecurityTokenAs(function->context()); 929} 930 931 932class FrameFunctionIterator { 933 public: 934 FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise) 935 : isolate_(isolate), 936 frame_iterator_(isolate), 937 functions_(2), 938 index_(0) { 939 GetFunctions(); 940 } 941 JSFunction* next() { 942 while (true) { 943 if (functions_.length() == 0) return NULL; 944 JSFunction* next_function = functions_[index_]; 945 index_--; 946 if (index_ < 0) { 947 GetFunctions(); 948 } 949 // Skip functions from other origins. 950 if (!AllowAccessToFunction(isolate_->context(), next_function)) continue; 951 return next_function; 952 } 953 } 954 955 // Iterate through functions until the first occurence of 'function'. 956 // Returns true if 'function' is found, and false if the iterator ends 957 // without finding it. 958 bool Find(JSFunction* function) { 959 JSFunction* next_function; 960 do { 961 next_function = next(); 962 if (next_function == function) return true; 963 } while (next_function != NULL); 964 return false; 965 } 966 967 private: 968 void GetFunctions() { 969 functions_.Rewind(0); 970 if (frame_iterator_.done()) return; 971 JavaScriptFrame* frame = frame_iterator_.frame(); 972 frame->GetFunctions(&functions_); 973 DCHECK(functions_.length() > 0); 974 frame_iterator_.Advance(); 975 index_ = functions_.length() - 1; 976 } 977 Isolate* isolate_; 978 JavaScriptFrameIterator frame_iterator_; 979 List<JSFunction*> functions_; 980 int index_; 981}; 982 983 984MaybeHandle<JSFunction> FindCaller(Isolate* isolate, 985 Handle<JSFunction> function) { 986 DisallowHeapAllocation no_allocation; 987 FrameFunctionIterator it(isolate, no_allocation); 988 if (function->shared()->native()) { 989 return MaybeHandle<JSFunction>(); 990 } 991 // Find the function from the frames. 992 if (!it.Find(*function)) { 993 // No frame corresponding to the given function found. Return null. 994 return MaybeHandle<JSFunction>(); 995 } 996 // Find previously called non-toplevel function. 997 JSFunction* caller; 998 do { 999 caller = it.next(); 1000 if (caller == NULL) return MaybeHandle<JSFunction>(); 1001 } while (caller->shared()->is_toplevel()); 1002 1003 // If caller is a built-in function and caller's caller is also built-in, 1004 // use that instead. 1005 JSFunction* potential_caller = caller; 1006 while (potential_caller != NULL && potential_caller->shared()->IsBuiltin()) { 1007 caller = potential_caller; 1008 potential_caller = it.next(); 1009 } 1010 if (!caller->shared()->native() && potential_caller != NULL) { 1011 caller = potential_caller; 1012 } 1013 // Censor if the caller is not a sloppy mode function. 1014 // Change from ES5, which used to throw, see: 1015 // https://bugs.ecmascript.org/show_bug.cgi?id=310 1016 if (is_strict(caller->shared()->language_mode())) { 1017 return MaybeHandle<JSFunction>(); 1018 } 1019 // Don't return caller from another security context. 1020 if (!AllowAccessToFunction(isolate->context(), caller)) { 1021 return MaybeHandle<JSFunction>(); 1022 } 1023 return Handle<JSFunction>(caller); 1024} 1025 1026 1027void Accessors::FunctionCallerGetter( 1028 v8::Local<v8::Name> name, 1029 const v8::PropertyCallbackInfo<v8::Value>& info) { 1030 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 1031 HandleScope scope(isolate); 1032 Handle<JSFunction> function = 1033 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder())); 1034 Handle<Object> result; 1035 MaybeHandle<JSFunction> maybe_caller; 1036 maybe_caller = FindCaller(isolate, function); 1037 Handle<JSFunction> caller; 1038 if (maybe_caller.ToHandle(&caller)) { 1039 result = caller; 1040 } else { 1041 result = isolate->factory()->null_value(); 1042 } 1043 info.GetReturnValue().Set(Utils::ToLocal(result)); 1044} 1045 1046 1047Handle<AccessorInfo> Accessors::FunctionCallerInfo( 1048 Isolate* isolate, PropertyAttributes attributes) { 1049 return MakeAccessor(isolate, isolate->factory()->caller_string(), 1050 &FunctionCallerGetter, nullptr, attributes); 1051} 1052 1053 1054// 1055// Accessors::BoundFunctionLength 1056// 1057 1058void Accessors::BoundFunctionLengthGetter( 1059 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 1060 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 1061 HandleScope scope(isolate); 1062 Handle<JSBoundFunction> function = 1063 Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder())); 1064 1065 Handle<Smi> target_length; 1066 Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()), 1067 isolate); 1068 if (!JSFunction::GetLength(isolate, target).ToHandle(&target_length)) { 1069 target_length = handle(Smi::FromInt(0), isolate); 1070 isolate->OptionalRescheduleException(false); 1071 return; 1072 } 1073 1074 int bound_length = function->bound_arguments()->length(); 1075 int length = Max(0, target_length->value() - bound_length); 1076 1077 Handle<Object> result(Smi::FromInt(length), isolate); 1078 info.GetReturnValue().Set(Utils::ToLocal(result)); 1079} 1080 1081Handle<AccessorInfo> Accessors::BoundFunctionLengthInfo( 1082 Isolate* isolate, PropertyAttributes attributes) { 1083 return MakeAccessor(isolate, isolate->factory()->length_string(), 1084 &BoundFunctionLengthGetter, &ReconfigureToDataProperty, 1085 attributes); 1086} 1087 1088// 1089// Accessors::BoundFunctionName 1090// 1091 1092void Accessors::BoundFunctionNameGetter( 1093 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 1094 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); 1095 HandleScope scope(isolate); 1096 Handle<JSBoundFunction> function = 1097 Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder())); 1098 Handle<Object> result; 1099 if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) { 1100 isolate->OptionalRescheduleException(false); 1101 return; 1102 } 1103 info.GetReturnValue().Set(Utils::ToLocal(result)); 1104} 1105 1106Handle<AccessorInfo> Accessors::BoundFunctionNameInfo( 1107 Isolate* isolate, PropertyAttributes attributes) { 1108 return MakeAccessor(isolate, isolate->factory()->name_string(), 1109 &BoundFunctionNameGetter, &ReconfigureToDataProperty, 1110 attributes); 1111} 1112 1113// 1114// Accessors::MakeModuleExport 1115// 1116 1117static void ModuleGetExport(v8::Local<v8::Name> property, 1118 const v8::PropertyCallbackInfo<v8::Value>& info) { 1119 JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder())); 1120 Context* context = Context::cast(instance->context()); 1121 DCHECK(context->IsModuleContext()); 1122 Isolate* isolate = instance->GetIsolate(); 1123 int slot = info.Data() 1124 ->Int32Value(info.GetIsolate()->GetCurrentContext()) 1125 .FromMaybe(-1); 1126 if (slot < 0 || slot >= context->length()) { 1127 Handle<Name> name = v8::Utils::OpenHandle(*property); 1128 1129 Handle<Object> exception = isolate->factory()->NewReferenceError( 1130 MessageTemplate::kNotDefined, name); 1131 isolate->ScheduleThrow(*exception); 1132 return; 1133 } 1134 Object* value = context->get(slot); 1135 if (value->IsTheHole(isolate)) { 1136 Handle<Name> name = v8::Utils::OpenHandle(*property); 1137 1138 Handle<Object> exception = isolate->factory()->NewReferenceError( 1139 MessageTemplate::kNotDefined, name); 1140 isolate->ScheduleThrow(*exception); 1141 return; 1142 } 1143 info.GetReturnValue().Set(v8::Utils::ToLocal(Handle<Object>(value, isolate))); 1144} 1145 1146 1147static void ModuleSetExport(v8::Local<v8::Name> property, 1148 v8::Local<v8::Value> value, 1149 const v8::PropertyCallbackInfo<void>& info) { 1150 if (!info.ShouldThrowOnError()) return; 1151 Handle<Name> name = v8::Utils::OpenHandle(*property); 1152 Isolate* isolate = name->GetIsolate(); 1153 Handle<Object> exception = 1154 isolate->factory()->NewTypeError(MessageTemplate::kNotDefined, name); 1155 isolate->ScheduleThrow(*exception); 1156} 1157 1158 1159Handle<AccessorInfo> Accessors::MakeModuleExport( 1160 Handle<String> name, 1161 int index, 1162 PropertyAttributes attributes) { 1163 Isolate* isolate = name->GetIsolate(); 1164 Handle<AccessorInfo> info = MakeAccessor(isolate, name, &ModuleGetExport, 1165 &ModuleSetExport, attributes); 1166 info->set_data(Smi::FromInt(index)); 1167 return info; 1168} 1169 1170 1171} // namespace internal 1172} // namespace v8 1173