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 40namespace v8 { 41namespace internal { 42 43 44template <class C> 45static 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. 58MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) { 59 UNREACHABLE(); 60 return NULL; 61} 62 63 64Object* Accessors::IllegalGetAccessor(Object* object, void*) { 65 UNREACHABLE(); 66 return object; 67} 68 69 70MaybeObject* 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 82MaybeObject* 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. 92Object* 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 104MaybeObject* 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 139const AccessorDescriptor Accessors::ArrayLength = { 140 ArrayGetLength, 141 ArraySetLength, 142 0 143}; 144 145 146// 147// Accessors::StringLength 148// 149 150 151MaybeObject* 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 161const AccessorDescriptor Accessors::StringLength = { 162 StringGetLength, 163 IllegalSetter, 164 0 165}; 166 167 168// 169// Accessors::ScriptSource 170// 171 172 173MaybeObject* Accessors::ScriptGetSource(Object* object, void*) { 174 Object* script = JSValue::cast(object)->value(); 175 return Script::cast(script)->source(); 176} 177 178 179const AccessorDescriptor Accessors::ScriptSource = { 180 ScriptGetSource, 181 IllegalSetter, 182 0 183}; 184 185 186// 187// Accessors::ScriptName 188// 189 190 191MaybeObject* Accessors::ScriptGetName(Object* object, void*) { 192 Object* script = JSValue::cast(object)->value(); 193 return Script::cast(script)->name(); 194} 195 196 197const AccessorDescriptor Accessors::ScriptName = { 198 ScriptGetName, 199 IllegalSetter, 200 0 201}; 202 203 204// 205// Accessors::ScriptId 206// 207 208 209MaybeObject* Accessors::ScriptGetId(Object* object, void*) { 210 Object* script = JSValue::cast(object)->value(); 211 return Script::cast(script)->id(); 212} 213 214 215const AccessorDescriptor Accessors::ScriptId = { 216 ScriptGetId, 217 IllegalSetter, 218 0 219}; 220 221 222// 223// Accessors::ScriptLineOffset 224// 225 226 227MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) { 228 Object* script = JSValue::cast(object)->value(); 229 return Script::cast(script)->line_offset(); 230} 231 232 233const AccessorDescriptor Accessors::ScriptLineOffset = { 234 ScriptGetLineOffset, 235 IllegalSetter, 236 0 237}; 238 239 240// 241// Accessors::ScriptColumnOffset 242// 243 244 245MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) { 246 Object* script = JSValue::cast(object)->value(); 247 return Script::cast(script)->column_offset(); 248} 249 250 251const AccessorDescriptor Accessors::ScriptColumnOffset = { 252 ScriptGetColumnOffset, 253 IllegalSetter, 254 0 255}; 256 257 258// 259// Accessors::ScriptData 260// 261 262 263MaybeObject* Accessors::ScriptGetData(Object* object, void*) { 264 Object* script = JSValue::cast(object)->value(); 265 return Script::cast(script)->data(); 266} 267 268 269const AccessorDescriptor Accessors::ScriptData = { 270 ScriptGetData, 271 IllegalSetter, 272 0 273}; 274 275 276// 277// Accessors::ScriptType 278// 279 280 281MaybeObject* Accessors::ScriptGetType(Object* object, void*) { 282 Object* script = JSValue::cast(object)->value(); 283 return Script::cast(script)->type(); 284} 285 286 287const AccessorDescriptor Accessors::ScriptType = { 288 ScriptGetType, 289 IllegalSetter, 290 0 291}; 292 293 294// 295// Accessors::ScriptCompilationType 296// 297 298 299MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) { 300 Object* script = JSValue::cast(object)->value(); 301 return Script::cast(script)->compilation_type(); 302} 303 304 305const AccessorDescriptor Accessors::ScriptCompilationType = { 306 ScriptGetCompilationType, 307 IllegalSetter, 308 0 309}; 310 311 312// 313// Accessors::ScriptGetLineEnds 314// 315 316 317MaybeObject* 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 334const AccessorDescriptor Accessors::ScriptLineEnds = { 335 ScriptGetLineEnds, 336 IllegalSetter, 337 0 338}; 339 340 341// 342// Accessors::ScriptGetContextData 343// 344 345 346MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) { 347 Object* script = JSValue::cast(object)->value(); 348 return Script::cast(script)->context_data(); 349} 350 351 352const AccessorDescriptor Accessors::ScriptContextData = { 353 ScriptGetContextData, 354 IllegalSetter, 355 0 356}; 357 358 359// 360// Accessors::ScriptGetEvalFromScript 361// 362 363 364MaybeObject* 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 379const AccessorDescriptor Accessors::ScriptEvalFromScript = { 380 ScriptGetEvalFromScript, 381 IllegalSetter, 382 0 383}; 384 385 386// 387// Accessors::ScriptGetEvalFromScriptPosition 388// 389 390 391MaybeObject* 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 410const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = { 411 ScriptGetEvalFromScriptPosition, 412 IllegalSetter, 413 0 414}; 415 416 417// 418// Accessors::ScriptGetEvalFromFunctionName 419// 420 421 422MaybeObject* 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 437const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = { 438 ScriptGetEvalFromFunctionName, 439 IllegalSetter, 440 0 441}; 442 443 444// 445// Accessors::FunctionPrototype 446// 447 448 449MaybeObject* 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 476MaybeObject* 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 499const AccessorDescriptor Accessors::FunctionPrototype = { 500 FunctionGetPrototype, 501 FunctionSetPrototype, 502 0 503}; 504 505 506// 507// Accessors::FunctionLength 508// 509 510 511MaybeObject* 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 531const AccessorDescriptor Accessors::FunctionLength = { 532 FunctionGetLength, 533 ReadOnlySetAccessor, 534 0 535}; 536 537 538// 539// Accessors::FunctionName 540// 541 542 543MaybeObject* 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 551const AccessorDescriptor Accessors::FunctionName = { 552 FunctionGetName, 553 ReadOnlySetAccessor, 554 0 555}; 556 557 558// 559// Accessors::FunctionArguments 560// 561 562 563static 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 589MaybeObject* 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 655const AccessorDescriptor Accessors::FunctionArguments = { 656 FunctionGetArguments, 657 ReadOnlySetAccessor, 658 0 659}; 660 661 662// 663// Accessors::FunctionCaller 664// 665 666 667static 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 680class 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 726MaybeObject* 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 768const AccessorDescriptor Accessors::FunctionCaller = { 769 FunctionGetCaller, 770 ReadOnlySetAccessor, 771 0 772}; 773 774 775// 776// Accessors::ObjectPrototype 777// 778 779 780MaybeObject* 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 790MaybeObject* 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 799const AccessorDescriptor Accessors::ObjectPrototype = { 800 ObjectGetPrototype, 801 ObjectSetPrototype, 802 0 803}; 804 805} } // namespace v8::internal 806