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