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* FindInstanceOf(Isolate* isolate, Object* obj) { 46 for (Object* cur = obj; !cur->IsNull(); cur = cur->GetPrototype(isolate)) { 47 if (Is<C>(cur)) return C::cast(cur); 48 } 49 return NULL; 50} 51 52 53// Entry point that never should be called. 54MaybeObject* Accessors::IllegalSetter(Isolate* isolate, 55 JSObject*, 56 Object*, 57 void*) { 58 UNREACHABLE(); 59 return NULL; 60} 61 62 63Object* Accessors::IllegalGetAccessor(Isolate* isolate, 64 Object* object, 65 void*) { 66 UNREACHABLE(); 67 return object; 68} 69 70 71MaybeObject* Accessors::ReadOnlySetAccessor(Isolate* isolate, 72 JSObject*, 73 Object* value, 74 void*) { 75 // According to ECMA-262, section 8.6.2.2, page 28, setting 76 // read-only properties must be silently ignored. 77 return value; 78} 79 80 81static V8_INLINE bool CheckForName(Handle<String> name, 82 String* property_name, 83 int offset, 84 int* object_offset) { 85 if (name->Equals(property_name)) { 86 *object_offset = offset; 87 return true; 88 } 89 return false; 90} 91 92 93bool Accessors::IsJSObjectFieldAccessor( 94 Handle<Map> map, Handle<String> name, 95 int* object_offset) { 96 Isolate* isolate = map->GetIsolate(); 97 switch (map->instance_type()) { 98 case JS_ARRAY_TYPE: 99 return 100 CheckForName(name, isolate->heap()->length_string(), 101 JSArray::kLengthOffset, object_offset); 102 case JS_TYPED_ARRAY_TYPE: 103 return 104 CheckForName(name, isolate->heap()->length_string(), 105 JSTypedArray::kLengthOffset, object_offset) || 106 CheckForName(name, isolate->heap()->byte_length_string(), 107 JSTypedArray::kByteLengthOffset, object_offset) || 108 CheckForName(name, isolate->heap()->byte_offset_string(), 109 JSTypedArray::kByteOffsetOffset, object_offset) || 110 CheckForName(name, isolate->heap()->buffer_string(), 111 JSTypedArray::kBufferOffset, object_offset); 112 case JS_ARRAY_BUFFER_TYPE: 113 return 114 CheckForName(name, isolate->heap()->byte_length_string(), 115 JSArrayBuffer::kByteLengthOffset, object_offset); 116 case JS_DATA_VIEW_TYPE: 117 return 118 CheckForName(name, isolate->heap()->byte_length_string(), 119 JSDataView::kByteLengthOffset, object_offset) || 120 CheckForName(name, isolate->heap()->byte_offset_string(), 121 JSDataView::kByteOffsetOffset, object_offset) || 122 CheckForName(name, isolate->heap()->buffer_string(), 123 JSDataView::kBufferOffset, object_offset); 124 default: { 125 if (map->instance_type() < FIRST_NONSTRING_TYPE) { 126 return 127 CheckForName(name, isolate->heap()->length_string(), 128 String::kLengthOffset, object_offset); 129 } 130 return false; 131 } 132 } 133} 134 135 136// 137// Accessors::ArrayLength 138// 139 140 141MaybeObject* Accessors::ArrayGetLength(Isolate* isolate, 142 Object* object, 143 void*) { 144 // Traverse the prototype chain until we reach an array. 145 JSArray* holder = FindInstanceOf<JSArray>(isolate, object); 146 return holder == NULL ? Smi::FromInt(0) : holder->length(); 147} 148 149 150// The helper function will 'flatten' Number objects. 151Handle<Object> Accessors::FlattenNumber(Isolate* isolate, 152 Handle<Object> value) { 153 if (value->IsNumber() || !value->IsJSValue()) return value; 154 Handle<JSValue> wrapper = Handle<JSValue>::cast(value); 155 ASSERT(wrapper->GetIsolate()->context()->native_context()->number_function()-> 156 has_initial_map()); 157 if (wrapper->map() == 158 isolate->context()->native_context()->number_function()->initial_map()) { 159 return handle(wrapper->value(), isolate); 160 } 161 162 return value; 163} 164 165 166MaybeObject* Accessors::ArraySetLength(Isolate* isolate, 167 JSObject* object_raw, 168 Object* value_raw, 169 void*) { 170 HandleScope scope(isolate); 171 Handle<JSObject> object(object_raw, isolate); 172 Handle<Object> value(value_raw, isolate); 173 174 // This means one of the object's prototypes is a JSArray and the 175 // object does not have a 'length' property. Calling SetProperty 176 // causes an infinite loop. 177 if (!object->IsJSArray()) { 178 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(object, 179 isolate->factory()->length_string(), value, NONE); 180 RETURN_IF_EMPTY_HANDLE(isolate, result); 181 return *result; 182 } 183 184 value = FlattenNumber(isolate, value); 185 186 Handle<JSArray> array_handle = Handle<JSArray>::cast(object); 187 188 bool has_exception; 189 Handle<Object> uint32_v = 190 Execution::ToUint32(isolate, value, &has_exception); 191 if (has_exception) return Failure::Exception(); 192 Handle<Object> number_v = 193 Execution::ToNumber(isolate, value, &has_exception); 194 if (has_exception) return Failure::Exception(); 195 196 if (uint32_v->Number() == number_v->Number()) { 197 return array_handle->SetElementsLength(*uint32_v); 198 } 199 return isolate->Throw( 200 *isolate->factory()->NewRangeError("invalid_array_length", 201 HandleVector<Object>(NULL, 0))); 202} 203 204 205const AccessorDescriptor Accessors::ArrayLength = { 206 ArrayGetLength, 207 ArraySetLength, 208 0 209}; 210 211 212// 213// Accessors::StringLength 214// 215 216 217MaybeObject* Accessors::StringGetLength(Isolate* isolate, 218 Object* object, 219 void*) { 220 Object* value = object; 221 if (object->IsJSValue()) value = JSValue::cast(object)->value(); 222 if (value->IsString()) return Smi::FromInt(String::cast(value)->length()); 223 // If object is not a string we return 0 to be compatible with WebKit. 224 // Note: Firefox returns the length of ToString(object). 225 return Smi::FromInt(0); 226} 227 228 229const AccessorDescriptor Accessors::StringLength = { 230 StringGetLength, 231 IllegalSetter, 232 0 233}; 234 235 236// 237// Accessors::ScriptSource 238// 239 240 241MaybeObject* Accessors::ScriptGetSource(Isolate* isolate, 242 Object* object, 243 void*) { 244 Object* script = JSValue::cast(object)->value(); 245 return Script::cast(script)->source(); 246} 247 248 249const AccessorDescriptor Accessors::ScriptSource = { 250 ScriptGetSource, 251 IllegalSetter, 252 0 253}; 254 255 256// 257// Accessors::ScriptName 258// 259 260 261MaybeObject* Accessors::ScriptGetName(Isolate* isolate, 262 Object* object, 263 void*) { 264 Object* script = JSValue::cast(object)->value(); 265 return Script::cast(script)->name(); 266} 267 268 269const AccessorDescriptor Accessors::ScriptName = { 270 ScriptGetName, 271 IllegalSetter, 272 0 273}; 274 275 276// 277// Accessors::ScriptId 278// 279 280 281MaybeObject* Accessors::ScriptGetId(Isolate* isolate, Object* object, void*) { 282 Object* script = JSValue::cast(object)->value(); 283 return Script::cast(script)->id(); 284} 285 286 287const AccessorDescriptor Accessors::ScriptId = { 288 ScriptGetId, 289 IllegalSetter, 290 0 291}; 292 293 294// 295// Accessors::ScriptLineOffset 296// 297 298 299MaybeObject* Accessors::ScriptGetLineOffset(Isolate* isolate, 300 Object* object, 301 void*) { 302 Object* script = JSValue::cast(object)->value(); 303 return Script::cast(script)->line_offset(); 304} 305 306 307const AccessorDescriptor Accessors::ScriptLineOffset = { 308 ScriptGetLineOffset, 309 IllegalSetter, 310 0 311}; 312 313 314// 315// Accessors::ScriptColumnOffset 316// 317 318 319MaybeObject* Accessors::ScriptGetColumnOffset(Isolate* isolate, 320 Object* object, 321 void*) { 322 Object* script = JSValue::cast(object)->value(); 323 return Script::cast(script)->column_offset(); 324} 325 326 327const AccessorDescriptor Accessors::ScriptColumnOffset = { 328 ScriptGetColumnOffset, 329 IllegalSetter, 330 0 331}; 332 333 334// 335// Accessors::ScriptData 336// 337 338 339MaybeObject* Accessors::ScriptGetData(Isolate* isolate, 340 Object* object, 341 void*) { 342 Object* script = JSValue::cast(object)->value(); 343 return Script::cast(script)->data(); 344} 345 346 347const AccessorDescriptor Accessors::ScriptData = { 348 ScriptGetData, 349 IllegalSetter, 350 0 351}; 352 353 354// 355// Accessors::ScriptType 356// 357 358 359MaybeObject* Accessors::ScriptGetType(Isolate* isolate, 360 Object* object, 361 void*) { 362 Object* script = JSValue::cast(object)->value(); 363 return Script::cast(script)->type(); 364} 365 366 367const AccessorDescriptor Accessors::ScriptType = { 368 ScriptGetType, 369 IllegalSetter, 370 0 371}; 372 373 374// 375// Accessors::ScriptCompilationType 376// 377 378 379MaybeObject* Accessors::ScriptGetCompilationType(Isolate* isolate, 380 Object* object, 381 void*) { 382 Object* script = JSValue::cast(object)->value(); 383 return Smi::FromInt(Script::cast(script)->compilation_type()); 384} 385 386 387const AccessorDescriptor Accessors::ScriptCompilationType = { 388 ScriptGetCompilationType, 389 IllegalSetter, 390 0 391}; 392 393 394// 395// Accessors::ScriptGetLineEnds 396// 397 398 399MaybeObject* Accessors::ScriptGetLineEnds(Isolate* isolate, 400 Object* object, 401 void*) { 402 JSValue* wrapper = JSValue::cast(object); 403 HandleScope scope(isolate); 404 Handle<Script> script(Script::cast(wrapper->value()), isolate); 405 InitScriptLineEnds(script); 406 ASSERT(script->line_ends()->IsFixedArray()); 407 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends())); 408 // We do not want anyone to modify this array from JS. 409 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() || 410 line_ends->map() == isolate->heap()->fixed_cow_array_map()); 411 Handle<JSArray> js_array = 412 isolate->factory()->NewJSArrayWithElements(line_ends); 413 return *js_array; 414} 415 416 417const AccessorDescriptor Accessors::ScriptLineEnds = { 418 ScriptGetLineEnds, 419 IllegalSetter, 420 0 421}; 422 423 424// 425// Accessors::ScriptGetContextData 426// 427 428 429MaybeObject* Accessors::ScriptGetContextData(Isolate* isolate, 430 Object* object, 431 void*) { 432 Object* script = JSValue::cast(object)->value(); 433 return Script::cast(script)->context_data(); 434} 435 436 437const AccessorDescriptor Accessors::ScriptContextData = { 438 ScriptGetContextData, 439 IllegalSetter, 440 0 441}; 442 443 444// 445// Accessors::ScriptGetEvalFromScript 446// 447 448 449MaybeObject* Accessors::ScriptGetEvalFromScript(Isolate* isolate, 450 Object* object, 451 void*) { 452 Object* script = JSValue::cast(object)->value(); 453 if (!Script::cast(script)->eval_from_shared()->IsUndefined()) { 454 Handle<SharedFunctionInfo> eval_from_shared( 455 SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared())); 456 457 if (eval_from_shared->script()->IsScript()) { 458 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script())); 459 return *GetScriptWrapper(eval_from_script); 460 } 461 } 462 return isolate->heap()->undefined_value(); 463} 464 465 466const AccessorDescriptor Accessors::ScriptEvalFromScript = { 467 ScriptGetEvalFromScript, 468 IllegalSetter, 469 0 470}; 471 472 473// 474// Accessors::ScriptGetEvalFromScriptPosition 475// 476 477 478MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Isolate* isolate, 479 Object* object, 480 void*) { 481 Script* raw_script = Script::cast(JSValue::cast(object)->value()); 482 HandleScope scope(isolate); 483 Handle<Script> script(raw_script); 484 485 // If this is not a script compiled through eval there is no eval position. 486 if (script->compilation_type() != Script::COMPILATION_TYPE_EVAL) { 487 return script->GetHeap()->undefined_value(); 488 } 489 490 // Get the function from where eval was called and find the source position 491 // from the instruction offset. 492 Handle<Code> code(SharedFunctionInfo::cast( 493 script->eval_from_shared())->code()); 494 return Smi::FromInt(code->SourcePosition(code->instruction_start() + 495 script->eval_from_instructions_offset()->value())); 496} 497 498 499const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = { 500 ScriptGetEvalFromScriptPosition, 501 IllegalSetter, 502 0 503}; 504 505 506// 507// Accessors::ScriptGetEvalFromFunctionName 508// 509 510 511MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Isolate* isolate, 512 Object* object, 513 void*) { 514 Object* script = JSValue::cast(object)->value(); 515 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast( 516 Script::cast(script)->eval_from_shared())); 517 518 519 // Find the name of the function calling eval. 520 if (!shared->name()->IsUndefined()) { 521 return shared->name(); 522 } else { 523 return shared->inferred_name(); 524 } 525} 526 527 528const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = { 529 ScriptGetEvalFromFunctionName, 530 IllegalSetter, 531 0 532}; 533 534 535// 536// Accessors::FunctionPrototype 537// 538 539 540Handle<Object> Accessors::FunctionGetPrototype(Handle<JSFunction> function) { 541 CALL_HEAP_FUNCTION(function->GetIsolate(), 542 Accessors::FunctionGetPrototype(function->GetIsolate(), 543 *function, 544 NULL), 545 Object); 546} 547 548 549Handle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function, 550 Handle<Object> prototype) { 551 ASSERT(function->should_have_prototype()); 552 CALL_HEAP_FUNCTION(function->GetIsolate(), 553 Accessors::FunctionSetPrototype(function->GetIsolate(), 554 *function, 555 *prototype, 556 NULL), 557 Object); 558} 559 560 561MaybeObject* Accessors::FunctionGetPrototype(Isolate* isolate, 562 Object* object, 563 void*) { 564 JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, object); 565 if (function_raw == NULL) return isolate->heap()->undefined_value(); 566 while (!function_raw->should_have_prototype()) { 567 function_raw = FindInstanceOf<JSFunction>(isolate, 568 function_raw->GetPrototype()); 569 // There has to be one because we hit the getter. 570 ASSERT(function_raw != NULL); 571 } 572 573 if (!function_raw->has_prototype()) { 574 HandleScope scope(isolate); 575 Handle<JSFunction> function(function_raw); 576 Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function); 577 JSFunction::SetPrototype(function, proto); 578 function_raw = *function; 579 } 580 return function_raw->prototype(); 581} 582 583 584MaybeObject* Accessors::FunctionSetPrototype(Isolate* isolate, 585 JSObject* object_raw, 586 Object* value_raw, 587 void*) { 588 JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, object_raw); 589 if (function_raw == NULL) return isolate->heap()->undefined_value(); 590 591 HandleScope scope(isolate); 592 Handle<JSFunction> function(function_raw, isolate); 593 Handle<JSObject> object(object_raw, isolate); 594 Handle<Object> value(value_raw, isolate); 595 if (!function->should_have_prototype()) { 596 // Since we hit this accessor, object will have no prototype property. 597 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(object, 598 isolate->factory()->prototype_string(), value, NONE); 599 RETURN_IF_EMPTY_HANDLE(isolate, result); 600 return *result; 601 } 602 603 Handle<Object> old_value; 604 bool is_observed = 605 FLAG_harmony_observation && 606 *function == *object && 607 function->map()->is_observed(); 608 if (is_observed) { 609 if (function->has_prototype()) 610 old_value = handle(function->prototype(), isolate); 611 else 612 old_value = isolate->factory()->NewFunctionPrototype(function); 613 } 614 615 JSFunction::SetPrototype(function, value); 616 ASSERT(function->prototype() == *value); 617 618 if (is_observed && !old_value->SameValue(*value)) { 619 JSObject::EnqueueChangeRecord( 620 function, "update", isolate->factory()->prototype_string(), old_value); 621 } 622 623 return *function; 624} 625 626 627const AccessorDescriptor Accessors::FunctionPrototype = { 628 FunctionGetPrototype, 629 FunctionSetPrototype, 630 0 631}; 632 633 634// 635// Accessors::FunctionLength 636// 637 638 639MaybeObject* Accessors::FunctionGetLength(Isolate* isolate, 640 Object* object, 641 void*) { 642 JSFunction* function = FindInstanceOf<JSFunction>(isolate, object); 643 if (function == NULL) return Smi::FromInt(0); 644 // Check if already compiled. 645 if (function->shared()->is_compiled()) { 646 return Smi::FromInt(function->shared()->length()); 647 } 648 // If the function isn't compiled yet, the length is not computed correctly 649 // yet. Compile it now and return the right length. 650 HandleScope scope(isolate); 651 Handle<JSFunction> handle(function); 652 if (JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) { 653 return Smi::FromInt(handle->shared()->length()); 654 } 655 return Failure::Exception(); 656} 657 658 659const AccessorDescriptor Accessors::FunctionLength = { 660 FunctionGetLength, 661 ReadOnlySetAccessor, 662 0 663}; 664 665 666// 667// Accessors::FunctionName 668// 669 670 671MaybeObject* Accessors::FunctionGetName(Isolate* isolate, 672 Object* object, 673 void*) { 674 JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object); 675 return holder == NULL 676 ? isolate->heap()->undefined_value() 677 : holder->shared()->name(); 678} 679 680 681const AccessorDescriptor Accessors::FunctionName = { 682 FunctionGetName, 683 ReadOnlySetAccessor, 684 0 685}; 686 687 688// 689// Accessors::FunctionArguments 690// 691 692 693Handle<Object> Accessors::FunctionGetArguments(Handle<JSFunction> function) { 694 CALL_HEAP_FUNCTION(function->GetIsolate(), 695 Accessors::FunctionGetArguments(function->GetIsolate(), 696 *function, 697 NULL), 698 Object); 699} 700 701 702static MaybeObject* ConstructArgumentsObjectForInlinedFunction( 703 JavaScriptFrame* frame, 704 Handle<JSFunction> inlined_function, 705 int inlined_frame_index) { 706 Isolate* isolate = inlined_function->GetIsolate(); 707 Factory* factory = isolate->factory(); 708 Vector<SlotRef> args_slots = 709 SlotRef::ComputeSlotMappingForArguments( 710 frame, 711 inlined_frame_index, 712 inlined_function->shared()->formal_parameter_count()); 713 int args_count = args_slots.length(); 714 Handle<JSObject> arguments = 715 factory->NewArgumentsObject(inlined_function, args_count); 716 Handle<FixedArray> array = factory->NewFixedArray(args_count); 717 for (int i = 0; i < args_count; ++i) { 718 Handle<Object> value = args_slots[i].GetValue(isolate); 719 array->set(i, *value); 720 } 721 arguments->set_elements(*array); 722 args_slots.Dispose(); 723 724 // Return the freshly allocated arguments object. 725 return *arguments; 726} 727 728 729MaybeObject* Accessors::FunctionGetArguments(Isolate* isolate, 730 Object* object, 731 void*) { 732 HandleScope scope(isolate); 733 JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object); 734 if (holder == NULL) return isolate->heap()->undefined_value(); 735 Handle<JSFunction> function(holder, isolate); 736 737 if (function->shared()->native()) return isolate->heap()->null_value(); 738 // Find the top invocation of the function by traversing frames. 739 List<JSFunction*> functions(2); 740 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { 741 JavaScriptFrame* frame = it.frame(); 742 frame->GetFunctions(&functions); 743 for (int i = functions.length() - 1; i >= 0; i--) { 744 // Skip all frames that aren't invocations of the given function. 745 if (functions[i] != *function) continue; 746 747 if (i > 0) { 748 // The function in question was inlined. Inlined functions have the 749 // correct number of arguments and no allocated arguments object, so 750 // we can construct a fresh one by interpreting the function's 751 // deoptimization input data. 752 return ConstructArgumentsObjectForInlinedFunction(frame, function, i); 753 } 754 755 if (!frame->is_optimized()) { 756 // If there is an arguments variable in the stack, we return that. 757 Handle<ScopeInfo> scope_info(function->shared()->scope_info()); 758 int index = scope_info->StackSlotIndex( 759 isolate->heap()->arguments_string()); 760 if (index >= 0) { 761 Handle<Object> arguments(frame->GetExpression(index), isolate); 762 if (!arguments->IsArgumentsMarker()) return *arguments; 763 } 764 } 765 766 // If there is no arguments variable in the stack or we have an 767 // optimized frame, we find the frame that holds the actual arguments 768 // passed to the function. 769 it.AdvanceToArgumentsFrame(); 770 frame = it.frame(); 771 772 // Get the number of arguments and construct an arguments object 773 // mirror for the right frame. 774 const int length = frame->ComputeParametersCount(); 775 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject( 776 function, length); 777 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); 778 779 // Copy the parameters to the arguments object. 780 ASSERT(array->length() == length); 781 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i)); 782 arguments->set_elements(*array); 783 784 // Return the freshly allocated arguments object. 785 return *arguments; 786 } 787 functions.Rewind(0); 788 } 789 790 // No frame corresponding to the given function found. Return null. 791 return isolate->heap()->null_value(); 792} 793 794 795const AccessorDescriptor Accessors::FunctionArguments = { 796 FunctionGetArguments, 797 ReadOnlySetAccessor, 798 0 799}; 800 801 802// 803// Accessors::FunctionCaller 804// 805 806 807class FrameFunctionIterator { 808 public: 809 FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise) 810 : frame_iterator_(isolate), 811 functions_(2), 812 index_(0) { 813 GetFunctions(); 814 } 815 JSFunction* next() { 816 if (functions_.length() == 0) return NULL; 817 JSFunction* next_function = functions_[index_]; 818 index_--; 819 if (index_ < 0) { 820 GetFunctions(); 821 } 822 return next_function; 823 } 824 825 // Iterate through functions until the first occurence of 'function'. 826 // Returns true if 'function' is found, and false if the iterator ends 827 // without finding it. 828 bool Find(JSFunction* function) { 829 JSFunction* next_function; 830 do { 831 next_function = next(); 832 if (next_function == function) return true; 833 } while (next_function != NULL); 834 return false; 835 } 836 837 private: 838 void GetFunctions() { 839 functions_.Rewind(0); 840 if (frame_iterator_.done()) return; 841 JavaScriptFrame* frame = frame_iterator_.frame(); 842 frame->GetFunctions(&functions_); 843 ASSERT(functions_.length() > 0); 844 frame_iterator_.Advance(); 845 index_ = functions_.length() - 1; 846 } 847 JavaScriptFrameIterator frame_iterator_; 848 List<JSFunction*> functions_; 849 int index_; 850}; 851 852 853MaybeObject* Accessors::FunctionGetCaller(Isolate* isolate, 854 Object* object, 855 void*) { 856 HandleScope scope(isolate); 857 DisallowHeapAllocation no_allocation; 858 JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object); 859 if (holder == NULL) return isolate->heap()->undefined_value(); 860 if (holder->shared()->native()) return isolate->heap()->null_value(); 861 Handle<JSFunction> function(holder, isolate); 862 863 FrameFunctionIterator it(isolate, no_allocation); 864 865 // Find the function from the frames. 866 if (!it.Find(*function)) { 867 // No frame corresponding to the given function found. Return null. 868 return isolate->heap()->null_value(); 869 } 870 871 // Find previously called non-toplevel function. 872 JSFunction* caller; 873 do { 874 caller = it.next(); 875 if (caller == NULL) return isolate->heap()->null_value(); 876 } while (caller->shared()->is_toplevel()); 877 878 // If caller is a built-in function and caller's caller is also built-in, 879 // use that instead. 880 JSFunction* potential_caller = caller; 881 while (potential_caller != NULL && potential_caller->IsBuiltin()) { 882 caller = potential_caller; 883 potential_caller = it.next(); 884 } 885 if (!caller->shared()->native() && potential_caller != NULL) { 886 caller = potential_caller; 887 } 888 // If caller is bound, return null. This is compatible with JSC, and 889 // allows us to make bound functions use the strict function map 890 // and its associated throwing caller and arguments. 891 if (caller->shared()->bound()) { 892 return isolate->heap()->null_value(); 893 } 894 // Censor if the caller is not a classic mode function. 895 // Change from ES5, which used to throw, see: 896 // https://bugs.ecmascript.org/show_bug.cgi?id=310 897 if (!caller->shared()->is_classic_mode()) { 898 return isolate->heap()->null_value(); 899 } 900 901 return caller; 902} 903 904 905const AccessorDescriptor Accessors::FunctionCaller = { 906 FunctionGetCaller, 907 ReadOnlySetAccessor, 908 0 909}; 910 911 912// 913// Accessors::MakeModuleExport 914// 915 916static void ModuleGetExport( 917 v8::Local<v8::String> property, 918 const v8::PropertyCallbackInfo<v8::Value>& info) { 919 JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder())); 920 Context* context = Context::cast(instance->context()); 921 ASSERT(context->IsModuleContext()); 922 int slot = info.Data()->Int32Value(); 923 Object* value = context->get(slot); 924 Isolate* isolate = instance->GetIsolate(); 925 if (value->IsTheHole()) { 926 Handle<String> name = v8::Utils::OpenHandle(*property); 927 isolate->ScheduleThrow( 928 *isolate->factory()->NewReferenceError("not_defined", 929 HandleVector(&name, 1))); 930 return; 931 } 932 info.GetReturnValue().Set(v8::Utils::ToLocal(Handle<Object>(value, isolate))); 933} 934 935 936static void ModuleSetExport( 937 v8::Local<v8::String> property, 938 v8::Local<v8::Value> value, 939 const v8::PropertyCallbackInfo<v8::Value>& info) { 940 JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder())); 941 Context* context = Context::cast(instance->context()); 942 ASSERT(context->IsModuleContext()); 943 int slot = info.Data()->Int32Value(); 944 Object* old_value = context->get(slot); 945 if (old_value->IsTheHole()) { 946 Handle<String> name = v8::Utils::OpenHandle(*property); 947 Isolate* isolate = instance->GetIsolate(); 948 isolate->ScheduleThrow( 949 *isolate->factory()->NewReferenceError("not_defined", 950 HandleVector(&name, 1))); 951 return; 952 } 953 context->set(slot, *v8::Utils::OpenHandle(*value)); 954} 955 956 957Handle<AccessorInfo> Accessors::MakeModuleExport( 958 Handle<String> name, 959 int index, 960 PropertyAttributes attributes) { 961 Isolate* isolate = name->GetIsolate(); 962 Factory* factory = isolate->factory(); 963 Handle<ExecutableAccessorInfo> info = factory->NewExecutableAccessorInfo(); 964 info->set_property_attributes(attributes); 965 info->set_all_can_read(true); 966 info->set_all_can_write(true); 967 info->set_name(*name); 968 info->set_data(Smi::FromInt(index)); 969 Handle<Object> getter = v8::FromCData(isolate, &ModuleGetExport); 970 Handle<Object> setter = v8::FromCData(isolate, &ModuleSetExport); 971 info->set_getter(*getter); 972 if (!(attributes & ReadOnly)) info->set_setter(*setter); 973 return info; 974} 975 976 977} } // namespace v8::internal 978