1 // Copyright 2006-2009 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 "api.h" 31 #include "arguments.h" 32 #include "bootstrapper.h" 33 #include "debug.h" 34 #include "execution.h" 35 #include "objects-inl.h" 36 #include "macro-assembler.h" 37 #include "scanner.h" 38 #include "scopeinfo.h" 39 #include "string-stream.h" 40 #include "utils.h" 41 42 #ifdef ENABLE_DISASSEMBLER 43 #include "disassembler.h" 44 #endif 45 46 47 namespace v8 { 48 namespace internal { 49 50 // Getters and setters are stored in a fixed array property. These are 51 // constants for their indices. 52 const int kGetterIndex = 0; 53 const int kSetterIndex = 1; 54 55 56 static Object* CreateJSValue(JSFunction* constructor, Object* value) { 57 Object* result = Heap::AllocateJSObject(constructor); 58 if (result->IsFailure()) return result; 59 JSValue::cast(result)->set_value(value); 60 return result; 61 } 62 63 64 Object* Object::ToObject(Context* global_context) { 65 if (IsNumber()) { 66 return CreateJSValue(global_context->number_function(), this); 67 } else if (IsBoolean()) { 68 return CreateJSValue(global_context->boolean_function(), this); 69 } else if (IsString()) { 70 return CreateJSValue(global_context->string_function(), this); 71 } 72 ASSERT(IsJSObject()); 73 return this; 74 } 75 76 77 Object* Object::ToObject() { 78 Context* global_context = Top::context()->global_context(); 79 if (IsJSObject()) { 80 return this; 81 } else if (IsNumber()) { 82 return CreateJSValue(global_context->number_function(), this); 83 } else if (IsBoolean()) { 84 return CreateJSValue(global_context->boolean_function(), this); 85 } else if (IsString()) { 86 return CreateJSValue(global_context->string_function(), this); 87 } 88 89 // Throw a type error. 90 return Failure::InternalError(); 91 } 92 93 94 Object* Object::ToBoolean() { 95 if (IsTrue()) return Heap::true_value(); 96 if (IsFalse()) return Heap::false_value(); 97 if (IsSmi()) { 98 return Heap::ToBoolean(Smi::cast(this)->value() != 0); 99 } 100 if (IsUndefined() || IsNull()) return Heap::false_value(); 101 // Undetectable object is false 102 if (IsUndetectableObject()) { 103 return Heap::false_value(); 104 } 105 if (IsString()) { 106 return Heap::ToBoolean(String::cast(this)->length() != 0); 107 } 108 if (IsHeapNumber()) { 109 return HeapNumber::cast(this)->HeapNumberToBoolean(); 110 } 111 return Heap::true_value(); 112 } 113 114 115 void Object::Lookup(String* name, LookupResult* result) { 116 if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result); 117 Object* holder = NULL; 118 Context* global_context = Top::context()->global_context(); 119 if (IsString()) { 120 holder = global_context->string_function()->instance_prototype(); 121 } else if (IsNumber()) { 122 holder = global_context->number_function()->instance_prototype(); 123 } else if (IsBoolean()) { 124 holder = global_context->boolean_function()->instance_prototype(); 125 } 126 ASSERT(holder != NULL); // Cannot handle null or undefined. 127 JSObject::cast(holder)->Lookup(name, result); 128 } 129 130 131 Object* Object::GetPropertyWithReceiver(Object* receiver, 132 String* name, 133 PropertyAttributes* attributes) { 134 LookupResult result; 135 Lookup(name, &result); 136 Object* value = GetProperty(receiver, &result, name, attributes); 137 ASSERT(*attributes <= ABSENT); 138 return value; 139 } 140 141 142 Object* Object::GetPropertyWithCallback(Object* receiver, 143 Object* structure, 144 String* name, 145 Object* holder) { 146 // To accommodate both the old and the new api we switch on the 147 // data structure used to store the callbacks. Eventually proxy 148 // callbacks should be phased out. 149 if (structure->IsProxy()) { 150 AccessorDescriptor* callback = 151 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy()); 152 Object* value = (callback->getter)(receiver, callback->data); 153 RETURN_IF_SCHEDULED_EXCEPTION(); 154 return value; 155 } 156 157 // api style callbacks. 158 if (structure->IsAccessorInfo()) { 159 AccessorInfo* data = AccessorInfo::cast(structure); 160 Object* fun_obj = data->getter(); 161 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); 162 HandleScope scope; 163 JSObject* self = JSObject::cast(receiver); 164 JSObject* holder_handle = JSObject::cast(holder); 165 Handle<String> key(name); 166 LOG(ApiNamedPropertyAccess("load", self, name)); 167 CustomArguments args(data->data(), self, holder_handle); 168 v8::AccessorInfo info(args.end()); 169 v8::Handle<v8::Value> result; 170 { 171 // Leaving JavaScript. 172 VMState state(EXTERNAL); 173 result = call_fun(v8::Utils::ToLocal(key), info); 174 } 175 RETURN_IF_SCHEDULED_EXCEPTION(); 176 if (result.IsEmpty()) return Heap::undefined_value(); 177 return *v8::Utils::OpenHandle(*result); 178 } 179 180 // __defineGetter__ callback 181 if (structure->IsFixedArray()) { 182 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); 183 if (getter->IsJSFunction()) { 184 return Object::GetPropertyWithDefinedGetter(receiver, 185 JSFunction::cast(getter)); 186 } 187 // Getter is not a function. 188 return Heap::undefined_value(); 189 } 190 191 UNREACHABLE(); 192 return 0; 193 } 194 195 196 Object* Object::GetPropertyWithDefinedGetter(Object* receiver, 197 JSFunction* getter) { 198 HandleScope scope; 199 Handle<JSFunction> fun(JSFunction::cast(getter)); 200 Handle<Object> self(receiver); 201 #ifdef ENABLE_DEBUGGER_SUPPORT 202 // Handle stepping into a getter if step into is active. 203 if (Debug::StepInActive()) { 204 Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false); 205 } 206 #endif 207 bool has_pending_exception; 208 Handle<Object> result = 209 Execution::Call(fun, self, 0, NULL, &has_pending_exception); 210 // Check for pending exception and return the result. 211 if (has_pending_exception) return Failure::Exception(); 212 return *result; 213 } 214 215 216 // Only deal with CALLBACKS and INTERCEPTOR 217 Object* JSObject::GetPropertyWithFailedAccessCheck( 218 Object* receiver, 219 LookupResult* result, 220 String* name, 221 PropertyAttributes* attributes) { 222 if (result->IsProperty()) { 223 switch (result->type()) { 224 case CALLBACKS: { 225 // Only allow API accessors. 226 Object* obj = result->GetCallbackObject(); 227 if (obj->IsAccessorInfo()) { 228 AccessorInfo* info = AccessorInfo::cast(obj); 229 if (info->all_can_read()) { 230 *attributes = result->GetAttributes(); 231 return GetPropertyWithCallback(receiver, 232 result->GetCallbackObject(), 233 name, 234 result->holder()); 235 } 236 } 237 break; 238 } 239 case NORMAL: 240 case FIELD: 241 case CONSTANT_FUNCTION: { 242 // Search ALL_CAN_READ accessors in prototype chain. 243 LookupResult r; 244 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r); 245 if (r.IsProperty()) { 246 return GetPropertyWithFailedAccessCheck(receiver, 247 &r, 248 name, 249 attributes); 250 } 251 break; 252 } 253 case INTERCEPTOR: { 254 // If the object has an interceptor, try real named properties. 255 // No access check in GetPropertyAttributeWithInterceptor. 256 LookupResult r; 257 result->holder()->LookupRealNamedProperty(name, &r); 258 if (r.IsProperty()) { 259 return GetPropertyWithFailedAccessCheck(receiver, 260 &r, 261 name, 262 attributes); 263 } 264 break; 265 } 266 default: 267 UNREACHABLE(); 268 } 269 } 270 271 // No accessible property found. 272 *attributes = ABSENT; 273 Top::ReportFailedAccessCheck(this, v8::ACCESS_GET); 274 return Heap::undefined_value(); 275 } 276 277 278 PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck( 279 Object* receiver, 280 LookupResult* result, 281 String* name, 282 bool continue_search) { 283 if (result->IsProperty()) { 284 switch (result->type()) { 285 case CALLBACKS: { 286 // Only allow API accessors. 287 Object* obj = result->GetCallbackObject(); 288 if (obj->IsAccessorInfo()) { 289 AccessorInfo* info = AccessorInfo::cast(obj); 290 if (info->all_can_read()) { 291 return result->GetAttributes(); 292 } 293 } 294 break; 295 } 296 297 case NORMAL: 298 case FIELD: 299 case CONSTANT_FUNCTION: { 300 if (!continue_search) break; 301 // Search ALL_CAN_READ accessors in prototype chain. 302 LookupResult r; 303 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r); 304 if (r.IsProperty()) { 305 return GetPropertyAttributeWithFailedAccessCheck(receiver, 306 &r, 307 name, 308 continue_search); 309 } 310 break; 311 } 312 313 case INTERCEPTOR: { 314 // If the object has an interceptor, try real named properties. 315 // No access check in GetPropertyAttributeWithInterceptor. 316 LookupResult r; 317 if (continue_search) { 318 result->holder()->LookupRealNamedProperty(name, &r); 319 } else { 320 result->holder()->LocalLookupRealNamedProperty(name, &r); 321 } 322 if (r.IsProperty()) { 323 return GetPropertyAttributeWithFailedAccessCheck(receiver, 324 &r, 325 name, 326 continue_search); 327 } 328 break; 329 } 330 331 default: 332 UNREACHABLE(); 333 } 334 } 335 336 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); 337 return ABSENT; 338 } 339 340 341 Object* JSObject::GetNormalizedProperty(LookupResult* result) { 342 ASSERT(!HasFastProperties()); 343 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); 344 if (IsGlobalObject()) { 345 value = JSGlobalPropertyCell::cast(value)->value(); 346 } 347 ASSERT(!value->IsJSGlobalPropertyCell()); 348 return value; 349 } 350 351 352 Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) { 353 ASSERT(!HasFastProperties()); 354 if (IsGlobalObject()) { 355 JSGlobalPropertyCell* cell = 356 JSGlobalPropertyCell::cast( 357 property_dictionary()->ValueAt(result->GetDictionaryEntry())); 358 cell->set_value(value); 359 } else { 360 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value); 361 } 362 return value; 363 } 364 365 366 Object* JSObject::SetNormalizedProperty(String* name, 367 Object* value, 368 PropertyDetails details) { 369 ASSERT(!HasFastProperties()); 370 int entry = property_dictionary()->FindEntry(name); 371 if (entry == StringDictionary::kNotFound) { 372 Object* store_value = value; 373 if (IsGlobalObject()) { 374 store_value = Heap::AllocateJSGlobalPropertyCell(value); 375 if (store_value->IsFailure()) return store_value; 376 } 377 Object* dict = property_dictionary()->Add(name, store_value, details); 378 if (dict->IsFailure()) return dict; 379 set_properties(StringDictionary::cast(dict)); 380 return value; 381 } 382 // Preserve enumeration index. 383 details = PropertyDetails(details.attributes(), 384 details.type(), 385 property_dictionary()->DetailsAt(entry).index()); 386 if (IsGlobalObject()) { 387 JSGlobalPropertyCell* cell = 388 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry)); 389 cell->set_value(value); 390 // Please note we have to update the property details. 391 property_dictionary()->DetailsAtPut(entry, details); 392 } else { 393 property_dictionary()->SetEntry(entry, name, value, details); 394 } 395 return value; 396 } 397 398 399 Object* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) { 400 ASSERT(!HasFastProperties()); 401 StringDictionary* dictionary = property_dictionary(); 402 int entry = dictionary->FindEntry(name); 403 if (entry != StringDictionary::kNotFound) { 404 // If we have a global object set the cell to the hole. 405 if (IsGlobalObject()) { 406 PropertyDetails details = dictionary->DetailsAt(entry); 407 if (details.IsDontDelete()) { 408 if (mode != FORCE_DELETION) return Heap::false_value(); 409 // When forced to delete global properties, we have to make a 410 // map change to invalidate any ICs that think they can load 411 // from the DontDelete cell without checking if it contains 412 // the hole value. 413 Object* new_map = map()->CopyDropDescriptors(); 414 if (new_map->IsFailure()) return new_map; 415 set_map(Map::cast(new_map)); 416 } 417 JSGlobalPropertyCell* cell = 418 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); 419 cell->set_value(Heap::the_hole_value()); 420 dictionary->DetailsAtPut(entry, details.AsDeleted()); 421 } else { 422 return dictionary->DeleteProperty(entry, mode); 423 } 424 } 425 return Heap::true_value(); 426 } 427 428 429 bool JSObject::IsDirty() { 430 Object* cons_obj = map()->constructor(); 431 if (!cons_obj->IsJSFunction()) 432 return true; 433 JSFunction* fun = JSFunction::cast(cons_obj); 434 if (!fun->shared()->function_data()->IsFunctionTemplateInfo()) 435 return true; 436 // If the object is fully fast case and has the same map it was 437 // created with then no changes can have been made to it. 438 return map() != fun->initial_map() 439 || !HasFastElements() 440 || !HasFastProperties(); 441 } 442 443 444 Object* Object::GetProperty(Object* receiver, 445 LookupResult* result, 446 String* name, 447 PropertyAttributes* attributes) { 448 // Make sure that the top context does not change when doing 449 // callbacks or interceptor calls. 450 AssertNoContextChange ncc; 451 452 // Traverse the prototype chain from the current object (this) to 453 // the holder and check for access rights. This avoid traversing the 454 // objects more than once in case of interceptors, because the 455 // holder will always be the interceptor holder and the search may 456 // only continue with a current object just after the interceptor 457 // holder in the prototype chain. 458 Object* last = result->IsProperty() ? result->holder() : Heap::null_value(); 459 for (Object* current = this; true; current = current->GetPrototype()) { 460 if (current->IsAccessCheckNeeded()) { 461 // Check if we're allowed to read from the current object. Note 462 // that even though we may not actually end up loading the named 463 // property from the current object, we still check that we have 464 // access to it. 465 JSObject* checked = JSObject::cast(current); 466 if (!Top::MayNamedAccess(checked, name, v8::ACCESS_GET)) { 467 return checked->GetPropertyWithFailedAccessCheck(receiver, 468 result, 469 name, 470 attributes); 471 } 472 } 473 // Stop traversing the chain once we reach the last object in the 474 // chain; either the holder of the result or null in case of an 475 // absent property. 476 if (current == last) break; 477 } 478 479 if (!result->IsProperty()) { 480 *attributes = ABSENT; 481 return Heap::undefined_value(); 482 } 483 *attributes = result->GetAttributes(); 484 Object* value; 485 JSObject* holder = result->holder(); 486 switch (result->type()) { 487 case NORMAL: 488 value = holder->GetNormalizedProperty(result); 489 ASSERT(!value->IsTheHole() || result->IsReadOnly()); 490 return value->IsTheHole() ? Heap::undefined_value() : value; 491 case FIELD: 492 value = holder->FastPropertyAt(result->GetFieldIndex()); 493 ASSERT(!value->IsTheHole() || result->IsReadOnly()); 494 return value->IsTheHole() ? Heap::undefined_value() : value; 495 case CONSTANT_FUNCTION: 496 return result->GetConstantFunction(); 497 case CALLBACKS: 498 return GetPropertyWithCallback(receiver, 499 result->GetCallbackObject(), 500 name, 501 holder); 502 case INTERCEPTOR: { 503 JSObject* recvr = JSObject::cast(receiver); 504 return holder->GetPropertyWithInterceptor(recvr, name, attributes); 505 } 506 default: 507 UNREACHABLE(); 508 return NULL; 509 } 510 } 511 512 513 Object* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { 514 // Non-JS objects do not have integer indexed properties. 515 if (!IsJSObject()) return Heap::undefined_value(); 516 return JSObject::cast(this)->GetElementWithReceiver(JSObject::cast(receiver), 517 index); 518 } 519 520 521 Object* Object::GetPrototype() { 522 // The object is either a number, a string, a boolean, or a real JS object. 523 if (IsJSObject()) return JSObject::cast(this)->map()->prototype(); 524 Context* context = Top::context()->global_context(); 525 526 if (IsNumber()) return context->number_function()->instance_prototype(); 527 if (IsString()) return context->string_function()->instance_prototype(); 528 if (IsBoolean()) { 529 return context->boolean_function()->instance_prototype(); 530 } else { 531 return Heap::null_value(); 532 } 533 } 534 535 536 void Object::ShortPrint() { 537 HeapStringAllocator allocator; 538 StringStream accumulator(&allocator); 539 ShortPrint(&accumulator); 540 accumulator.OutputToStdOut(); 541 } 542 543 544 void Object::ShortPrint(StringStream* accumulator) { 545 if (IsSmi()) { 546 Smi::cast(this)->SmiPrint(accumulator); 547 } else if (IsFailure()) { 548 Failure::cast(this)->FailurePrint(accumulator); 549 } else { 550 HeapObject::cast(this)->HeapObjectShortPrint(accumulator); 551 } 552 } 553 554 555 void Smi::SmiPrint() { 556 PrintF("%d", value()); 557 } 558 559 560 void Smi::SmiPrint(StringStream* accumulator) { 561 accumulator->Add("%d", value()); 562 } 563 564 565 void Failure::FailurePrint(StringStream* accumulator) { 566 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value())); 567 } 568 569 570 void Failure::FailurePrint() { 571 PrintF("Failure(%p)", reinterpret_cast<void*>(value())); 572 } 573 574 575 Failure* Failure::RetryAfterGC(int requested_bytes, AllocationSpace space) { 576 ASSERT((space & ~kSpaceTagMask) == 0); 577 // TODO(X64): Stop using Smi validation for non-smi checks, even if they 578 // happen to be identical at the moment. 579 580 int requested = requested_bytes >> kObjectAlignmentBits; 581 int value = (requested << kSpaceTagSize) | space; 582 // We can't very well allocate a heap number in this situation, and if the 583 // requested memory is so large it seems reasonable to say that this is an 584 // out of memory situation. This fixes a crash in 585 // js1_5/Regress/regress-303213.js. 586 if (value >> kSpaceTagSize != requested || 587 !Smi::IsValid(value) || 588 value != ((value << kFailureTypeTagSize) >> kFailureTypeTagSize) || 589 !Smi::IsValid(value << kFailureTypeTagSize)) { 590 Top::context()->mark_out_of_memory(); 591 return Failure::OutOfMemoryException(); 592 } 593 return Construct(RETRY_AFTER_GC, value); 594 } 595 596 597 // Should a word be prefixed by 'a' or 'an' in order to read naturally in 598 // English? Returns false for non-ASCII or words that don't start with 599 // a capital letter. The a/an rule follows pronunciation in English. 600 // We don't use the BBC's overcorrect "an historic occasion" though if 601 // you speak a dialect you may well say "an 'istoric occasion". 602 static bool AnWord(String* str) { 603 if (str->length() == 0) return false; // A nothing. 604 int c0 = str->Get(0); 605 int c1 = str->length() > 1 ? str->Get(1) : 0; 606 if (c0 == 'U') { 607 if (c1 > 'Z') { 608 return true; // An Umpire, but a UTF8String, a U. 609 } 610 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { 611 return true; // An Ape, an ABCBook. 612 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && 613 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || 614 c0 == 'S' || c0 == 'X')) { 615 return true; // An MP3File, an M. 616 } 617 return false; 618 } 619 620 621 Object* String::TryFlatten() { 622 #ifdef DEBUG 623 // Do not attempt to flatten in debug mode when allocation is not 624 // allowed. This is to avoid an assertion failure when allocating. 625 // Flattening strings is the only case where we always allow 626 // allocation because no GC is performed if the allocation fails. 627 if (!Heap::IsAllocationAllowed()) return this; 628 #endif 629 630 switch (StringShape(this).representation_tag()) { 631 case kConsStringTag: { 632 ConsString* cs = ConsString::cast(this); 633 if (cs->second()->length() == 0) { 634 return this; 635 } 636 // There's little point in putting the flat string in new space if the 637 // cons string is in old space. It can never get GCed until there is 638 // an old space GC. 639 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED; 640 int len = length(); 641 Object* object; 642 String* result; 643 if (IsAsciiRepresentation()) { 644 object = Heap::AllocateRawAsciiString(len, tenure); 645 if (object->IsFailure()) return object; 646 result = String::cast(object); 647 String* first = cs->first(); 648 int first_length = first->length(); 649 char* dest = SeqAsciiString::cast(result)->GetChars(); 650 WriteToFlat(first, dest, 0, first_length); 651 String* second = cs->second(); 652 WriteToFlat(second, 653 dest + first_length, 654 0, 655 len - first_length); 656 } else { 657 object = Heap::AllocateRawTwoByteString(len, tenure); 658 if (object->IsFailure()) return object; 659 result = String::cast(object); 660 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); 661 String* first = cs->first(); 662 int first_length = first->length(); 663 WriteToFlat(first, dest, 0, first_length); 664 String* second = cs->second(); 665 WriteToFlat(second, 666 dest + first_length, 667 0, 668 len - first_length); 669 } 670 cs->set_first(result); 671 cs->set_second(Heap::empty_string()); 672 return this; 673 } 674 default: 675 return this; 676 } 677 } 678 679 680 bool String::MakeExternal(v8::String::ExternalStringResource* resource) { 681 #ifdef DEBUG 682 if (FLAG_enable_slow_asserts) { 683 // Assert that the resource and the string are equivalent. 684 ASSERT(static_cast<size_t>(this->length()) == resource->length()); 685 SmartPointer<uc16> smart_chars(NewArray<uc16>(this->length())); 686 String::WriteToFlat(this, *smart_chars, 0, this->length()); 687 ASSERT(memcmp(*smart_chars, 688 resource->data(), 689 resource->length() * sizeof(**smart_chars)) == 0); 690 } 691 #endif // DEBUG 692 693 int size = this->Size(); // Byte size of the original string. 694 if (size < ExternalString::kSize) { 695 // The string is too small to fit an external String in its place. This can 696 // only happen for zero length strings. 697 return false; 698 } 699 ASSERT(size >= ExternalString::kSize); 700 bool is_symbol = this->IsSymbol(); 701 int length = this->length(); 702 int hash_field = this->hash_field(); 703 704 // Morph the object to an external string by adjusting the map and 705 // reinitializing the fields. 706 this->set_map(Heap::external_string_map()); 707 ExternalTwoByteString* self = ExternalTwoByteString::cast(this); 708 self->set_length(length); 709 self->set_hash_field(hash_field); 710 self->set_resource(resource); 711 // Additionally make the object into an external symbol if the original string 712 // was a symbol to start with. 713 if (is_symbol) { 714 self->Hash(); // Force regeneration of the hash value. 715 // Now morph this external string into a external symbol. 716 this->set_map(Heap::external_symbol_map()); 717 } 718 719 // Fill the remainder of the string with dead wood. 720 int new_size = this->Size(); // Byte size of the external String object. 721 Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size); 722 return true; 723 } 724 725 726 bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) { 727 #ifdef DEBUG 728 if (FLAG_enable_slow_asserts) { 729 // Assert that the resource and the string are equivalent. 730 ASSERT(static_cast<size_t>(this->length()) == resource->length()); 731 SmartPointer<char> smart_chars(NewArray<char>(this->length())); 732 String::WriteToFlat(this, *smart_chars, 0, this->length()); 733 ASSERT(memcmp(*smart_chars, 734 resource->data(), 735 resource->length()*sizeof(**smart_chars)) == 0); 736 } 737 #endif // DEBUG 738 739 int size = this->Size(); // Byte size of the original string. 740 if (size < ExternalString::kSize) { 741 // The string is too small to fit an external String in its place. This can 742 // only happen for zero length strings. 743 return false; 744 } 745 ASSERT(size >= ExternalString::kSize); 746 bool is_symbol = this->IsSymbol(); 747 int length = this->length(); 748 int hash_field = this->hash_field(); 749 750 // Morph the object to an external string by adjusting the map and 751 // reinitializing the fields. 752 this->set_map(Heap::external_ascii_string_map()); 753 ExternalAsciiString* self = ExternalAsciiString::cast(this); 754 self->set_length(length); 755 self->set_hash_field(hash_field); 756 self->set_resource(resource); 757 // Additionally make the object into an external symbol if the original string 758 // was a symbol to start with. 759 if (is_symbol) { 760 self->Hash(); // Force regeneration of the hash value. 761 // Now morph this external string into a external symbol. 762 this->set_map(Heap::external_ascii_symbol_map()); 763 } 764 765 // Fill the remainder of the string with dead wood. 766 int new_size = this->Size(); // Byte size of the external String object. 767 Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size); 768 return true; 769 } 770 771 772 void String::StringShortPrint(StringStream* accumulator) { 773 int len = length(); 774 if (len > kMaxShortPrintLength) { 775 accumulator->Add("<Very long string[%u]>", len); 776 return; 777 } 778 779 if (!LooksValid()) { 780 accumulator->Add("<Invalid String>"); 781 return; 782 } 783 784 StringInputBuffer buf(this); 785 786 bool truncated = false; 787 if (len > kMaxShortPrintLength) { 788 len = kMaxShortPrintLength; 789 truncated = true; 790 } 791 bool ascii = true; 792 for (int i = 0; i < len; i++) { 793 int c = buf.GetNext(); 794 795 if (c < 32 || c >= 127) { 796 ascii = false; 797 } 798 } 799 buf.Reset(this); 800 if (ascii) { 801 accumulator->Add("<String[%u]: ", length()); 802 for (int i = 0; i < len; i++) { 803 accumulator->Put(buf.GetNext()); 804 } 805 accumulator->Put('>'); 806 } else { 807 // Backslash indicates that the string contains control 808 // characters and that backslashes are therefore escaped. 809 accumulator->Add("<String[%u]\\: ", length()); 810 for (int i = 0; i < len; i++) { 811 int c = buf.GetNext(); 812 if (c == '\n') { 813 accumulator->Add("\\n"); 814 } else if (c == '\r') { 815 accumulator->Add("\\r"); 816 } else if (c == '\\') { 817 accumulator->Add("\\\\"); 818 } else if (c < 32 || c > 126) { 819 accumulator->Add("\\x%02x", c); 820 } else { 821 accumulator->Put(c); 822 } 823 } 824 if (truncated) { 825 accumulator->Put('.'); 826 accumulator->Put('.'); 827 accumulator->Put('.'); 828 } 829 accumulator->Put('>'); 830 } 831 return; 832 } 833 834 835 void JSObject::JSObjectShortPrint(StringStream* accumulator) { 836 switch (map()->instance_type()) { 837 case JS_ARRAY_TYPE: { 838 double length = JSArray::cast(this)->length()->Number(); 839 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length)); 840 break; 841 } 842 case JS_REGEXP_TYPE: { 843 accumulator->Add("<JS RegExp>"); 844 break; 845 } 846 case JS_FUNCTION_TYPE: { 847 Object* fun_name = JSFunction::cast(this)->shared()->name(); 848 bool printed = false; 849 if (fun_name->IsString()) { 850 String* str = String::cast(fun_name); 851 if (str->length() > 0) { 852 accumulator->Add("<JS Function "); 853 accumulator->Put(str); 854 accumulator->Put('>'); 855 printed = true; 856 } 857 } 858 if (!printed) { 859 accumulator->Add("<JS Function>"); 860 } 861 break; 862 } 863 // All other JSObjects are rather similar to each other (JSObject, 864 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue). 865 default: { 866 Object* constructor = map()->constructor(); 867 bool printed = false; 868 if (constructor->IsHeapObject() && 869 !Heap::Contains(HeapObject::cast(constructor))) { 870 accumulator->Add("!!!INVALID CONSTRUCTOR!!!"); 871 } else { 872 bool global_object = IsJSGlobalProxy(); 873 if (constructor->IsJSFunction()) { 874 if (!Heap::Contains(JSFunction::cast(constructor)->shared())) { 875 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!"); 876 } else { 877 Object* constructor_name = 878 JSFunction::cast(constructor)->shared()->name(); 879 if (constructor_name->IsString()) { 880 String* str = String::cast(constructor_name); 881 if (str->length() > 0) { 882 bool vowel = AnWord(str); 883 accumulator->Add("<%sa%s ", 884 global_object ? "Global Object: " : "", 885 vowel ? "n" : ""); 886 accumulator->Put(str); 887 accumulator->Put('>'); 888 printed = true; 889 } 890 } 891 } 892 } 893 if (!printed) { 894 accumulator->Add("<JS %sObject", global_object ? "Global " : ""); 895 } 896 } 897 if (IsJSValue()) { 898 accumulator->Add(" value = "); 899 JSValue::cast(this)->value()->ShortPrint(accumulator); 900 } 901 accumulator->Put('>'); 902 break; 903 } 904 } 905 } 906 907 908 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { 909 // if (!Heap::InNewSpace(this)) PrintF("*", this); 910 if (!Heap::Contains(this)) { 911 accumulator->Add("!!!INVALID POINTER!!!"); 912 return; 913 } 914 if (!Heap::Contains(map())) { 915 accumulator->Add("!!!INVALID MAP!!!"); 916 return; 917 } 918 919 accumulator->Add("%p ", this); 920 921 if (IsString()) { 922 String::cast(this)->StringShortPrint(accumulator); 923 return; 924 } 925 if (IsJSObject()) { 926 JSObject::cast(this)->JSObjectShortPrint(accumulator); 927 return; 928 } 929 switch (map()->instance_type()) { 930 case MAP_TYPE: 931 accumulator->Add("<Map>"); 932 break; 933 case FIXED_ARRAY_TYPE: 934 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length()); 935 break; 936 case BYTE_ARRAY_TYPE: 937 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length()); 938 break; 939 case PIXEL_ARRAY_TYPE: 940 accumulator->Add("<PixelArray[%u]>", PixelArray::cast(this)->length()); 941 break; 942 case EXTERNAL_BYTE_ARRAY_TYPE: 943 accumulator->Add("<ExternalByteArray[%u]>", 944 ExternalByteArray::cast(this)->length()); 945 break; 946 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: 947 accumulator->Add("<ExternalUnsignedByteArray[%u]>", 948 ExternalUnsignedByteArray::cast(this)->length()); 949 break; 950 case EXTERNAL_SHORT_ARRAY_TYPE: 951 accumulator->Add("<ExternalShortArray[%u]>", 952 ExternalShortArray::cast(this)->length()); 953 break; 954 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: 955 accumulator->Add("<ExternalUnsignedShortArray[%u]>", 956 ExternalUnsignedShortArray::cast(this)->length()); 957 break; 958 case EXTERNAL_INT_ARRAY_TYPE: 959 accumulator->Add("<ExternalIntArray[%u]>", 960 ExternalIntArray::cast(this)->length()); 961 break; 962 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: 963 accumulator->Add("<ExternalUnsignedIntArray[%u]>", 964 ExternalUnsignedIntArray::cast(this)->length()); 965 break; 966 case EXTERNAL_FLOAT_ARRAY_TYPE: 967 accumulator->Add("<ExternalFloatArray[%u]>", 968 ExternalFloatArray::cast(this)->length()); 969 break; 970 case SHARED_FUNCTION_INFO_TYPE: 971 accumulator->Add("<SharedFunctionInfo>"); 972 break; 973 #define MAKE_STRUCT_CASE(NAME, Name, name) \ 974 case NAME##_TYPE: \ 975 accumulator->Put('<'); \ 976 accumulator->Add(#Name); \ 977 accumulator->Put('>'); \ 978 break; 979 STRUCT_LIST(MAKE_STRUCT_CASE) 980 #undef MAKE_STRUCT_CASE 981 case CODE_TYPE: 982 accumulator->Add("<Code>"); 983 break; 984 case ODDBALL_TYPE: { 985 if (IsUndefined()) 986 accumulator->Add("<undefined>"); 987 else if (IsTheHole()) 988 accumulator->Add("<the hole>"); 989 else if (IsNull()) 990 accumulator->Add("<null>"); 991 else if (IsTrue()) 992 accumulator->Add("<true>"); 993 else if (IsFalse()) 994 accumulator->Add("<false>"); 995 else 996 accumulator->Add("<Odd Oddball>"); 997 break; 998 } 999 case HEAP_NUMBER_TYPE: 1000 accumulator->Add("<Number: "); 1001 HeapNumber::cast(this)->HeapNumberPrint(accumulator); 1002 accumulator->Put('>'); 1003 break; 1004 case PROXY_TYPE: 1005 accumulator->Add("<Proxy>"); 1006 break; 1007 case JS_GLOBAL_PROPERTY_CELL_TYPE: 1008 accumulator->Add("Cell for "); 1009 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator); 1010 break; 1011 default: 1012 accumulator->Add("<Other heap object (%d)>", map()->instance_type()); 1013 break; 1014 } 1015 } 1016 1017 1018 int HeapObject::SlowSizeFromMap(Map* map) { 1019 // Avoid calling functions such as FixedArray::cast during GC, which 1020 // read map pointer of this object again. 1021 InstanceType instance_type = map->instance_type(); 1022 uint32_t type = static_cast<uint32_t>(instance_type); 1023 1024 if (instance_type < FIRST_NONSTRING_TYPE 1025 && (StringShape(instance_type).IsSequential())) { 1026 if ((type & kStringEncodingMask) == kAsciiStringTag) { 1027 SeqAsciiString* seq_ascii_this = reinterpret_cast<SeqAsciiString*>(this); 1028 return seq_ascii_this->SeqAsciiStringSize(instance_type); 1029 } else { 1030 SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this); 1031 return self->SeqTwoByteStringSize(instance_type); 1032 } 1033 } 1034 1035 switch (instance_type) { 1036 case FIXED_ARRAY_TYPE: 1037 return reinterpret_cast<FixedArray*>(this)->FixedArraySize(); 1038 case BYTE_ARRAY_TYPE: 1039 return reinterpret_cast<ByteArray*>(this)->ByteArraySize(); 1040 case CODE_TYPE: 1041 return reinterpret_cast<Code*>(this)->CodeSize(); 1042 case MAP_TYPE: 1043 return Map::kSize; 1044 default: 1045 return map->instance_size(); 1046 } 1047 } 1048 1049 1050 void HeapObject::Iterate(ObjectVisitor* v) { 1051 // Handle header 1052 IteratePointer(v, kMapOffset); 1053 // Handle object body 1054 Map* m = map(); 1055 IterateBody(m->instance_type(), SizeFromMap(m), v); 1056 } 1057 1058 1059 void HeapObject::IterateBody(InstanceType type, int object_size, 1060 ObjectVisitor* v) { 1061 // Avoiding <Type>::cast(this) because it accesses the map pointer field. 1062 // During GC, the map pointer field is encoded. 1063 if (type < FIRST_NONSTRING_TYPE) { 1064 switch (type & kStringRepresentationMask) { 1065 case kSeqStringTag: 1066 break; 1067 case kConsStringTag: 1068 reinterpret_cast<ConsString*>(this)->ConsStringIterateBody(v); 1069 break; 1070 case kExternalStringTag: 1071 if ((type & kStringEncodingMask) == kAsciiStringTag) { 1072 reinterpret_cast<ExternalAsciiString*>(this)-> 1073 ExternalAsciiStringIterateBody(v); 1074 } else { 1075 reinterpret_cast<ExternalTwoByteString*>(this)-> 1076 ExternalTwoByteStringIterateBody(v); 1077 } 1078 break; 1079 } 1080 return; 1081 } 1082 1083 switch (type) { 1084 case FIXED_ARRAY_TYPE: 1085 reinterpret_cast<FixedArray*>(this)->FixedArrayIterateBody(v); 1086 break; 1087 case JS_OBJECT_TYPE: 1088 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 1089 case JS_VALUE_TYPE: 1090 case JS_ARRAY_TYPE: 1091 case JS_REGEXP_TYPE: 1092 case JS_FUNCTION_TYPE: 1093 case JS_GLOBAL_PROXY_TYPE: 1094 case JS_GLOBAL_OBJECT_TYPE: 1095 case JS_BUILTINS_OBJECT_TYPE: 1096 reinterpret_cast<JSObject*>(this)->JSObjectIterateBody(object_size, v); 1097 break; 1098 case ODDBALL_TYPE: 1099 reinterpret_cast<Oddball*>(this)->OddballIterateBody(v); 1100 break; 1101 case PROXY_TYPE: 1102 reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v); 1103 break; 1104 case MAP_TYPE: 1105 reinterpret_cast<Map*>(this)->MapIterateBody(v); 1106 break; 1107 case CODE_TYPE: 1108 reinterpret_cast<Code*>(this)->CodeIterateBody(v); 1109 break; 1110 case JS_GLOBAL_PROPERTY_CELL_TYPE: 1111 reinterpret_cast<JSGlobalPropertyCell*>(this) 1112 ->JSGlobalPropertyCellIterateBody(v); 1113 break; 1114 case HEAP_NUMBER_TYPE: 1115 case FILLER_TYPE: 1116 case BYTE_ARRAY_TYPE: 1117 case PIXEL_ARRAY_TYPE: 1118 case EXTERNAL_BYTE_ARRAY_TYPE: 1119 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: 1120 case EXTERNAL_SHORT_ARRAY_TYPE: 1121 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: 1122 case EXTERNAL_INT_ARRAY_TYPE: 1123 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: 1124 case EXTERNAL_FLOAT_ARRAY_TYPE: 1125 break; 1126 case SHARED_FUNCTION_INFO_TYPE: { 1127 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this); 1128 shared->SharedFunctionInfoIterateBody(v); 1129 break; 1130 } 1131 #define MAKE_STRUCT_CASE(NAME, Name, name) \ 1132 case NAME##_TYPE: 1133 STRUCT_LIST(MAKE_STRUCT_CASE) 1134 #undef MAKE_STRUCT_CASE 1135 IterateStructBody(object_size, v); 1136 break; 1137 default: 1138 PrintF("Unknown type: %d\n", type); 1139 UNREACHABLE(); 1140 } 1141 } 1142 1143 1144 void HeapObject::IterateStructBody(int object_size, ObjectVisitor* v) { 1145 IteratePointers(v, HeapObject::kHeaderSize, object_size); 1146 } 1147 1148 1149 Object* HeapNumber::HeapNumberToBoolean() { 1150 // NaN, +0, and -0 should return the false object 1151 switch (fpclassify(value())) { 1152 case FP_NAN: // fall through 1153 case FP_ZERO: return Heap::false_value(); 1154 default: return Heap::true_value(); 1155 } 1156 } 1157 1158 1159 void HeapNumber::HeapNumberPrint() { 1160 PrintF("%.16g", Number()); 1161 } 1162 1163 1164 void HeapNumber::HeapNumberPrint(StringStream* accumulator) { 1165 // The Windows version of vsnprintf can allocate when printing a %g string 1166 // into a buffer that may not be big enough. We don't want random memory 1167 // allocation when producing post-crash stack traces, so we print into a 1168 // buffer that is plenty big enough for any floating point number, then 1169 // print that using vsnprintf (which may truncate but never allocate if 1170 // there is no more space in the buffer). 1171 EmbeddedVector<char, 100> buffer; 1172 OS::SNPrintF(buffer, "%.16g", Number()); 1173 accumulator->Add("%s", buffer.start()); 1174 } 1175 1176 1177 String* JSObject::class_name() { 1178 if (IsJSFunction()) { 1179 return Heap::function_class_symbol(); 1180 } 1181 if (map()->constructor()->IsJSFunction()) { 1182 JSFunction* constructor = JSFunction::cast(map()->constructor()); 1183 return String::cast(constructor->shared()->instance_class_name()); 1184 } 1185 // If the constructor is not present, return "Object". 1186 return Heap::Object_symbol(); 1187 } 1188 1189 1190 String* JSObject::constructor_name() { 1191 if (IsJSFunction()) { 1192 return JSFunction::cast(this)->IsBoilerplate() ? 1193 Heap::function_class_symbol() : Heap::closure_symbol(); 1194 } 1195 if (map()->constructor()->IsJSFunction()) { 1196 JSFunction* constructor = JSFunction::cast(map()->constructor()); 1197 String* name = String::cast(constructor->shared()->name()); 1198 return name->length() > 0 ? name : constructor->shared()->inferred_name(); 1199 } 1200 // If the constructor is not present, return "Object". 1201 return Heap::Object_symbol(); 1202 } 1203 1204 1205 void JSObject::JSObjectIterateBody(int object_size, ObjectVisitor* v) { 1206 // Iterate over all fields in the body. Assumes all are Object*. 1207 IteratePointers(v, kPropertiesOffset, object_size); 1208 } 1209 1210 1211 Object* JSObject::AddFastPropertyUsingMap(Map* new_map, 1212 String* name, 1213 Object* value) { 1214 int index = new_map->PropertyIndexFor(name); 1215 if (map()->unused_property_fields() == 0) { 1216 ASSERT(map()->unused_property_fields() == 0); 1217 int new_unused = new_map->unused_property_fields(); 1218 Object* values = 1219 properties()->CopySize(properties()->length() + new_unused + 1); 1220 if (values->IsFailure()) return values; 1221 set_properties(FixedArray::cast(values)); 1222 } 1223 set_map(new_map); 1224 return FastPropertyAtPut(index, value); 1225 } 1226 1227 1228 Object* JSObject::AddFastProperty(String* name, 1229 Object* value, 1230 PropertyAttributes attributes) { 1231 // Normalize the object if the name is an actual string (not the 1232 // hidden symbols) and is not a real identifier. 1233 StringInputBuffer buffer(name); 1234 if (!Scanner::IsIdentifier(&buffer) && name != Heap::hidden_symbol()) { 1235 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1236 if (obj->IsFailure()) return obj; 1237 return AddSlowProperty(name, value, attributes); 1238 } 1239 1240 DescriptorArray* old_descriptors = map()->instance_descriptors(); 1241 // Compute the new index for new field. 1242 int index = map()->NextFreePropertyIndex(); 1243 1244 // Allocate new instance descriptors with (name, index) added 1245 FieldDescriptor new_field(name, index, attributes); 1246 Object* new_descriptors = 1247 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS); 1248 if (new_descriptors->IsFailure()) return new_descriptors; 1249 1250 // Only allow map transition if the object's map is NOT equal to the 1251 // global object_function's map and there is not a transition for name. 1252 bool allow_map_transition = 1253 !old_descriptors->Contains(name) && 1254 (Top::context()->global_context()->object_function()->map() != map()); 1255 1256 ASSERT(index < map()->inobject_properties() || 1257 (index - map()->inobject_properties()) < properties()->length() || 1258 map()->unused_property_fields() == 0); 1259 // Allocate a new map for the object. 1260 Object* r = map()->CopyDropDescriptors(); 1261 if (r->IsFailure()) return r; 1262 Map* new_map = Map::cast(r); 1263 if (allow_map_transition) { 1264 // Allocate new instance descriptors for the old map with map transition. 1265 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); 1266 Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); 1267 if (r->IsFailure()) return r; 1268 old_descriptors = DescriptorArray::cast(r); 1269 } 1270 1271 if (map()->unused_property_fields() == 0) { 1272 if (properties()->length() > kMaxFastProperties) { 1273 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1274 if (obj->IsFailure()) return obj; 1275 return AddSlowProperty(name, value, attributes); 1276 } 1277 // Make room for the new value 1278 Object* values = 1279 properties()->CopySize(properties()->length() + kFieldsAdded); 1280 if (values->IsFailure()) return values; 1281 set_properties(FixedArray::cast(values)); 1282 new_map->set_unused_property_fields(kFieldsAdded - 1); 1283 } else { 1284 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); 1285 } 1286 // We have now allocated all the necessary objects. 1287 // All the changes can be applied at once, so they are atomic. 1288 map()->set_instance_descriptors(old_descriptors); 1289 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); 1290 set_map(new_map); 1291 return FastPropertyAtPut(index, value); 1292 } 1293 1294 1295 Object* JSObject::AddConstantFunctionProperty(String* name, 1296 JSFunction* function, 1297 PropertyAttributes attributes) { 1298 ASSERT(!Heap::InNewSpace(function)); 1299 1300 // Allocate new instance descriptors with (name, function) added 1301 ConstantFunctionDescriptor d(name, function, attributes); 1302 Object* new_descriptors = 1303 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS); 1304 if (new_descriptors->IsFailure()) return new_descriptors; 1305 1306 // Allocate a new map for the object. 1307 Object* new_map = map()->CopyDropDescriptors(); 1308 if (new_map->IsFailure()) return new_map; 1309 1310 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors); 1311 Map::cast(new_map)->set_instance_descriptors(descriptors); 1312 Map* old_map = map(); 1313 set_map(Map::cast(new_map)); 1314 1315 // If the old map is the global object map (from new Object()), 1316 // then transitions are not added to it, so we are done. 1317 if (old_map == Top::context()->global_context()->object_function()->map()) { 1318 return function; 1319 } 1320 1321 // Do not add CONSTANT_TRANSITIONS to global objects 1322 if (IsGlobalObject()) { 1323 return function; 1324 } 1325 1326 // Add a CONSTANT_TRANSITION descriptor to the old map, 1327 // so future assignments to this property on other objects 1328 // of the same type will create a normal field, not a constant function. 1329 // Don't do this for special properties, with non-trival attributes. 1330 if (attributes != NONE) { 1331 return function; 1332 } 1333 ConstTransitionDescriptor mark(name); 1334 new_descriptors = 1335 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS); 1336 if (new_descriptors->IsFailure()) { 1337 return function; // We have accomplished the main goal, so return success. 1338 } 1339 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); 1340 1341 return function; 1342 } 1343 1344 1345 // Add property in slow mode 1346 Object* JSObject::AddSlowProperty(String* name, 1347 Object* value, 1348 PropertyAttributes attributes) { 1349 ASSERT(!HasFastProperties()); 1350 StringDictionary* dict = property_dictionary(); 1351 Object* store_value = value; 1352 if (IsGlobalObject()) { 1353 // In case name is an orphaned property reuse the cell. 1354 int entry = dict->FindEntry(name); 1355 if (entry != StringDictionary::kNotFound) { 1356 store_value = dict->ValueAt(entry); 1357 JSGlobalPropertyCell::cast(store_value)->set_value(value); 1358 // Assign an enumeration index to the property and update 1359 // SetNextEnumerationIndex. 1360 int index = dict->NextEnumerationIndex(); 1361 PropertyDetails details = PropertyDetails(attributes, NORMAL, index); 1362 dict->SetNextEnumerationIndex(index + 1); 1363 dict->SetEntry(entry, name, store_value, details); 1364 return value; 1365 } 1366 store_value = Heap::AllocateJSGlobalPropertyCell(value); 1367 if (store_value->IsFailure()) return store_value; 1368 JSGlobalPropertyCell::cast(store_value)->set_value(value); 1369 } 1370 PropertyDetails details = PropertyDetails(attributes, NORMAL); 1371 Object* result = dict->Add(name, store_value, details); 1372 if (result->IsFailure()) return result; 1373 if (dict != result) set_properties(StringDictionary::cast(result)); 1374 return value; 1375 } 1376 1377 1378 Object* JSObject::AddProperty(String* name, 1379 Object* value, 1380 PropertyAttributes attributes) { 1381 ASSERT(!IsJSGlobalProxy()); 1382 if (HasFastProperties()) { 1383 // Ensure the descriptor array does not get too big. 1384 if (map()->instance_descriptors()->number_of_descriptors() < 1385 DescriptorArray::kMaxNumberOfDescriptors) { 1386 if (value->IsJSFunction() && !Heap::InNewSpace(value)) { 1387 return AddConstantFunctionProperty(name, 1388 JSFunction::cast(value), 1389 attributes); 1390 } else { 1391 return AddFastProperty(name, value, attributes); 1392 } 1393 } else { 1394 // Normalize the object to prevent very large instance descriptors. 1395 // This eliminates unwanted N^2 allocation and lookup behavior. 1396 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1397 if (obj->IsFailure()) return obj; 1398 } 1399 } 1400 return AddSlowProperty(name, value, attributes); 1401 } 1402 1403 1404 Object* JSObject::SetPropertyPostInterceptor(String* name, 1405 Object* value, 1406 PropertyAttributes attributes) { 1407 // Check local property, ignore interceptor. 1408 LookupResult result; 1409 LocalLookupRealNamedProperty(name, &result); 1410 if (result.IsFound()) { 1411 // An existing property, a map transition or a null descriptor was 1412 // found. Use set property to handle all these cases. 1413 return SetProperty(&result, name, value, attributes); 1414 } 1415 // Add a new real property. 1416 return AddProperty(name, value, attributes); 1417 } 1418 1419 1420 Object* JSObject::ReplaceSlowProperty(String* name, 1421 Object* value, 1422 PropertyAttributes attributes) { 1423 StringDictionary* dictionary = property_dictionary(); 1424 int old_index = dictionary->FindEntry(name); 1425 int new_enumeration_index = 0; // 0 means "Use the next available index." 1426 if (old_index != -1) { 1427 // All calls to ReplaceSlowProperty have had all transitions removed. 1428 ASSERT(!dictionary->DetailsAt(old_index).IsTransition()); 1429 new_enumeration_index = dictionary->DetailsAt(old_index).index(); 1430 } 1431 1432 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); 1433 return SetNormalizedProperty(name, value, new_details); 1434 } 1435 1436 1437 Object* JSObject::ConvertDescriptorToFieldAndMapTransition( 1438 String* name, 1439 Object* new_value, 1440 PropertyAttributes attributes) { 1441 Map* old_map = map(); 1442 Object* result = ConvertDescriptorToField(name, new_value, attributes); 1443 if (result->IsFailure()) return result; 1444 // If we get to this point we have succeeded - do not return failure 1445 // after this point. Later stuff is optional. 1446 if (!HasFastProperties()) { 1447 return result; 1448 } 1449 // Do not add transitions to the map of "new Object()". 1450 if (map() == Top::context()->global_context()->object_function()->map()) { 1451 return result; 1452 } 1453 1454 MapTransitionDescriptor transition(name, 1455 map(), 1456 attributes); 1457 Object* new_descriptors = 1458 old_map->instance_descriptors()-> 1459 CopyInsert(&transition, KEEP_TRANSITIONS); 1460 if (new_descriptors->IsFailure()) return result; // Yes, return _result_. 1461 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); 1462 return result; 1463 } 1464 1465 1466 Object* JSObject::ConvertDescriptorToField(String* name, 1467 Object* new_value, 1468 PropertyAttributes attributes) { 1469 if (map()->unused_property_fields() == 0 && 1470 properties()->length() > kMaxFastProperties) { 1471 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1472 if (obj->IsFailure()) return obj; 1473 return ReplaceSlowProperty(name, new_value, attributes); 1474 } 1475 1476 int index = map()->NextFreePropertyIndex(); 1477 FieldDescriptor new_field(name, index, attributes); 1478 // Make a new DescriptorArray replacing an entry with FieldDescriptor. 1479 Object* descriptors_unchecked = map()->instance_descriptors()-> 1480 CopyInsert(&new_field, REMOVE_TRANSITIONS); 1481 if (descriptors_unchecked->IsFailure()) return descriptors_unchecked; 1482 DescriptorArray* new_descriptors = 1483 DescriptorArray::cast(descriptors_unchecked); 1484 1485 // Make a new map for the object. 1486 Object* new_map_unchecked = map()->CopyDropDescriptors(); 1487 if (new_map_unchecked->IsFailure()) return new_map_unchecked; 1488 Map* new_map = Map::cast(new_map_unchecked); 1489 new_map->set_instance_descriptors(new_descriptors); 1490 1491 // Make new properties array if necessary. 1492 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer. 1493 int new_unused_property_fields = map()->unused_property_fields() - 1; 1494 if (map()->unused_property_fields() == 0) { 1495 new_unused_property_fields = kFieldsAdded - 1; 1496 Object* new_properties_unchecked = 1497 properties()->CopySize(properties()->length() + kFieldsAdded); 1498 if (new_properties_unchecked->IsFailure()) return new_properties_unchecked; 1499 new_properties = FixedArray::cast(new_properties_unchecked); 1500 } 1501 1502 // Update pointers to commit changes. 1503 // Object points to the new map. 1504 new_map->set_unused_property_fields(new_unused_property_fields); 1505 set_map(new_map); 1506 if (new_properties) { 1507 set_properties(FixedArray::cast(new_properties)); 1508 } 1509 return FastPropertyAtPut(index, new_value); 1510 } 1511 1512 1513 1514 Object* JSObject::SetPropertyWithInterceptor(String* name, 1515 Object* value, 1516 PropertyAttributes attributes) { 1517 HandleScope scope; 1518 Handle<JSObject> this_handle(this); 1519 Handle<String> name_handle(name); 1520 Handle<Object> value_handle(value); 1521 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); 1522 if (!interceptor->setter()->IsUndefined()) { 1523 LOG(ApiNamedPropertyAccess("interceptor-named-set", this, name)); 1524 CustomArguments args(interceptor->data(), this, this); 1525 v8::AccessorInfo info(args.end()); 1526 v8::NamedPropertySetter setter = 1527 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter()); 1528 v8::Handle<v8::Value> result; 1529 { 1530 // Leaving JavaScript. 1531 VMState state(EXTERNAL); 1532 Handle<Object> value_unhole(value->IsTheHole() ? 1533 Heap::undefined_value() : 1534 value); 1535 result = setter(v8::Utils::ToLocal(name_handle), 1536 v8::Utils::ToLocal(value_unhole), 1537 info); 1538 } 1539 RETURN_IF_SCHEDULED_EXCEPTION(); 1540 if (!result.IsEmpty()) return *value_handle; 1541 } 1542 Object* raw_result = this_handle->SetPropertyPostInterceptor(*name_handle, 1543 *value_handle, 1544 attributes); 1545 RETURN_IF_SCHEDULED_EXCEPTION(); 1546 return raw_result; 1547 } 1548 1549 1550 Object* JSObject::SetProperty(String* name, 1551 Object* value, 1552 PropertyAttributes attributes) { 1553 LookupResult result; 1554 LocalLookup(name, &result); 1555 return SetProperty(&result, name, value, attributes); 1556 } 1557 1558 1559 Object* JSObject::SetPropertyWithCallback(Object* structure, 1560 String* name, 1561 Object* value, 1562 JSObject* holder) { 1563 HandleScope scope; 1564 1565 // We should never get here to initialize a const with the hole 1566 // value since a const declaration would conflict with the setter. 1567 ASSERT(!value->IsTheHole()); 1568 Handle<Object> value_handle(value); 1569 1570 // To accommodate both the old and the new api we switch on the 1571 // data structure used to store the callbacks. Eventually proxy 1572 // callbacks should be phased out. 1573 if (structure->IsProxy()) { 1574 AccessorDescriptor* callback = 1575 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy()); 1576 Object* obj = (callback->setter)(this, value, callback->data); 1577 RETURN_IF_SCHEDULED_EXCEPTION(); 1578 if (obj->IsFailure()) return obj; 1579 return *value_handle; 1580 } 1581 1582 if (structure->IsAccessorInfo()) { 1583 // api style callbacks 1584 AccessorInfo* data = AccessorInfo::cast(structure); 1585 Object* call_obj = data->setter(); 1586 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj); 1587 if (call_fun == NULL) return value; 1588 Handle<String> key(name); 1589 LOG(ApiNamedPropertyAccess("store", this, name)); 1590 CustomArguments args(data->data(), this, JSObject::cast(holder)); 1591 v8::AccessorInfo info(args.end()); 1592 { 1593 // Leaving JavaScript. 1594 VMState state(EXTERNAL); 1595 call_fun(v8::Utils::ToLocal(key), 1596 v8::Utils::ToLocal(value_handle), 1597 info); 1598 } 1599 RETURN_IF_SCHEDULED_EXCEPTION(); 1600 return *value_handle; 1601 } 1602 1603 if (structure->IsFixedArray()) { 1604 Object* setter = FixedArray::cast(structure)->get(kSetterIndex); 1605 if (setter->IsJSFunction()) { 1606 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); 1607 } else { 1608 Handle<String> key(name); 1609 Handle<Object> holder_handle(holder); 1610 Handle<Object> args[2] = { key, holder_handle }; 1611 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", 1612 HandleVector(args, 2))); 1613 } 1614 } 1615 1616 UNREACHABLE(); 1617 return 0; 1618 } 1619 1620 1621 Object* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter, 1622 Object* value) { 1623 Handle<Object> value_handle(value); 1624 Handle<JSFunction> fun(JSFunction::cast(setter)); 1625 Handle<JSObject> self(this); 1626 #ifdef ENABLE_DEBUGGER_SUPPORT 1627 // Handle stepping into a setter if step into is active. 1628 if (Debug::StepInActive()) { 1629 Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false); 1630 } 1631 #endif 1632 bool has_pending_exception; 1633 Object** argv[] = { value_handle.location() }; 1634 Execution::Call(fun, self, 1, argv, &has_pending_exception); 1635 // Check for pending exception and return the result. 1636 if (has_pending_exception) return Failure::Exception(); 1637 return *value_handle; 1638 } 1639 1640 1641 void JSObject::LookupCallbackSetterInPrototypes(String* name, 1642 LookupResult* result) { 1643 for (Object* pt = GetPrototype(); 1644 pt != Heap::null_value(); 1645 pt = pt->GetPrototype()) { 1646 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); 1647 if (result->IsProperty()) { 1648 if (result->IsReadOnly()) { 1649 result->NotFound(); 1650 return; 1651 } 1652 if (result->type() == CALLBACKS) { 1653 return; 1654 } 1655 } 1656 } 1657 result->NotFound(); 1658 } 1659 1660 1661 Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) { 1662 for (Object* pt = GetPrototype(); 1663 pt != Heap::null_value(); 1664 pt = pt->GetPrototype()) { 1665 if (!JSObject::cast(pt)->HasDictionaryElements()) { 1666 continue; 1667 } 1668 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); 1669 int entry = dictionary->FindEntry(index); 1670 if (entry != NumberDictionary::kNotFound) { 1671 Object* element = dictionary->ValueAt(entry); 1672 PropertyDetails details = dictionary->DetailsAt(entry); 1673 if (details.type() == CALLBACKS) { 1674 // Only accessors allowed as elements. 1675 return FixedArray::cast(element)->get(kSetterIndex); 1676 } 1677 } 1678 } 1679 return Heap::undefined_value(); 1680 } 1681 1682 1683 void JSObject::LookupInDescriptor(String* name, LookupResult* result) { 1684 DescriptorArray* descriptors = map()->instance_descriptors(); 1685 int number = DescriptorLookupCache::Lookup(descriptors, name); 1686 if (number == DescriptorLookupCache::kAbsent) { 1687 number = descriptors->Search(name); 1688 DescriptorLookupCache::Update(descriptors, name, number); 1689 } 1690 if (number != DescriptorArray::kNotFound) { 1691 result->DescriptorResult(this, descriptors->GetDetails(number), number); 1692 } else { 1693 result->NotFound(); 1694 } 1695 } 1696 1697 1698 void JSObject::LocalLookupRealNamedProperty(String* name, 1699 LookupResult* result) { 1700 if (IsJSGlobalProxy()) { 1701 Object* proto = GetPrototype(); 1702 if (proto->IsNull()) return result->NotFound(); 1703 ASSERT(proto->IsJSGlobalObject()); 1704 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result); 1705 } 1706 1707 if (HasFastProperties()) { 1708 LookupInDescriptor(name, result); 1709 if (result->IsFound()) { 1710 // A property, a map transition or a null descriptor was found. 1711 // We return all of these result types because 1712 // LocalLookupRealNamedProperty is used when setting properties 1713 // where map transitions and null descriptors are handled. 1714 ASSERT(result->holder() == this && result->type() != NORMAL); 1715 // Disallow caching for uninitialized constants. These can only 1716 // occur as fields. 1717 if (result->IsReadOnly() && result->type() == FIELD && 1718 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) { 1719 result->DisallowCaching(); 1720 } 1721 return; 1722 } 1723 } else { 1724 int entry = property_dictionary()->FindEntry(name); 1725 if (entry != StringDictionary::kNotFound) { 1726 Object* value = property_dictionary()->ValueAt(entry); 1727 if (IsGlobalObject()) { 1728 PropertyDetails d = property_dictionary()->DetailsAt(entry); 1729 if (d.IsDeleted()) { 1730 result->NotFound(); 1731 return; 1732 } 1733 value = JSGlobalPropertyCell::cast(value)->value(); 1734 } 1735 // Make sure to disallow caching for uninitialized constants 1736 // found in the dictionary-mode objects. 1737 if (value->IsTheHole()) result->DisallowCaching(); 1738 result->DictionaryResult(this, entry); 1739 return; 1740 } 1741 // Slow case object skipped during lookup. Do not use inline caching. 1742 if (!IsGlobalObject()) result->DisallowCaching(); 1743 } 1744 result->NotFound(); 1745 } 1746 1747 1748 void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) { 1749 LocalLookupRealNamedProperty(name, result); 1750 if (result->IsProperty()) return; 1751 1752 LookupRealNamedPropertyInPrototypes(name, result); 1753 } 1754 1755 1756 void JSObject::LookupRealNamedPropertyInPrototypes(String* name, 1757 LookupResult* result) { 1758 for (Object* pt = GetPrototype(); 1759 pt != Heap::null_value(); 1760 pt = JSObject::cast(pt)->GetPrototype()) { 1761 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); 1762 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return; 1763 } 1764 result->NotFound(); 1765 } 1766 1767 1768 // We only need to deal with CALLBACKS and INTERCEPTORS 1769 Object* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result, 1770 String* name, 1771 Object* value) { 1772 if (!result->IsProperty()) { 1773 LookupCallbackSetterInPrototypes(name, result); 1774 } 1775 1776 if (result->IsProperty()) { 1777 if (!result->IsReadOnly()) { 1778 switch (result->type()) { 1779 case CALLBACKS: { 1780 Object* obj = result->GetCallbackObject(); 1781 if (obj->IsAccessorInfo()) { 1782 AccessorInfo* info = AccessorInfo::cast(obj); 1783 if (info->all_can_write()) { 1784 return SetPropertyWithCallback(result->GetCallbackObject(), 1785 name, 1786 value, 1787 result->holder()); 1788 } 1789 } 1790 break; 1791 } 1792 case INTERCEPTOR: { 1793 // Try lookup real named properties. Note that only property can be 1794 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain. 1795 LookupResult r; 1796 LookupRealNamedProperty(name, &r); 1797 if (r.IsProperty()) { 1798 return SetPropertyWithFailedAccessCheck(&r, name, value); 1799 } 1800 break; 1801 } 1802 default: { 1803 break; 1804 } 1805 } 1806 } 1807 } 1808 1809 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); 1810 return value; 1811 } 1812 1813 1814 Object* JSObject::SetProperty(LookupResult* result, 1815 String* name, 1816 Object* value, 1817 PropertyAttributes attributes) { 1818 // Make sure that the top context does not change when doing callbacks or 1819 // interceptor calls. 1820 AssertNoContextChange ncc; 1821 1822 // Optimization for 2-byte strings often used as keys in a decompression 1823 // dictionary. We make these short keys into symbols to avoid constantly 1824 // reallocating them. 1825 if (!name->IsSymbol() && name->length() <= 2) { 1826 Object* symbol_version = Heap::LookupSymbol(name); 1827 if (!symbol_version->IsFailure()) name = String::cast(symbol_version); 1828 } 1829 1830 // Check access rights if needed. 1831 if (IsAccessCheckNeeded() 1832 && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { 1833 return SetPropertyWithFailedAccessCheck(result, name, value); 1834 } 1835 1836 if (IsJSGlobalProxy()) { 1837 Object* proto = GetPrototype(); 1838 if (proto->IsNull()) return value; 1839 ASSERT(proto->IsJSGlobalObject()); 1840 return JSObject::cast(proto)->SetProperty(result, name, value, attributes); 1841 } 1842 1843 if (!result->IsProperty() && !IsJSContextExtensionObject()) { 1844 // We could not find a local property so let's check whether there is an 1845 // accessor that wants to handle the property. 1846 LookupResult accessor_result; 1847 LookupCallbackSetterInPrototypes(name, &accessor_result); 1848 if (accessor_result.IsProperty()) { 1849 return SetPropertyWithCallback(accessor_result.GetCallbackObject(), 1850 name, 1851 value, 1852 accessor_result.holder()); 1853 } 1854 } 1855 if (!result->IsFound()) { 1856 // Neither properties nor transitions found. 1857 return AddProperty(name, value, attributes); 1858 } 1859 if (result->IsReadOnly() && result->IsProperty()) return value; 1860 // This is a real property that is not read-only, or it is a 1861 // transition or null descriptor and there are no setters in the prototypes. 1862 switch (result->type()) { 1863 case NORMAL: 1864 return SetNormalizedProperty(result, value); 1865 case FIELD: 1866 return FastPropertyAtPut(result->GetFieldIndex(), value); 1867 case MAP_TRANSITION: 1868 if (attributes == result->GetAttributes()) { 1869 // Only use map transition if the attributes match. 1870 return AddFastPropertyUsingMap(result->GetTransitionMap(), 1871 name, 1872 value); 1873 } 1874 return ConvertDescriptorToField(name, value, attributes); 1875 case CONSTANT_FUNCTION: 1876 // Only replace the function if necessary. 1877 if (value == result->GetConstantFunction()) return value; 1878 // Preserve the attributes of this existing property. 1879 attributes = result->GetAttributes(); 1880 return ConvertDescriptorToField(name, value, attributes); 1881 case CALLBACKS: 1882 return SetPropertyWithCallback(result->GetCallbackObject(), 1883 name, 1884 value, 1885 result->holder()); 1886 case INTERCEPTOR: 1887 return SetPropertyWithInterceptor(name, value, attributes); 1888 case CONSTANT_TRANSITION: 1889 // Replace with a MAP_TRANSITION to a new map with a FIELD, even 1890 // if the value is a function. 1891 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 1892 case NULL_DESCRIPTOR: 1893 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 1894 default: 1895 UNREACHABLE(); 1896 } 1897 UNREACHABLE(); 1898 return value; 1899 } 1900 1901 1902 // Set a real local property, even if it is READ_ONLY. If the property is not 1903 // present, add it with attributes NONE. This code is an exact clone of 1904 // SetProperty, with the check for IsReadOnly and the check for a 1905 // callback setter removed. The two lines looking up the LookupResult 1906 // result are also added. If one of the functions is changed, the other 1907 // should be. 1908 Object* JSObject::IgnoreAttributesAndSetLocalProperty( 1909 String* name, 1910 Object* value, 1911 PropertyAttributes attributes) { 1912 // Make sure that the top context does not change when doing callbacks or 1913 // interceptor calls. 1914 AssertNoContextChange ncc; 1915 LookupResult result; 1916 LocalLookup(name, &result); 1917 // Check access rights if needed. 1918 if (IsAccessCheckNeeded() 1919 && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { 1920 return SetPropertyWithFailedAccessCheck(&result, name, value); 1921 } 1922 1923 if (IsJSGlobalProxy()) { 1924 Object* proto = GetPrototype(); 1925 if (proto->IsNull()) return value; 1926 ASSERT(proto->IsJSGlobalObject()); 1927 return JSObject::cast(proto)->IgnoreAttributesAndSetLocalProperty( 1928 name, 1929 value, 1930 attributes); 1931 } 1932 1933 // Check for accessor in prototype chain removed here in clone. 1934 if (!result.IsFound()) { 1935 // Neither properties nor transitions found. 1936 return AddProperty(name, value, attributes); 1937 } 1938 PropertyDetails details = PropertyDetails(attributes, NORMAL); 1939 1940 // Check of IsReadOnly removed from here in clone. 1941 switch (result.type()) { 1942 case NORMAL: 1943 return SetNormalizedProperty(name, value, details); 1944 case FIELD: 1945 return FastPropertyAtPut(result.GetFieldIndex(), value); 1946 case MAP_TRANSITION: 1947 if (attributes == result.GetAttributes()) { 1948 // Only use map transition if the attributes match. 1949 return AddFastPropertyUsingMap(result.GetTransitionMap(), 1950 name, 1951 value); 1952 } 1953 return ConvertDescriptorToField(name, value, attributes); 1954 case CONSTANT_FUNCTION: 1955 // Only replace the function if necessary. 1956 if (value == result.GetConstantFunction()) return value; 1957 // Preserve the attributes of this existing property. 1958 attributes = result.GetAttributes(); 1959 return ConvertDescriptorToField(name, value, attributes); 1960 case CALLBACKS: 1961 case INTERCEPTOR: 1962 // Override callback in clone 1963 return ConvertDescriptorToField(name, value, attributes); 1964 case CONSTANT_TRANSITION: 1965 // Replace with a MAP_TRANSITION to a new map with a FIELD, even 1966 // if the value is a function. 1967 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 1968 case NULL_DESCRIPTOR: 1969 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 1970 default: 1971 UNREACHABLE(); 1972 } 1973 UNREACHABLE(); 1974 return value; 1975 } 1976 1977 1978 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( 1979 JSObject* receiver, 1980 String* name, 1981 bool continue_search) { 1982 // Check local property, ignore interceptor. 1983 LookupResult result; 1984 LocalLookupRealNamedProperty(name, &result); 1985 if (result.IsProperty()) return result.GetAttributes(); 1986 1987 if (continue_search) { 1988 // Continue searching via the prototype chain. 1989 Object* pt = GetPrototype(); 1990 if (pt != Heap::null_value()) { 1991 return JSObject::cast(pt)-> 1992 GetPropertyAttributeWithReceiver(receiver, name); 1993 } 1994 } 1995 return ABSENT; 1996 } 1997 1998 1999 PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor( 2000 JSObject* receiver, 2001 String* name, 2002 bool continue_search) { 2003 // Make sure that the top context does not change when doing 2004 // callbacks or interceptor calls. 2005 AssertNoContextChange ncc; 2006 2007 HandleScope scope; 2008 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); 2009 Handle<JSObject> receiver_handle(receiver); 2010 Handle<JSObject> holder_handle(this); 2011 Handle<String> name_handle(name); 2012 CustomArguments args(interceptor->data(), receiver, this); 2013 v8::AccessorInfo info(args.end()); 2014 if (!interceptor->query()->IsUndefined()) { 2015 v8::NamedPropertyQuery query = 2016 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query()); 2017 LOG(ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name)); 2018 v8::Handle<v8::Boolean> result; 2019 { 2020 // Leaving JavaScript. 2021 VMState state(EXTERNAL); 2022 result = query(v8::Utils::ToLocal(name_handle), info); 2023 } 2024 if (!result.IsEmpty()) { 2025 // Convert the boolean result to a property attribute 2026 // specification. 2027 return result->IsTrue() ? NONE : ABSENT; 2028 } 2029 } else if (!interceptor->getter()->IsUndefined()) { 2030 v8::NamedPropertyGetter getter = 2031 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); 2032 LOG(ApiNamedPropertyAccess("interceptor-named-get-has", this, name)); 2033 v8::Handle<v8::Value> result; 2034 { 2035 // Leaving JavaScript. 2036 VMState state(EXTERNAL); 2037 result = getter(v8::Utils::ToLocal(name_handle), info); 2038 } 2039 if (!result.IsEmpty()) return NONE; 2040 } 2041 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle, 2042 *name_handle, 2043 continue_search); 2044 } 2045 2046 2047 PropertyAttributes JSObject::GetPropertyAttributeWithReceiver( 2048 JSObject* receiver, 2049 String* key) { 2050 uint32_t index = 0; 2051 if (key->AsArrayIndex(&index)) { 2052 if (HasElementWithReceiver(receiver, index)) return NONE; 2053 return ABSENT; 2054 } 2055 // Named property. 2056 LookupResult result; 2057 Lookup(key, &result); 2058 return GetPropertyAttribute(receiver, &result, key, true); 2059 } 2060 2061 2062 PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver, 2063 LookupResult* result, 2064 String* name, 2065 bool continue_search) { 2066 // Check access rights if needed. 2067 if (IsAccessCheckNeeded() && 2068 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { 2069 return GetPropertyAttributeWithFailedAccessCheck(receiver, 2070 result, 2071 name, 2072 continue_search); 2073 } 2074 if (result->IsProperty()) { 2075 switch (result->type()) { 2076 case NORMAL: // fall through 2077 case FIELD: 2078 case CONSTANT_FUNCTION: 2079 case CALLBACKS: 2080 return result->GetAttributes(); 2081 case INTERCEPTOR: 2082 return result->holder()-> 2083 GetPropertyAttributeWithInterceptor(receiver, name, continue_search); 2084 default: 2085 UNREACHABLE(); 2086 } 2087 } 2088 return ABSENT; 2089 } 2090 2091 2092 PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) { 2093 // Check whether the name is an array index. 2094 uint32_t index = 0; 2095 if (name->AsArrayIndex(&index)) { 2096 if (HasLocalElement(index)) return NONE; 2097 return ABSENT; 2098 } 2099 // Named property. 2100 LookupResult result; 2101 LocalLookup(name, &result); 2102 return GetPropertyAttribute(this, &result, name, false); 2103 } 2104 2105 2106 Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode, 2107 int expected_additional_properties) { 2108 if (!HasFastProperties()) return this; 2109 2110 // The global object is always normalized. 2111 ASSERT(!IsGlobalObject()); 2112 2113 // Allocate new content. 2114 int property_count = map()->NumberOfDescribedProperties(); 2115 if (expected_additional_properties > 0) { 2116 property_count += expected_additional_properties; 2117 } else { 2118 property_count += 2; // Make space for two more properties. 2119 } 2120 Object* obj = 2121 StringDictionary::Allocate(property_count * 2); 2122 if (obj->IsFailure()) return obj; 2123 StringDictionary* dictionary = StringDictionary::cast(obj); 2124 2125 DescriptorArray* descs = map()->instance_descriptors(); 2126 for (int i = 0; i < descs->number_of_descriptors(); i++) { 2127 PropertyDetails details = descs->GetDetails(i); 2128 switch (details.type()) { 2129 case CONSTANT_FUNCTION: { 2130 PropertyDetails d = 2131 PropertyDetails(details.attributes(), NORMAL, details.index()); 2132 Object* value = descs->GetConstantFunction(i); 2133 Object* result = dictionary->Add(descs->GetKey(i), value, d); 2134 if (result->IsFailure()) return result; 2135 dictionary = StringDictionary::cast(result); 2136 break; 2137 } 2138 case FIELD: { 2139 PropertyDetails d = 2140 PropertyDetails(details.attributes(), NORMAL, details.index()); 2141 Object* value = FastPropertyAt(descs->GetFieldIndex(i)); 2142 Object* result = dictionary->Add(descs->GetKey(i), value, d); 2143 if (result->IsFailure()) return result; 2144 dictionary = StringDictionary::cast(result); 2145 break; 2146 } 2147 case CALLBACKS: { 2148 PropertyDetails d = 2149 PropertyDetails(details.attributes(), CALLBACKS, details.index()); 2150 Object* value = descs->GetCallbacksObject(i); 2151 Object* result = dictionary->Add(descs->GetKey(i), value, d); 2152 if (result->IsFailure()) return result; 2153 dictionary = StringDictionary::cast(result); 2154 break; 2155 } 2156 case MAP_TRANSITION: 2157 case CONSTANT_TRANSITION: 2158 case NULL_DESCRIPTOR: 2159 case INTERCEPTOR: 2160 break; 2161 default: 2162 UNREACHABLE(); 2163 } 2164 } 2165 2166 // Copy the next enumeration index from instance descriptor. 2167 int index = map()->instance_descriptors()->NextEnumerationIndex(); 2168 dictionary->SetNextEnumerationIndex(index); 2169 2170 // Allocate new map. 2171 obj = map()->CopyDropDescriptors(); 2172 if (obj->IsFailure()) return obj; 2173 Map* new_map = Map::cast(obj); 2174 2175 // Clear inobject properties if needed by adjusting the instance size and 2176 // putting in a filler object instead of the inobject properties. 2177 if (mode == CLEAR_INOBJECT_PROPERTIES && map()->inobject_properties() > 0) { 2178 int instance_size_delta = map()->inobject_properties() * kPointerSize; 2179 int new_instance_size = map()->instance_size() - instance_size_delta; 2180 new_map->set_inobject_properties(0); 2181 new_map->set_instance_size(new_instance_size); 2182 Heap::CreateFillerObjectAt(this->address() + new_instance_size, 2183 instance_size_delta); 2184 } 2185 new_map->set_unused_property_fields(0); 2186 2187 // We have now successfully allocated all the necessary objects. 2188 // Changes can now be made with the guarantee that all of them take effect. 2189 set_map(new_map); 2190 map()->set_instance_descriptors(Heap::empty_descriptor_array()); 2191 2192 set_properties(dictionary); 2193 2194 Counters::props_to_dictionary.Increment(); 2195 2196 #ifdef DEBUG 2197 if (FLAG_trace_normalization) { 2198 PrintF("Object properties have been normalized:\n"); 2199 Print(); 2200 } 2201 #endif 2202 return this; 2203 } 2204 2205 2206 Object* JSObject::TransformToFastProperties(int unused_property_fields) { 2207 if (HasFastProperties()) return this; 2208 ASSERT(!IsGlobalObject()); 2209 return property_dictionary()-> 2210 TransformPropertiesToFastFor(this, unused_property_fields); 2211 } 2212 2213 2214 Object* JSObject::NormalizeElements() { 2215 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); 2216 if (HasDictionaryElements()) return this; 2217 2218 // Get number of entries. 2219 FixedArray* array = FixedArray::cast(elements()); 2220 2221 // Compute the effective length. 2222 int length = IsJSArray() ? 2223 Smi::cast(JSArray::cast(this)->length())->value() : 2224 array->length(); 2225 Object* obj = NumberDictionary::Allocate(length); 2226 if (obj->IsFailure()) return obj; 2227 NumberDictionary* dictionary = NumberDictionary::cast(obj); 2228 // Copy entries. 2229 for (int i = 0; i < length; i++) { 2230 Object* value = array->get(i); 2231 if (!value->IsTheHole()) { 2232 PropertyDetails details = PropertyDetails(NONE, NORMAL); 2233 Object* result = dictionary->AddNumberEntry(i, array->get(i), details); 2234 if (result->IsFailure()) return result; 2235 dictionary = NumberDictionary::cast(result); 2236 } 2237 } 2238 // Switch to using the dictionary as the backing storage for elements. 2239 set_elements(dictionary); 2240 2241 Counters::elements_to_dictionary.Increment(); 2242 2243 #ifdef DEBUG 2244 if (FLAG_trace_normalization) { 2245 PrintF("Object elements have been normalized:\n"); 2246 Print(); 2247 } 2248 #endif 2249 2250 return this; 2251 } 2252 2253 2254 Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) { 2255 // Check local property, ignore interceptor. 2256 LookupResult result; 2257 LocalLookupRealNamedProperty(name, &result); 2258 if (!result.IsProperty()) return Heap::true_value(); 2259 2260 // Normalize object if needed. 2261 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 2262 if (obj->IsFailure()) return obj; 2263 2264 return DeleteNormalizedProperty(name, mode); 2265 } 2266 2267 2268 Object* JSObject::DeletePropertyWithInterceptor(String* name) { 2269 HandleScope scope; 2270 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); 2271 Handle<String> name_handle(name); 2272 Handle<JSObject> this_handle(this); 2273 if (!interceptor->deleter()->IsUndefined()) { 2274 v8::NamedPropertyDeleter deleter = 2275 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter()); 2276 LOG(ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name)); 2277 CustomArguments args(interceptor->data(), this, this); 2278 v8::AccessorInfo info(args.end()); 2279 v8::Handle<v8::Boolean> result; 2280 { 2281 // Leaving JavaScript. 2282 VMState state(EXTERNAL); 2283 result = deleter(v8::Utils::ToLocal(name_handle), info); 2284 } 2285 RETURN_IF_SCHEDULED_EXCEPTION(); 2286 if (!result.IsEmpty()) { 2287 ASSERT(result->IsBoolean()); 2288 return *v8::Utils::OpenHandle(*result); 2289 } 2290 } 2291 Object* raw_result = 2292 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); 2293 RETURN_IF_SCHEDULED_EXCEPTION(); 2294 return raw_result; 2295 } 2296 2297 2298 Object* JSObject::DeleteElementPostInterceptor(uint32_t index, 2299 DeleteMode mode) { 2300 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); 2301 switch (GetElementsKind()) { 2302 case FAST_ELEMENTS: { 2303 uint32_t length = IsJSArray() ? 2304 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : 2305 static_cast<uint32_t>(FixedArray::cast(elements())->length()); 2306 if (index < length) { 2307 FixedArray::cast(elements())->set_the_hole(index); 2308 } 2309 break; 2310 } 2311 case DICTIONARY_ELEMENTS: { 2312 NumberDictionary* dictionary = element_dictionary(); 2313 int entry = dictionary->FindEntry(index); 2314 if (entry != NumberDictionary::kNotFound) { 2315 return dictionary->DeleteProperty(entry, mode); 2316 } 2317 break; 2318 } 2319 default: 2320 UNREACHABLE(); 2321 break; 2322 } 2323 return Heap::true_value(); 2324 } 2325 2326 2327 Object* JSObject::DeleteElementWithInterceptor(uint32_t index) { 2328 // Make sure that the top context does not change when doing 2329 // callbacks or interceptor calls. 2330 AssertNoContextChange ncc; 2331 HandleScope scope; 2332 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); 2333 if (interceptor->deleter()->IsUndefined()) return Heap::false_value(); 2334 v8::IndexedPropertyDeleter deleter = 2335 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter()); 2336 Handle<JSObject> this_handle(this); 2337 LOG(ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index)); 2338 CustomArguments args(interceptor->data(), this, this); 2339 v8::AccessorInfo info(args.end()); 2340 v8::Handle<v8::Boolean> result; 2341 { 2342 // Leaving JavaScript. 2343 VMState state(EXTERNAL); 2344 result = deleter(index, info); 2345 } 2346 RETURN_IF_SCHEDULED_EXCEPTION(); 2347 if (!result.IsEmpty()) { 2348 ASSERT(result->IsBoolean()); 2349 return *v8::Utils::OpenHandle(*result); 2350 } 2351 Object* raw_result = 2352 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); 2353 RETURN_IF_SCHEDULED_EXCEPTION(); 2354 return raw_result; 2355 } 2356 2357 2358 Object* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { 2359 // Check access rights if needed. 2360 if (IsAccessCheckNeeded() && 2361 !Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { 2362 Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE); 2363 return Heap::false_value(); 2364 } 2365 2366 if (IsJSGlobalProxy()) { 2367 Object* proto = GetPrototype(); 2368 if (proto->IsNull()) return Heap::false_value(); 2369 ASSERT(proto->IsJSGlobalObject()); 2370 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); 2371 } 2372 2373 if (HasIndexedInterceptor()) { 2374 // Skip interceptor if forcing deletion. 2375 if (mode == FORCE_DELETION) { 2376 return DeleteElementPostInterceptor(index, mode); 2377 } 2378 return DeleteElementWithInterceptor(index); 2379 } 2380 2381 switch (GetElementsKind()) { 2382 case FAST_ELEMENTS: { 2383 uint32_t length = IsJSArray() ? 2384 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : 2385 static_cast<uint32_t>(FixedArray::cast(elements())->length()); 2386 if (index < length) { 2387 FixedArray::cast(elements())->set_the_hole(index); 2388 } 2389 break; 2390 } 2391 case PIXEL_ELEMENTS: 2392 case EXTERNAL_BYTE_ELEMENTS: 2393 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 2394 case EXTERNAL_SHORT_ELEMENTS: 2395 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 2396 case EXTERNAL_INT_ELEMENTS: 2397 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 2398 case EXTERNAL_FLOAT_ELEMENTS: 2399 // Pixel and external array elements cannot be deleted. Just 2400 // silently ignore here. 2401 break; 2402 case DICTIONARY_ELEMENTS: { 2403 NumberDictionary* dictionary = element_dictionary(); 2404 int entry = dictionary->FindEntry(index); 2405 if (entry != NumberDictionary::kNotFound) { 2406 return dictionary->DeleteProperty(entry, mode); 2407 } 2408 break; 2409 } 2410 default: 2411 UNREACHABLE(); 2412 break; 2413 } 2414 return Heap::true_value(); 2415 } 2416 2417 2418 Object* JSObject::DeleteProperty(String* name, DeleteMode mode) { 2419 // ECMA-262, 3rd, 8.6.2.5 2420 ASSERT(name->IsString()); 2421 2422 // Check access rights if needed. 2423 if (IsAccessCheckNeeded() && 2424 !Top::MayNamedAccess(this, name, v8::ACCESS_DELETE)) { 2425 Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE); 2426 return Heap::false_value(); 2427 } 2428 2429 if (IsJSGlobalProxy()) { 2430 Object* proto = GetPrototype(); 2431 if (proto->IsNull()) return Heap::false_value(); 2432 ASSERT(proto->IsJSGlobalObject()); 2433 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode); 2434 } 2435 2436 uint32_t index = 0; 2437 if (name->AsArrayIndex(&index)) { 2438 return DeleteElement(index, mode); 2439 } else { 2440 LookupResult result; 2441 LocalLookup(name, &result); 2442 if (!result.IsProperty()) return Heap::true_value(); 2443 // Ignore attributes if forcing a deletion. 2444 if (result.IsDontDelete() && mode != FORCE_DELETION) { 2445 return Heap::false_value(); 2446 } 2447 // Check for interceptor. 2448 if (result.type() == INTERCEPTOR) { 2449 // Skip interceptor if forcing a deletion. 2450 if (mode == FORCE_DELETION) { 2451 return DeletePropertyPostInterceptor(name, mode); 2452 } 2453 return DeletePropertyWithInterceptor(name); 2454 } 2455 // Normalize object if needed. 2456 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 2457 if (obj->IsFailure()) return obj; 2458 // Make sure the properties are normalized before removing the entry. 2459 return DeleteNormalizedProperty(name, mode); 2460 } 2461 } 2462 2463 2464 // Check whether this object references another object. 2465 bool JSObject::ReferencesObject(Object* obj) { 2466 AssertNoAllocation no_alloc; 2467 2468 // Is the object the constructor for this object? 2469 if (map()->constructor() == obj) { 2470 return true; 2471 } 2472 2473 // Is the object the prototype for this object? 2474 if (map()->prototype() == obj) { 2475 return true; 2476 } 2477 2478 // Check if the object is among the named properties. 2479 Object* key = SlowReverseLookup(obj); 2480 if (key != Heap::undefined_value()) { 2481 return true; 2482 } 2483 2484 // Check if the object is among the indexed properties. 2485 switch (GetElementsKind()) { 2486 case PIXEL_ELEMENTS: 2487 case EXTERNAL_BYTE_ELEMENTS: 2488 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 2489 case EXTERNAL_SHORT_ELEMENTS: 2490 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 2491 case EXTERNAL_INT_ELEMENTS: 2492 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 2493 case EXTERNAL_FLOAT_ELEMENTS: 2494 // Raw pixels and external arrays do not reference other 2495 // objects. 2496 break; 2497 case FAST_ELEMENTS: { 2498 int length = IsJSArray() ? 2499 Smi::cast(JSArray::cast(this)->length())->value() : 2500 FixedArray::cast(elements())->length(); 2501 for (int i = 0; i < length; i++) { 2502 Object* element = FixedArray::cast(elements())->get(i); 2503 if (!element->IsTheHole() && element == obj) { 2504 return true; 2505 } 2506 } 2507 break; 2508 } 2509 case DICTIONARY_ELEMENTS: { 2510 key = element_dictionary()->SlowReverseLookup(obj); 2511 if (key != Heap::undefined_value()) { 2512 return true; 2513 } 2514 break; 2515 } 2516 default: 2517 UNREACHABLE(); 2518 break; 2519 } 2520 2521 // For functions check the context. Boilerplate functions do 2522 // not have to be traversed since they have no real context. 2523 if (IsJSFunction() && !JSFunction::cast(this)->IsBoilerplate()) { 2524 // Get the constructor function for arguments array. 2525 JSObject* arguments_boilerplate = 2526 Top::context()->global_context()->arguments_boilerplate(); 2527 JSFunction* arguments_function = 2528 JSFunction::cast(arguments_boilerplate->map()->constructor()); 2529 2530 // Get the context and don't check if it is the global context. 2531 JSFunction* f = JSFunction::cast(this); 2532 Context* context = f->context(); 2533 if (context->IsGlobalContext()) { 2534 return false; 2535 } 2536 2537 // Check the non-special context slots. 2538 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) { 2539 // Only check JS objects. 2540 if (context->get(i)->IsJSObject()) { 2541 JSObject* ctxobj = JSObject::cast(context->get(i)); 2542 // If it is an arguments array check the content. 2543 if (ctxobj->map()->constructor() == arguments_function) { 2544 if (ctxobj->ReferencesObject(obj)) { 2545 return true; 2546 } 2547 } else if (ctxobj == obj) { 2548 return true; 2549 } 2550 } 2551 } 2552 2553 // Check the context extension if any. 2554 if (context->has_extension()) { 2555 return context->extension()->ReferencesObject(obj); 2556 } 2557 } 2558 2559 // No references to object. 2560 return false; 2561 } 2562 2563 2564 // Tests for the fast common case for property enumeration: 2565 // - This object and all prototypes has an enum cache (which means that it has 2566 // no interceptors and needs no access checks). 2567 // - This object has no elements. 2568 // - No prototype has enumerable properties/elements. 2569 bool JSObject::IsSimpleEnum() { 2570 for (Object* o = this; 2571 o != Heap::null_value(); 2572 o = JSObject::cast(o)->GetPrototype()) { 2573 JSObject* curr = JSObject::cast(o); 2574 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false; 2575 ASSERT(!curr->HasNamedInterceptor()); 2576 ASSERT(!curr->HasIndexedInterceptor()); 2577 ASSERT(!curr->IsAccessCheckNeeded()); 2578 if (curr->NumberOfEnumElements() > 0) return false; 2579 if (curr != this) { 2580 FixedArray* curr_fixed_array = 2581 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache()); 2582 if (curr_fixed_array->length() > 0) return false; 2583 } 2584 } 2585 return true; 2586 } 2587 2588 2589 int Map::NumberOfDescribedProperties() { 2590 int result = 0; 2591 DescriptorArray* descs = instance_descriptors(); 2592 for (int i = 0; i < descs->number_of_descriptors(); i++) { 2593 if (descs->IsProperty(i)) result++; 2594 } 2595 return result; 2596 } 2597 2598 2599 int Map::PropertyIndexFor(String* name) { 2600 DescriptorArray* descs = instance_descriptors(); 2601 for (int i = 0; i < descs->number_of_descriptors(); i++) { 2602 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) { 2603 return descs->GetFieldIndex(i); 2604 } 2605 } 2606 return -1; 2607 } 2608 2609 2610 int Map::NextFreePropertyIndex() { 2611 int max_index = -1; 2612 DescriptorArray* descs = instance_descriptors(); 2613 for (int i = 0; i < descs->number_of_descriptors(); i++) { 2614 if (descs->GetType(i) == FIELD) { 2615 int current_index = descs->GetFieldIndex(i); 2616 if (current_index > max_index) max_index = current_index; 2617 } 2618 } 2619 return max_index + 1; 2620 } 2621 2622 2623 AccessorDescriptor* Map::FindAccessor(String* name) { 2624 DescriptorArray* descs = instance_descriptors(); 2625 for (int i = 0; i < descs->number_of_descriptors(); i++) { 2626 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { 2627 return descs->GetCallbacks(i); 2628 } 2629 } 2630 return NULL; 2631 } 2632 2633 2634 void JSObject::LocalLookup(String* name, LookupResult* result) { 2635 ASSERT(name->IsString()); 2636 2637 if (IsJSGlobalProxy()) { 2638 Object* proto = GetPrototype(); 2639 if (proto->IsNull()) return result->NotFound(); 2640 ASSERT(proto->IsJSGlobalObject()); 2641 return JSObject::cast(proto)->LocalLookup(name, result); 2642 } 2643 2644 // Do not use inline caching if the object is a non-global object 2645 // that requires access checks. 2646 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) { 2647 result->DisallowCaching(); 2648 } 2649 2650 // Check __proto__ before interceptor. 2651 if (name->Equals(Heap::Proto_symbol()) && !IsJSContextExtensionObject()) { 2652 result->ConstantResult(this); 2653 return; 2654 } 2655 2656 // Check for lookup interceptor except when bootstrapping. 2657 if (HasNamedInterceptor() && !Bootstrapper::IsActive()) { 2658 result->InterceptorResult(this); 2659 return; 2660 } 2661 2662 LocalLookupRealNamedProperty(name, result); 2663 } 2664 2665 2666 void JSObject::Lookup(String* name, LookupResult* result) { 2667 // Ecma-262 3rd 8.6.2.4 2668 for (Object* current = this; 2669 current != Heap::null_value(); 2670 current = JSObject::cast(current)->GetPrototype()) { 2671 JSObject::cast(current)->LocalLookup(name, result); 2672 if (result->IsProperty()) return; 2673 } 2674 result->NotFound(); 2675 } 2676 2677 2678 // Search object and it's prototype chain for callback properties. 2679 void JSObject::LookupCallback(String* name, LookupResult* result) { 2680 for (Object* current = this; 2681 current != Heap::null_value(); 2682 current = JSObject::cast(current)->GetPrototype()) { 2683 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); 2684 if (result->IsProperty() && result->type() == CALLBACKS) return; 2685 } 2686 result->NotFound(); 2687 } 2688 2689 2690 Object* JSObject::DefineGetterSetter(String* name, 2691 PropertyAttributes attributes) { 2692 // Make sure that the top context does not change when doing callbacks or 2693 // interceptor calls. 2694 AssertNoContextChange ncc; 2695 2696 // Check access rights if needed. 2697 if (IsAccessCheckNeeded() && 2698 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { 2699 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); 2700 return Heap::undefined_value(); 2701 } 2702 2703 // Try to flatten before operating on the string. 2704 name->TryFlattenIfNotFlat(); 2705 2706 // Check if there is an API defined callback object which prohibits 2707 // callback overwriting in this object or it's prototype chain. 2708 // This mechanism is needed for instance in a browser setting, where 2709 // certain accessors such as window.location should not be allowed 2710 // to be overwritten because allowing overwriting could potentially 2711 // cause security problems. 2712 LookupResult callback_result; 2713 LookupCallback(name, &callback_result); 2714 if (callback_result.IsFound()) { 2715 Object* obj = callback_result.GetCallbackObject(); 2716 if (obj->IsAccessorInfo() && 2717 AccessorInfo::cast(obj)->prohibits_overwriting()) { 2718 return Heap::undefined_value(); 2719 } 2720 } 2721 2722 uint32_t index; 2723 bool is_element = name->AsArrayIndex(&index); 2724 if (is_element && IsJSArray()) return Heap::undefined_value(); 2725 2726 if (is_element) { 2727 switch (GetElementsKind()) { 2728 case FAST_ELEMENTS: 2729 break; 2730 case PIXEL_ELEMENTS: 2731 case EXTERNAL_BYTE_ELEMENTS: 2732 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 2733 case EXTERNAL_SHORT_ELEMENTS: 2734 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 2735 case EXTERNAL_INT_ELEMENTS: 2736 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 2737 case EXTERNAL_FLOAT_ELEMENTS: 2738 // Ignore getters and setters on pixel and external array 2739 // elements. 2740 return Heap::undefined_value(); 2741 case DICTIONARY_ELEMENTS: { 2742 // Lookup the index. 2743 NumberDictionary* dictionary = element_dictionary(); 2744 int entry = dictionary->FindEntry(index); 2745 if (entry != NumberDictionary::kNotFound) { 2746 Object* result = dictionary->ValueAt(entry); 2747 PropertyDetails details = dictionary->DetailsAt(entry); 2748 if (details.IsReadOnly()) return Heap::undefined_value(); 2749 if (details.type() == CALLBACKS) { 2750 // Only accessors allowed as elements. 2751 ASSERT(result->IsFixedArray()); 2752 return result; 2753 } 2754 } 2755 break; 2756 } 2757 default: 2758 UNREACHABLE(); 2759 break; 2760 } 2761 } else { 2762 // Lookup the name. 2763 LookupResult result; 2764 LocalLookup(name, &result); 2765 if (result.IsProperty()) { 2766 if (result.IsReadOnly()) return Heap::undefined_value(); 2767 if (result.type() == CALLBACKS) { 2768 Object* obj = result.GetCallbackObject(); 2769 if (obj->IsFixedArray()) { 2770 // The object might be in fast mode even though it has 2771 // a getter/setter. 2772 Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 2773 if (ok->IsFailure()) return ok; 2774 2775 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); 2776 SetNormalizedProperty(name, obj, details); 2777 return obj; 2778 } 2779 } 2780 } 2781 } 2782 2783 // Allocate the fixed array to hold getter and setter. 2784 Object* structure = Heap::AllocateFixedArray(2, TENURED); 2785 if (structure->IsFailure()) return structure; 2786 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); 2787 2788 if (is_element) { 2789 // Normalize object to make this operation simple. 2790 Object* ok = NormalizeElements(); 2791 if (ok->IsFailure()) return ok; 2792 2793 // Update the dictionary with the new CALLBACKS property. 2794 Object* dict = 2795 element_dictionary()->Set(index, structure, details); 2796 if (dict->IsFailure()) return dict; 2797 2798 // If name is an index we need to stay in slow case. 2799 NumberDictionary* elements = NumberDictionary::cast(dict); 2800 elements->set_requires_slow_elements(); 2801 // Set the potential new dictionary on the object. 2802 set_elements(NumberDictionary::cast(dict)); 2803 } else { 2804 // Normalize object to make this operation simple. 2805 Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 2806 if (ok->IsFailure()) return ok; 2807 2808 // For the global object allocate a new map to invalidate the global inline 2809 // caches which have a global property cell reference directly in the code. 2810 if (IsGlobalObject()) { 2811 Object* new_map = map()->CopyDropDescriptors(); 2812 if (new_map->IsFailure()) return new_map; 2813 set_map(Map::cast(new_map)); 2814 } 2815 2816 // Update the dictionary with the new CALLBACKS property. 2817 return SetNormalizedProperty(name, structure, details); 2818 } 2819 2820 return structure; 2821 } 2822 2823 2824 Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun, 2825 PropertyAttributes attributes) { 2826 // Check access rights if needed. 2827 if (IsAccessCheckNeeded() && 2828 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { 2829 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); 2830 return Heap::undefined_value(); 2831 } 2832 2833 if (IsJSGlobalProxy()) { 2834 Object* proto = GetPrototype(); 2835 if (proto->IsNull()) return this; 2836 ASSERT(proto->IsJSGlobalObject()); 2837 return JSObject::cast(proto)->DefineAccessor(name, is_getter, 2838 fun, attributes); 2839 } 2840 2841 Object* array = DefineGetterSetter(name, attributes); 2842 if (array->IsFailure() || array->IsUndefined()) return array; 2843 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun); 2844 return this; 2845 } 2846 2847 2848 Object* JSObject::LookupAccessor(String* name, bool is_getter) { 2849 // Make sure that the top context does not change when doing callbacks or 2850 // interceptor calls. 2851 AssertNoContextChange ncc; 2852 2853 // Check access rights if needed. 2854 if (IsAccessCheckNeeded() && 2855 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { 2856 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); 2857 return Heap::undefined_value(); 2858 } 2859 2860 // Make the lookup and include prototypes. 2861 int accessor_index = is_getter ? kGetterIndex : kSetterIndex; 2862 uint32_t index; 2863 if (name->AsArrayIndex(&index)) { 2864 for (Object* obj = this; 2865 obj != Heap::null_value(); 2866 obj = JSObject::cast(obj)->GetPrototype()) { 2867 JSObject* js_object = JSObject::cast(obj); 2868 if (js_object->HasDictionaryElements()) { 2869 NumberDictionary* dictionary = js_object->element_dictionary(); 2870 int entry = dictionary->FindEntry(index); 2871 if (entry != NumberDictionary::kNotFound) { 2872 Object* element = dictionary->ValueAt(entry); 2873 PropertyDetails details = dictionary->DetailsAt(entry); 2874 if (details.type() == CALLBACKS) { 2875 // Only accessors allowed as elements. 2876 return FixedArray::cast(element)->get(accessor_index); 2877 } 2878 } 2879 } 2880 } 2881 } else { 2882 for (Object* obj = this; 2883 obj != Heap::null_value(); 2884 obj = JSObject::cast(obj)->GetPrototype()) { 2885 LookupResult result; 2886 JSObject::cast(obj)->LocalLookup(name, &result); 2887 if (result.IsProperty()) { 2888 if (result.IsReadOnly()) return Heap::undefined_value(); 2889 if (result.type() == CALLBACKS) { 2890 Object* obj = result.GetCallbackObject(); 2891 if (obj->IsFixedArray()) { 2892 return FixedArray::cast(obj)->get(accessor_index); 2893 } 2894 } 2895 } 2896 } 2897 } 2898 return Heap::undefined_value(); 2899 } 2900 2901 2902 Object* JSObject::SlowReverseLookup(Object* value) { 2903 if (HasFastProperties()) { 2904 DescriptorArray* descs = map()->instance_descriptors(); 2905 for (int i = 0; i < descs->number_of_descriptors(); i++) { 2906 if (descs->GetType(i) == FIELD) { 2907 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) { 2908 return descs->GetKey(i); 2909 } 2910 } else if (descs->GetType(i) == CONSTANT_FUNCTION) { 2911 if (descs->GetConstantFunction(i) == value) { 2912 return descs->GetKey(i); 2913 } 2914 } 2915 } 2916 return Heap::undefined_value(); 2917 } else { 2918 return property_dictionary()->SlowReverseLookup(value); 2919 } 2920 } 2921 2922 2923 Object* Map::CopyDropDescriptors() { 2924 Object* result = Heap::AllocateMap(instance_type(), instance_size()); 2925 if (result->IsFailure()) return result; 2926 Map::cast(result)->set_prototype(prototype()); 2927 Map::cast(result)->set_constructor(constructor()); 2928 // Don't copy descriptors, so map transitions always remain a forest. 2929 // If we retained the same descriptors we would have two maps 2930 // pointing to the same transition which is bad because the garbage 2931 // collector relies on being able to reverse pointers from transitions 2932 // to maps. If properties need to be retained use CopyDropTransitions. 2933 Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array()); 2934 // Please note instance_type and instance_size are set when allocated. 2935 Map::cast(result)->set_inobject_properties(inobject_properties()); 2936 Map::cast(result)->set_unused_property_fields(unused_property_fields()); 2937 2938 // If the map has pre-allocated properties always start out with a descriptor 2939 // array describing these properties. 2940 if (pre_allocated_property_fields() > 0) { 2941 ASSERT(constructor()->IsJSFunction()); 2942 JSFunction* ctor = JSFunction::cast(constructor()); 2943 Object* descriptors = 2944 ctor->initial_map()->instance_descriptors()->RemoveTransitions(); 2945 if (descriptors->IsFailure()) return descriptors; 2946 Map::cast(result)->set_instance_descriptors( 2947 DescriptorArray::cast(descriptors)); 2948 Map::cast(result)->set_pre_allocated_property_fields( 2949 pre_allocated_property_fields()); 2950 } 2951 Map::cast(result)->set_bit_field(bit_field()); 2952 Map::cast(result)->set_bit_field2(bit_field2()); 2953 Map::cast(result)->ClearCodeCache(); 2954 return result; 2955 } 2956 2957 2958 Object* Map::CopyDropTransitions() { 2959 Object* new_map = CopyDropDescriptors(); 2960 if (new_map->IsFailure()) return new_map; 2961 Object* descriptors = instance_descriptors()->RemoveTransitions(); 2962 if (descriptors->IsFailure()) return descriptors; 2963 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); 2964 return cast(new_map); 2965 } 2966 2967 2968 Object* Map::UpdateCodeCache(String* name, Code* code) { 2969 ASSERT(code->ic_state() == MONOMORPHIC); 2970 FixedArray* cache = code_cache(); 2971 2972 // When updating the code cache we disregard the type encoded in the 2973 // flags. This allows call constant stubs to overwrite call field 2974 // stubs, etc. 2975 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); 2976 2977 // First check whether we can update existing code cache without 2978 // extending it. 2979 int length = cache->length(); 2980 int deleted_index = -1; 2981 for (int i = 0; i < length; i += 2) { 2982 Object* key = cache->get(i); 2983 if (key->IsNull()) { 2984 if (deleted_index < 0) deleted_index = i; 2985 continue; 2986 } 2987 if (key->IsUndefined()) { 2988 if (deleted_index >= 0) i = deleted_index; 2989 cache->set(i + 0, name); 2990 cache->set(i + 1, code); 2991 return this; 2992 } 2993 if (name->Equals(String::cast(key))) { 2994 Code::Flags found = Code::cast(cache->get(i + 1))->flags(); 2995 if (Code::RemoveTypeFromFlags(found) == flags) { 2996 cache->set(i + 1, code); 2997 return this; 2998 } 2999 } 3000 } 3001 3002 // Reached the end of the code cache. If there were deleted 3003 // elements, reuse the space for the first of them. 3004 if (deleted_index >= 0) { 3005 cache->set(deleted_index + 0, name); 3006 cache->set(deleted_index + 1, code); 3007 return this; 3008 } 3009 3010 // Extend the code cache with some new entries (at least one). 3011 int new_length = length + ((length >> 1) & ~1) + 2; 3012 ASSERT((new_length & 1) == 0); // must be a multiple of two 3013 Object* result = cache->CopySize(new_length); 3014 if (result->IsFailure()) return result; 3015 3016 // Add the (name, code) pair to the new cache. 3017 cache = FixedArray::cast(result); 3018 cache->set(length + 0, name); 3019 cache->set(length + 1, code); 3020 set_code_cache(cache); 3021 return this; 3022 } 3023 3024 3025 Object* Map::FindInCodeCache(String* name, Code::Flags flags) { 3026 FixedArray* cache = code_cache(); 3027 int length = cache->length(); 3028 for (int i = 0; i < length; i += 2) { 3029 Object* key = cache->get(i); 3030 // Skip deleted elements. 3031 if (key->IsNull()) continue; 3032 if (key->IsUndefined()) return key; 3033 if (name->Equals(String::cast(key))) { 3034 Code* code = Code::cast(cache->get(i + 1)); 3035 if (code->flags() == flags) return code; 3036 } 3037 } 3038 return Heap::undefined_value(); 3039 } 3040 3041 3042 int Map::IndexInCodeCache(Code* code) { 3043 FixedArray* array = code_cache(); 3044 int len = array->length(); 3045 for (int i = 0; i < len; i += 2) { 3046 if (array->get(i + 1) == code) return i + 1; 3047 } 3048 return -1; 3049 } 3050 3051 3052 void Map::RemoveFromCodeCache(int index) { 3053 FixedArray* array = code_cache(); 3054 ASSERT(array->length() >= index && array->get(index)->IsCode()); 3055 // Use null instead of undefined for deleted elements to distinguish 3056 // deleted elements from unused elements. This distinction is used 3057 // when looking up in the cache and when updating the cache. 3058 array->set_null(index - 1); // key 3059 array->set_null(index); // code 3060 } 3061 3062 3063 void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) { 3064 IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize); 3065 } 3066 3067 3068 static bool HasKey(FixedArray* array, Object* key) { 3069 int len0 = array->length(); 3070 for (int i = 0; i < len0; i++) { 3071 Object* element = array->get(i); 3072 if (element->IsSmi() && key->IsSmi() && (element == key)) return true; 3073 if (element->IsString() && 3074 key->IsString() && String::cast(element)->Equals(String::cast(key))) { 3075 return true; 3076 } 3077 } 3078 return false; 3079 } 3080 3081 3082 Object* FixedArray::AddKeysFromJSArray(JSArray* array) { 3083 ASSERT(!array->HasPixelElements() && !array->HasExternalArrayElements()); 3084 switch (array->GetElementsKind()) { 3085 case JSObject::FAST_ELEMENTS: 3086 return UnionOfKeys(FixedArray::cast(array->elements())); 3087 case JSObject::DICTIONARY_ELEMENTS: { 3088 NumberDictionary* dict = array->element_dictionary(); 3089 int size = dict->NumberOfElements(); 3090 3091 // Allocate a temporary fixed array. 3092 Object* object = Heap::AllocateFixedArray(size); 3093 if (object->IsFailure()) return object; 3094 FixedArray* key_array = FixedArray::cast(object); 3095 3096 int capacity = dict->Capacity(); 3097 int pos = 0; 3098 // Copy the elements from the JSArray to the temporary fixed array. 3099 for (int i = 0; i < capacity; i++) { 3100 if (dict->IsKey(dict->KeyAt(i))) { 3101 key_array->set(pos++, dict->ValueAt(i)); 3102 } 3103 } 3104 // Compute the union of this and the temporary fixed array. 3105 return UnionOfKeys(key_array); 3106 } 3107 default: 3108 UNREACHABLE(); 3109 } 3110 UNREACHABLE(); 3111 return Heap::null_value(); // Failure case needs to "return" a value. 3112 } 3113 3114 3115 Object* FixedArray::UnionOfKeys(FixedArray* other) { 3116 int len0 = length(); 3117 int len1 = other->length(); 3118 // Optimize if either is empty. 3119 if (len0 == 0) return other; 3120 if (len1 == 0) return this; 3121 3122 // Compute how many elements are not in this. 3123 int extra = 0; 3124 for (int