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