1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 #include "accessors.h" 30 31 #include "contexts.h" 32 #include "deoptimizer.h" 33 #include "execution.h" 34 #include "factory.h" 35 #include "frames-inl.h" 36 #include "isolate.h" 37 #include "list-inl.h" 38 #include "property-details.h" 39 40 namespace v8 { 41 namespace internal { 42 43 44 template <class C> 45 static C* 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. 54 MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) { 55 UNREACHABLE(); 56 return NULL; 57 } 58 59 60 Object* Accessors::IllegalGetAccessor(Object* object, void*) { 61 UNREACHABLE(); 62 return object; 63 } 64 65 66 MaybeObject* 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 78 MaybeObject* 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. 86 Object* 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 98 MaybeObject* 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 133 const AccessorDescriptor Accessors::ArrayLength = { 134 ArrayGetLength, 135 ArraySetLength, 136 0 137 }; 138 139 140 // 141 // Accessors::StringLength 142 // 143 144 145 MaybeObject* 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 155 const AccessorDescriptor Accessors::StringLength = { 156 StringGetLength, 157 IllegalSetter, 158 0 159 }; 160 161 162 // 163 // Accessors::ScriptSource 164 // 165 166 167 MaybeObject* Accessors::ScriptGetSource(Object* object, void*) { 168 Object* script = JSValue::cast(object)->value(); 169 return Script::cast(script)->source(); 170 } 171 172 173 const AccessorDescriptor Accessors::ScriptSource = { 174 ScriptGetSource, 175 IllegalSetter, 176 0 177 }; 178 179 180 // 181 // Accessors::ScriptName 182 // 183 184 185 MaybeObject* Accessors::ScriptGetName(Object* object, void*) { 186 Object* script = JSValue::cast(object)->value(); 187 return Script::cast(script)->name(); 188 } 189 190 191 const AccessorDescriptor Accessors::ScriptName = { 192 ScriptGetName, 193 IllegalSetter, 194 0 195 }; 196 197 198 // 199 // Accessors::ScriptId 200 // 201 202 203 MaybeObject* Accessors::ScriptGetId(Object* object, void*) { 204 Object* script = JSValue::cast(object)->value(); 205 return Script::cast(script)->id(); 206 } 207 208 209 const AccessorDescriptor Accessors::ScriptId = { 210 ScriptGetId, 211 IllegalSetter, 212 0 213 }; 214 215 216 // 217 // Accessors::ScriptLineOffset 218 // 219 220 221 MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) { 222 Object* script = JSValue::cast(object)->value(); 223 return Script::cast(script)->line_offset(); 224 } 225 226 227 const AccessorDescriptor Accessors::ScriptLineOffset = { 228 ScriptGetLineOffset, 229 IllegalSetter, 230 0 231 }; 232 233 234 // 235 // Accessors::ScriptColumnOffset 236 // 237 238 239 MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) { 240 Object* script = JSValue::cast(object)->value(); 241 return Script::cast(script)->column_offset(); 242 } 243 244 245 const AccessorDescriptor Accessors::ScriptColumnOffset = { 246 ScriptGetColumnOffset, 247 IllegalSetter, 248 0 249 }; 250 251 252 // 253 // Accessors::ScriptData 254 // 255 256 257 MaybeObject* Accessors::ScriptGetData(Object* object, void*) { 258 Object* script = JSValue::cast(object)->value(); 259 return Script::cast(script)->data(); 260 } 261 262 263 const AccessorDescriptor Accessors::ScriptData = { 264 ScriptGetData, 265 IllegalSetter, 266 0 267 }; 268 269 270 // 271 // Accessors::ScriptType 272 // 273 274 275 MaybeObject* Accessors::ScriptGetType(Object* object, void*) { 276 Object* script = JSValue::cast(object)->value(); 277 return Script::cast(script)->type(); 278 } 279 280 281 const AccessorDescriptor Accessors::ScriptType = { 282 ScriptGetType, 283 IllegalSetter, 284 0 285 }; 286 287 288 // 289 // Accessors::ScriptCompilationType 290 // 291 292 293 MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) { 294 Object* script = JSValue::cast(object)->value(); 295 return Smi::FromInt(Script::cast(script)->compilation_type()); 296 } 297 298 299 const AccessorDescriptor Accessors::ScriptCompilationType = { 300 ScriptGetCompilationType, 301 IllegalSetter, 302 0 303 }; 304 305 306 // 307 // Accessors::ScriptGetLineEnds 308 // 309 310 311 MaybeObject* 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 328 const AccessorDescriptor Accessors::ScriptLineEnds = { 329 ScriptGetLineEnds, 330 IllegalSetter, 331 0 332 }; 333 334 335 // 336 // Accessors::ScriptGetContextData 337 // 338 339 340 MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) { 341 Object* script = JSValue::cast(object)->value(); 342 return Script::cast(script)->context_data(); 343 } 344 345 346 const AccessorDescriptor Accessors::ScriptContextData = { 347 ScriptGetContextData, 348 IllegalSetter, 349 0 350 }; 351 352 353 // 354 // Accessors::ScriptGetEvalFromScript 355 // 356 357 358 MaybeObject* 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 373 const AccessorDescriptor Accessors::ScriptEvalFromScript = { 374 ScriptGetEvalFromScript, 375 IllegalSetter, 376 0 377 }; 378 379 380 // 381 // Accessors::ScriptGetEvalFromScriptPosition 382 // 383 384 385 MaybeObject* 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 404 const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = { 405 ScriptGetEvalFromScriptPosition, 406 IllegalSetter, 407 0 408 }; 409 410 411 // 412 // Accessors::ScriptGetEvalFromFunctionName 413 // 414 415 416 MaybeObject* 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 431 const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = { 432 ScriptGetEvalFromFunctionName, 433 IllegalSetter, 434 0 435 }; 436 437 438 // 439 // Accessors::FunctionPrototype 440 // 441 442 443 Handle<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 450 MaybeObject* 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 472 MaybeObject* 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 514 const AccessorDescriptor Accessors::FunctionPrototype = { 515 FunctionGetPrototype, 516 FunctionSetPrototype, 517 0 518 }; 519 520 521 // 522 // Accessors::FunctionLength 523 // 524 525 526 MaybeObject* 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 545 const AccessorDescriptor Accessors::FunctionLength = { 546 FunctionGetLength, 547 ReadOnlySetAccessor, 548 0 549 }; 550 551 552 // 553 // Accessors::FunctionName 554 // 555 556 557 MaybeObject* 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 566 const AccessorDescriptor Accessors::FunctionName = { 567 FunctionGetName, 568 ReadOnlySetAccessor, 569 0 570 }; 571 572 573 // 574 // Accessors::FunctionArguments 575 // 576 577 578 Handle<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 585 static 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 612 MaybeObject* 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 677 const AccessorDescriptor Accessors::FunctionArguments = { 678 FunctionGetArguments, 679 ReadOnlySetAccessor, 680 0 681 }; 682 683 684 // 685 // Accessors::FunctionCaller 686 // 687 688 689 class 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 735 MaybeObject* 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 786 const AccessorDescriptor Accessors::FunctionCaller = { 787 FunctionGetCaller, 788 ReadOnlySetAccessor, 789 0 790 }; 791 792 793 // 794 // Accessors::MakeModuleExport 795 // 796 797 static 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 817 static 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 838 Handle<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