1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 #include "accessors.h" 30 31 #include "contexts.h" 32 #include "deoptimizer.h" 33 #include "execution.h" 34 #include "factory.h" 35 #include "frames-inl.h" 36 #include "isolate.h" 37 #include "list-inl.h" 38 #include "property-details.h" 39 40 namespace v8 { 41 namespace internal { 42 43 44 template <class C> 45 static C* FindInPrototypeChain(Object* obj, bool* found_it) { 46 ASSERT(!*found_it); 47 Heap* heap = HEAP; 48 while (!Is<C>(obj)) { 49 if (obj == heap->null_value()) return NULL; 50 obj = obj->GetPrototype(); 51 } 52 *found_it = true; 53 return C::cast(obj); 54 } 55 56 57 // Entry point that never should be called. 58 MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) { 59 UNREACHABLE(); 60 return NULL; 61 } 62 63 64 Object* Accessors::IllegalGetAccessor(Object* object, void*) { 65 UNREACHABLE(); 66 return object; 67 } 68 69 70 MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) { 71 // According to ECMA-262, section 8.6.2.2, page 28, setting 72 // read-only properties must be silently ignored. 73 return value; 74 } 75 76 77 // 78 // Accessors::ArrayLength 79 // 80 81 82 MaybeObject* Accessors::ArrayGetLength(Object* object, void*) { 83 // Traverse the prototype chain until we reach an array. 84 bool found_it = false; 85 JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it); 86 if (!found_it) return Smi::FromInt(0); 87 return holder->length(); 88 } 89 90 91 // The helper function will 'flatten' Number objects. 92 Object* Accessors::FlattenNumber(Object* value) { 93 if (value->IsNumber() || !value->IsJSValue()) return value; 94 JSValue* wrapper = JSValue::cast(value); 95 ASSERT(Isolate::Current()->context()->global_context()->number_function()-> 96 has_initial_map()); 97 Map* number_map = Isolate::Current()->context()->global_context()-> 98 number_function()->initial_map(); 99 if (wrapper->map() == number_map) return wrapper->value(); 100 return value; 101 } 102 103 104 MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) { 105 Isolate* isolate = object->GetIsolate(); 106 107 // This means one of the object's prototypes is a JSArray and the 108 // object does not have a 'length' property. Calling SetProperty 109 // causes an infinite loop. 110 if (!object->IsJSArray()) { 111 return object->SetLocalPropertyIgnoreAttributes( 112 isolate->heap()->length_symbol(), value, NONE); 113 } 114 115 value = FlattenNumber(value); 116 117 // Need to call methods that may trigger GC. 118 HandleScope scope(isolate); 119 120 // Protect raw pointers. 121 Handle<JSObject> object_handle(object, isolate); 122 Handle<Object> value_handle(value, isolate); 123 124 bool has_exception; 125 Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception); 126 if (has_exception) return Failure::Exception(); 127 Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception); 128 if (has_exception) return Failure::Exception(); 129 130 if (uint32_v->Number() == number_v->Number()) { 131 return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v); 132 } 133 return isolate->Throw( 134 *isolate->factory()->NewRangeError("invalid_array_length", 135 HandleVector<Object>(NULL, 0))); 136 } 137 138 139 const AccessorDescriptor Accessors::ArrayLength = { 140 ArrayGetLength, 141 ArraySetLength, 142 0 143 }; 144 145 146 // 147 // Accessors::StringLength 148 // 149 150 151 MaybeObject* Accessors::StringGetLength(Object* object, void*) { 152 Object* value = object; 153 if (object->IsJSValue()) value = JSValue::cast(object)->value(); 154 if (value->IsString()) return Smi::FromInt(String::cast(value)->length()); 155 // If object is not a string we return 0 to be compatible with WebKit. 156 // Note: Firefox returns the length of ToString(object). 157 return Smi::FromInt(0); 158 } 159 160 161 const AccessorDescriptor Accessors::StringLength = { 162 StringGetLength, 163 IllegalSetter, 164 0 165 }; 166 167 168 // 169 // Accessors::ScriptSource 170 // 171 172 173 MaybeObject* Accessors::ScriptGetSource(Object* object, void*) { 174 Object* script = JSValue::cast(object)->value(); 175 return Script::cast(script)->source(); 176 } 177 178 179 const AccessorDescriptor Accessors::ScriptSource = { 180 ScriptGetSource, 181 IllegalSetter, 182 0 183 }; 184 185 186 // 187 // Accessors::ScriptName 188 // 189 190 191 MaybeObject* Accessors::ScriptGetName(Object* object, void*) { 192 Object* script = JSValue::cast(object)->value(); 193 return Script::cast(script)->name(); 194 } 195 196 197 const AccessorDescriptor Accessors::ScriptName = { 198 ScriptGetName, 199 IllegalSetter, 200 0 201 }; 202 203 204 // 205 // Accessors::ScriptId 206 // 207 208 209 MaybeObject* Accessors::ScriptGetId(Object* object, void*) { 210 Object* script = JSValue::cast(object)->value(); 211 return Script::cast(script)->id(); 212 } 213 214 215 const AccessorDescriptor Accessors::ScriptId = { 216 ScriptGetId, 217 IllegalSetter, 218 0 219 }; 220 221 222 // 223 // Accessors::ScriptLineOffset 224 // 225 226 227 MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) { 228 Object* script = JSValue::cast(object)->value(); 229 return Script::cast(script)->line_offset(); 230 } 231 232 233 const AccessorDescriptor Accessors::ScriptLineOffset = { 234 ScriptGetLineOffset, 235 IllegalSetter, 236 0 237 }; 238 239 240 // 241 // Accessors::ScriptColumnOffset 242 // 243 244 245 MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) { 246 Object* script = JSValue::cast(object)->value(); 247 return Script::cast(script)->column_offset(); 248 } 249 250 251 const AccessorDescriptor Accessors::ScriptColumnOffset = { 252 ScriptGetColumnOffset, 253 IllegalSetter, 254 0 255 }; 256 257 258 // 259 // Accessors::ScriptData 260 // 261 262 263 MaybeObject* Accessors::ScriptGetData(Object* object, void*) { 264 Object* script = JSValue::cast(object)->value(); 265 return Script::cast(script)->data(); 266 } 267 268 269 const AccessorDescriptor Accessors::ScriptData = { 270 ScriptGetData, 271 IllegalSetter, 272 0 273 }; 274 275 276 // 277 // Accessors::ScriptType 278 // 279 280 281 MaybeObject* Accessors::ScriptGetType(Object* object, void*) { 282 Object* script = JSValue::cast(object)->value(); 283 return Script::cast(script)->type(); 284 } 285 286 287 const AccessorDescriptor Accessors::ScriptType = { 288 ScriptGetType, 289 IllegalSetter, 290 0 291 }; 292 293 294 // 295 // Accessors::ScriptCompilationType 296 // 297 298 299 MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) { 300 Object* script = JSValue::cast(object)->value(); 301 return Script::cast(script)->compilation_type(); 302 } 303 304 305 const AccessorDescriptor Accessors::ScriptCompilationType = { 306 ScriptGetCompilationType, 307 IllegalSetter, 308 0 309 }; 310 311 312 // 313 // Accessors::ScriptGetLineEnds 314 // 315 316 317 MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) { 318 JSValue* wrapper = JSValue::cast(object); 319 Isolate* isolate = wrapper->GetIsolate(); 320 HandleScope scope(isolate); 321 Handle<Script> script(Script::cast(wrapper->value()), isolate); 322 InitScriptLineEnds(script); 323 ASSERT(script->line_ends()->IsFixedArray()); 324 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends())); 325 // We do not want anyone to modify this array from JS. 326 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() || 327 line_ends->map() == isolate->heap()->fixed_cow_array_map()); 328 Handle<JSArray> js_array = 329 isolate->factory()->NewJSArrayWithElements(line_ends); 330 return *js_array; 331 } 332 333 334 const AccessorDescriptor Accessors::ScriptLineEnds = { 335 ScriptGetLineEnds, 336 IllegalSetter, 337 0 338 }; 339 340 341 // 342 // Accessors::ScriptGetContextData 343 // 344 345 346 MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) { 347 Object* script = JSValue::cast(object)->value(); 348 return Script::cast(script)->context_data(); 349 } 350 351 352 const AccessorDescriptor Accessors::ScriptContextData = { 353 ScriptGetContextData, 354 IllegalSetter, 355 0 356 }; 357 358 359 // 360 // Accessors::ScriptGetEvalFromScript 361 // 362 363 364 MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) { 365 Object* script = JSValue::cast(object)->value(); 366 if (!Script::cast(script)->eval_from_shared()->IsUndefined()) { 367 Handle<SharedFunctionInfo> eval_from_shared( 368 SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared())); 369 370 if (eval_from_shared->script()->IsScript()) { 371 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script())); 372 return *GetScriptWrapper(eval_from_script); 373 } 374 } 375 return HEAP->undefined_value(); 376 } 377 378 379 const AccessorDescriptor Accessors::ScriptEvalFromScript = { 380 ScriptGetEvalFromScript, 381 IllegalSetter, 382 0 383 }; 384 385 386 // 387 // Accessors::ScriptGetEvalFromScriptPosition 388 // 389 390 391 MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) { 392 HandleScope scope; 393 Handle<Script> script(Script::cast(JSValue::cast(object)->value())); 394 395 // If this is not a script compiled through eval there is no eval position. 396 int compilation_type = Smi::cast(script->compilation_type())->value(); 397 if (compilation_type != Script::COMPILATION_TYPE_EVAL) { 398 return HEAP->undefined_value(); 399 } 400 401 // Get the function from where eval was called and find the source position 402 // from the instruction offset. 403 Handle<Code> code(SharedFunctionInfo::cast( 404 script->eval_from_shared())->code()); 405 return Smi::FromInt(code->SourcePosition(code->instruction_start() + 406 script->eval_from_instructions_offset()->value())); 407 } 408 409 410 const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = { 411 ScriptGetEvalFromScriptPosition, 412 IllegalSetter, 413 0 414 }; 415 416 417 // 418 // Accessors::ScriptGetEvalFromFunctionName 419 // 420 421 422 MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) { 423 Object* script = JSValue::cast(object)->value(); 424 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast( 425 Script::cast(script)->eval_from_shared())); 426 427 428 // Find the name of the function calling eval. 429 if (!shared->name()->IsUndefined()) { 430 return shared->name(); 431 } else { 432 return shared->inferred_name(); 433 } 434 } 435 436 437 const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = { 438 ScriptGetEvalFromFunctionName, 439 IllegalSetter, 440 0 441 }; 442 443 444 // 445 // Accessors::FunctionPrototype 446 // 447 448 449 MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) { 450 Heap* heap = Isolate::Current()->heap(); 451 bool found_it = false; 452 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it); 453 if (!found_it) return heap->undefined_value(); 454 while (!function->should_have_prototype()) { 455 found_it = false; 456 function = FindInPrototypeChain<JSFunction>(object->GetPrototype(), 457 &found_it); 458 // There has to be one because we hit the getter. 459 ASSERT(found_it); 460 } 461 462 if (!function->has_prototype()) { 463 Object* prototype; 464 { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function); 465 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype; 466 } 467 Object* result; 468 { MaybeObject* maybe_result = function->SetPrototype(prototype); 469 if (!maybe_result->ToObject(&result)) return maybe_result; 470 } 471 } 472 return function->prototype(); 473 } 474 475 476 MaybeObject* Accessors::FunctionSetPrototype(JSObject* object, 477 Object* value, 478 void*) { 479 Heap* heap = object->GetHeap(); 480 bool found_it = false; 481 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it); 482 if (!found_it) return heap->undefined_value(); 483 if (!function->should_have_prototype()) { 484 // Since we hit this accessor, object will have no prototype property. 485 return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(), 486 value, 487 NONE); 488 } 489 490 Object* prototype; 491 { MaybeObject* maybe_prototype = function->SetPrototype(value); 492 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype; 493 } 494 ASSERT(function->prototype() == value); 495 return function; 496 } 497 498 499 const AccessorDescriptor Accessors::FunctionPrototype = { 500 FunctionGetPrototype, 501 FunctionSetPrototype, 502 0 503 }; 504 505 506 // 507 // Accessors::FunctionLength 508 // 509 510 511 MaybeObject* Accessors::FunctionGetLength(Object* object, void*) { 512 bool found_it = false; 513 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it); 514 if (!found_it) return Smi::FromInt(0); 515 // Check if already compiled. 516 if (!function->shared()->is_compiled()) { 517 // If the function isn't compiled yet, the length is not computed 518 // correctly yet. Compile it now and return the right length. 519 HandleScope scope; 520 Handle<JSFunction> handle(function); 521 if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) { 522 return Failure::Exception(); 523 } 524 return Smi::FromInt(handle->shared()->length()); 525 } else { 526 return Smi::FromInt(function->shared()->length()); 527 } 528 } 529 530 531 const AccessorDescriptor Accessors::FunctionLength = { 532 FunctionGetLength, 533 ReadOnlySetAccessor, 534 0 535 }; 536 537 538 // 539 // Accessors::FunctionName 540 // 541 542 543 MaybeObject* Accessors::FunctionGetName(Object* object, void*) { 544 bool found_it = false; 545 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); 546 if (!found_it) return HEAP->undefined_value(); 547 return holder->shared()->name(); 548 } 549 550 551 const AccessorDescriptor Accessors::FunctionName = { 552 FunctionGetName, 553 ReadOnlySetAccessor, 554 0 555 }; 556 557 558 // 559 // Accessors::FunctionArguments 560 // 561 562 563 static MaybeObject* ConstructArgumentsObjectForInlinedFunction( 564 JavaScriptFrame* frame, 565 Handle<JSFunction> inlined_function, 566 int inlined_frame_index) { 567 Factory* factory = Isolate::Current()->factory(); 568 Vector<SlotRef> args_slots = 569 SlotRef::ComputeSlotMappingForArguments( 570 frame, 571 inlined_frame_index, 572 inlined_function->shared()->formal_parameter_count()); 573 int args_count = args_slots.length(); 574 Handle<JSObject> arguments = 575 factory->NewArgumentsObject(inlined_function, args_count); 576 Handle<FixedArray> array = factory->NewFixedArray(args_count); 577 for (int i = 0; i < args_count; ++i) { 578 Handle<Object> value = args_slots[i].GetValue(); 579 array->set(i, *value); 580 } 581 arguments->set_elements(*array); 582 args_slots.Dispose(); 583 584 // Return the freshly allocated arguments object. 585 return *arguments; 586 } 587 588 589 MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) { 590 Isolate* isolate = Isolate::Current(); 591 HandleScope scope(isolate); 592 bool found_it = false; 593 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); 594 if (!found_it) return isolate->heap()->undefined_value(); 595 Handle<JSFunction> function(holder, isolate); 596 597 if (function->shared()->native()) return isolate->heap()->null_value(); 598 // Find the top invocation of the function by traversing frames. 599 List<JSFunction*> functions(2); 600 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { 601 JavaScriptFrame* frame = it.frame(); 602 frame->GetFunctions(&functions); 603 for (int i = functions.length() - 1; i >= 0; i--) { 604 // Skip all frames that aren't invocations of the given function. 605 if (functions[i] != *function) continue; 606 607 if (i > 0) { 608 // The function in question was inlined. Inlined functions have the 609 // correct number of arguments and no allocated arguments object, so 610 // we can construct a fresh one by interpreting the function's 611 // deoptimization input data. 612 return ConstructArgumentsObjectForInlinedFunction(frame, function, i); 613 } 614 615 if (!frame->is_optimized()) { 616 // If there is an arguments variable in the stack, we return that. 617 Handle<ScopeInfo> scope_info(function->shared()->scope_info()); 618 int index = scope_info->StackSlotIndex( 619 isolate->heap()->arguments_symbol()); 620 if (index >= 0) { 621 Handle<Object> arguments(frame->GetExpression(index), isolate); 622 if (!arguments->IsArgumentsMarker()) return *arguments; 623 } 624 } 625 626 // If there is no arguments variable in the stack or we have an 627 // optimized frame, we find the frame that holds the actual arguments 628 // passed to the function. 629 it.AdvanceToArgumentsFrame(); 630 frame = it.frame(); 631 632 // Get the number of arguments and construct an arguments object 633 // mirror for the right frame. 634 const int length = frame->ComputeParametersCount(); 635 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject( 636 function, length); 637 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); 638 639 // Copy the parameters to the arguments object. 640 ASSERT(array->length() == length); 641 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i)); 642 arguments->set_elements(*array); 643 644 // Return the freshly allocated arguments object. 645 return *arguments; 646 } 647 functions.Rewind(0); 648 } 649 650 // No frame corresponding to the given function found. Return null. 651 return isolate->heap()->null_value(); 652 } 653 654 655 const AccessorDescriptor Accessors::FunctionArguments = { 656 FunctionGetArguments, 657 ReadOnlySetAccessor, 658 0 659 }; 660 661 662 // 663 // Accessors::FunctionCaller 664 // 665 666 667 static MaybeObject* CheckNonStrictCallerOrThrow( 668 Isolate* isolate, 669 JSFunction* caller) { 670 DisableAssertNoAllocation enable_allocation; 671 if (!caller->shared()->is_classic_mode()) { 672 return isolate->Throw( 673 *isolate->factory()->NewTypeError("strict_caller", 674 HandleVector<Object>(NULL, 0))); 675 } 676 return caller; 677 } 678 679 680 class FrameFunctionIterator { 681 public: 682 FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise) 683 : frame_iterator_(isolate), 684 functions_(2), 685 index_(0) { 686 GetFunctions(); 687 } 688 JSFunction* next() { 689 if (functions_.length() == 0) return NULL; 690 JSFunction* next_function = functions_[index_]; 691 index_--; 692 if (index_ < 0) { 693 GetFunctions(); 694 } 695 return next_function; 696 } 697 698 // Iterate through functions until the first occurence of 'function'. 699 // Returns true if 'function' is found, and false if the iterator ends 700 // without finding it. 701 bool Find(JSFunction* function) { 702 JSFunction* next_function; 703 do { 704 next_function = next(); 705 if (next_function == function) return true; 706 } while (next_function != NULL); 707 return false; 708 } 709 710 private: 711 void GetFunctions() { 712 functions_.Rewind(0); 713 if (frame_iterator_.done()) return; 714 JavaScriptFrame* frame = frame_iterator_.frame(); 715 frame->GetFunctions(&functions_); 716 ASSERT(functions_.length() > 0); 717 frame_iterator_.Advance(); 718 index_ = functions_.length() - 1; 719 } 720 JavaScriptFrameIterator frame_iterator_; 721 List<JSFunction*> functions_; 722 int index_; 723 }; 724 725 726 MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { 727 Isolate* isolate = Isolate::Current(); 728 HandleScope scope(isolate); 729 AssertNoAllocation no_alloc; 730 bool found_it = false; 731 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); 732 if (!found_it) return isolate->heap()->undefined_value(); 733 if (holder->shared()->native()) return isolate->heap()->null_value(); 734 Handle<JSFunction> function(holder, isolate); 735 736 FrameFunctionIterator it(isolate, no_alloc); 737 738 // Find the function from the frames. 739 if (!it.Find(*function)) { 740 // No frame corresponding to the given function found. Return null. 741 return isolate->heap()->null_value(); 742 } 743 744 // Find previously called non-toplevel function. 745 JSFunction* caller; 746 do { 747 caller = it.next(); 748 if (caller == NULL) return isolate->heap()->null_value(); 749 } while (caller->shared()->is_toplevel()); 750 751 // If caller is a built-in function and caller's caller is also built-in, 752 // use that instead. 753 JSFunction* potential_caller = caller; 754 while (potential_caller != NULL && potential_caller->IsBuiltin()) { 755 caller = potential_caller; 756 potential_caller = it.next(); 757 } 758 // If caller is bound, return null. This is compatible with JSC, and 759 // allows us to make bound functions use the strict function map 760 // and its associated throwing caller and arguments. 761 if (caller->shared()->bound()) { 762 return isolate->heap()->null_value(); 763 } 764 return CheckNonStrictCallerOrThrow(isolate, caller); 765 } 766 767 768 const AccessorDescriptor Accessors::FunctionCaller = { 769 FunctionGetCaller, 770 ReadOnlySetAccessor, 771 0 772 }; 773 774 775 // 776 // Accessors::ObjectPrototype 777 // 778 779 780 MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) { 781 Object* current = receiver->GetPrototype(); 782 while (current->IsJSObject() && 783 JSObject::cast(current)->map()->is_hidden_prototype()) { 784 current = current->GetPrototype(); 785 } 786 return current; 787 } 788 789 790 MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver, 791 Object* value, 792 void*) { 793 const bool skip_hidden_prototypes = true; 794 // To be consistent with other Set functions, return the value. 795 return receiver->SetPrototype(value, skip_hidden_prototypes); 796 } 797 798 799 const AccessorDescriptor Accessors::ObjectPrototype = { 800 ObjectGetPrototype, 801 ObjectSetPrototype, 802 0 803 }; 804 805 } } // namespace v8::internal 806