1 // Copyright 2011 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 "codegen.h" 34 #include "debug.h" 35 #include "deoptimizer.h" 36 #include "execution.h" 37 #include "full-codegen.h" 38 #include "hydrogen.h" 39 #include "objects-inl.h" 40 #include "objects-visiting.h" 41 #include "macro-assembler.h" 42 #include "safepoint-table.h" 43 #include "scanner-base.h" 44 #include "scopeinfo.h" 45 #include "string-stream.h" 46 #include "utils.h" 47 #include "vm-state-inl.h" 48 49 #ifdef ENABLE_DISASSEMBLER 50 #include "disasm.h" 51 #include "disassembler.h" 52 #endif 53 54 namespace v8 { 55 namespace internal { 56 57 // Getters and setters are stored in a fixed array property. These are 58 // constants for their indices. 59 const int kGetterIndex = 0; 60 const int kSetterIndex = 1; 61 62 63 MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, 64 Object* value) { 65 Object* result; 66 { MaybeObject* maybe_result = 67 constructor->GetHeap()->AllocateJSObject(constructor); 68 if (!maybe_result->ToObject(&result)) return maybe_result; 69 } 70 JSValue::cast(result)->set_value(value); 71 return result; 72 } 73 74 75 MaybeObject* Object::ToObject(Context* global_context) { 76 if (IsNumber()) { 77 return CreateJSValue(global_context->number_function(), this); 78 } else if (IsBoolean()) { 79 return CreateJSValue(global_context->boolean_function(), this); 80 } else if (IsString()) { 81 return CreateJSValue(global_context->string_function(), this); 82 } 83 ASSERT(IsJSObject()); 84 return this; 85 } 86 87 88 MaybeObject* Object::ToObject() { 89 if (IsJSObject()) { 90 return this; 91 } else if (IsNumber()) { 92 Isolate* isolate = Isolate::Current(); 93 Context* global_context = isolate->context()->global_context(); 94 return CreateJSValue(global_context->number_function(), this); 95 } else if (IsBoolean()) { 96 Isolate* isolate = HeapObject::cast(this)->GetIsolate(); 97 Context* global_context = isolate->context()->global_context(); 98 return CreateJSValue(global_context->boolean_function(), this); 99 } else if (IsString()) { 100 Isolate* isolate = HeapObject::cast(this)->GetIsolate(); 101 Context* global_context = isolate->context()->global_context(); 102 return CreateJSValue(global_context->string_function(), this); 103 } 104 105 // Throw a type error. 106 return Failure::InternalError(); 107 } 108 109 110 Object* Object::ToBoolean() { 111 if (IsTrue()) return this; 112 if (IsFalse()) return this; 113 if (IsSmi()) { 114 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0); 115 } 116 HeapObject* heap_object = HeapObject::cast(this); 117 if (heap_object->IsUndefined() || heap_object->IsNull()) { 118 return heap_object->GetHeap()->false_value(); 119 } 120 // Undetectable object is false 121 if (heap_object->IsUndetectableObject()) { 122 return heap_object->GetHeap()->false_value(); 123 } 124 if (heap_object->IsString()) { 125 return heap_object->GetHeap()->ToBoolean( 126 String::cast(this)->length() != 0); 127 } 128 if (heap_object->IsHeapNumber()) { 129 return HeapNumber::cast(this)->HeapNumberToBoolean(); 130 } 131 return heap_object->GetHeap()->true_value(); 132 } 133 134 135 void Object::Lookup(String* name, LookupResult* result) { 136 Object* holder = NULL; 137 if (IsSmi()) { 138 Heap* heap = Isolate::Current()->heap(); 139 Context* global_context = heap->isolate()->context()->global_context(); 140 holder = global_context->number_function()->instance_prototype(); 141 } else { 142 HeapObject* heap_object = HeapObject::cast(this); 143 if (heap_object->IsJSObject()) { 144 return JSObject::cast(this)->Lookup(name, result); 145 } 146 Heap* heap = heap_object->GetHeap(); 147 if (heap_object->IsString()) { 148 Context* global_context = heap->isolate()->context()->global_context(); 149 holder = global_context->string_function()->instance_prototype(); 150 } else if (heap_object->IsHeapNumber()) { 151 Context* global_context = heap->isolate()->context()->global_context(); 152 holder = global_context->number_function()->instance_prototype(); 153 } else if (heap_object->IsBoolean()) { 154 Context* global_context = heap->isolate()->context()->global_context(); 155 holder = global_context->boolean_function()->instance_prototype(); 156 } 157 } 158 ASSERT(holder != NULL); // Cannot handle null or undefined. 159 JSObject::cast(holder)->Lookup(name, result); 160 } 161 162 163 MaybeObject* Object::GetPropertyWithReceiver(Object* receiver, 164 String* name, 165 PropertyAttributes* attributes) { 166 LookupResult result; 167 Lookup(name, &result); 168 MaybeObject* value = GetProperty(receiver, &result, name, attributes); 169 ASSERT(*attributes <= ABSENT); 170 return value; 171 } 172 173 174 MaybeObject* Object::GetPropertyWithCallback(Object* receiver, 175 Object* structure, 176 String* name, 177 Object* holder) { 178 Isolate* isolate = name->GetIsolate(); 179 // To accommodate both the old and the new api we switch on the 180 // data structure used to store the callbacks. Eventually proxy 181 // callbacks should be phased out. 182 if (structure->IsProxy()) { 183 AccessorDescriptor* callback = 184 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy()); 185 MaybeObject* value = (callback->getter)(receiver, callback->data); 186 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 187 return value; 188 } 189 190 // api style callbacks. 191 if (structure->IsAccessorInfo()) { 192 AccessorInfo* data = AccessorInfo::cast(structure); 193 Object* fun_obj = data->getter(); 194 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); 195 HandleScope scope; 196 JSObject* self = JSObject::cast(receiver); 197 JSObject* holder_handle = JSObject::cast(holder); 198 Handle<String> key(name); 199 LOG(isolate, ApiNamedPropertyAccess("load", self, name)); 200 CustomArguments args(isolate, data->data(), self, holder_handle); 201 v8::AccessorInfo info(args.end()); 202 v8::Handle<v8::Value> result; 203 { 204 // Leaving JavaScript. 205 VMState state(isolate, EXTERNAL); 206 result = call_fun(v8::Utils::ToLocal(key), info); 207 } 208 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 209 if (result.IsEmpty()) { 210 return isolate->heap()->undefined_value(); 211 } 212 return *v8::Utils::OpenHandle(*result); 213 } 214 215 // __defineGetter__ callback 216 if (structure->IsFixedArray()) { 217 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); 218 if (getter->IsJSFunction()) { 219 return Object::GetPropertyWithDefinedGetter(receiver, 220 JSFunction::cast(getter)); 221 } 222 // Getter is not a function. 223 return isolate->heap()->undefined_value(); 224 } 225 226 UNREACHABLE(); 227 return NULL; 228 } 229 230 231 MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver, 232 JSFunction* getter) { 233 HandleScope scope; 234 Handle<JSFunction> fun(JSFunction::cast(getter)); 235 Handle<Object> self(receiver); 236 #ifdef ENABLE_DEBUGGER_SUPPORT 237 Debug* debug = fun->GetHeap()->isolate()->debug(); 238 // Handle stepping into a getter if step into is active. 239 if (debug->StepInActive()) { 240 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false); 241 } 242 #endif 243 bool has_pending_exception; 244 Handle<Object> result = 245 Execution::Call(fun, self, 0, NULL, &has_pending_exception); 246 // Check for pending exception and return the result. 247 if (has_pending_exception) return Failure::Exception(); 248 return *result; 249 } 250 251 252 // Only deal with CALLBACKS and INTERCEPTOR 253 MaybeObject* JSObject::GetPropertyWithFailedAccessCheck( 254 Object* receiver, 255 LookupResult* result, 256 String* name, 257 PropertyAttributes* attributes) { 258 if (result->IsProperty()) { 259 switch (result->type()) { 260 case CALLBACKS: { 261 // Only allow API accessors. 262 Object* obj = result->GetCallbackObject(); 263 if (obj->IsAccessorInfo()) { 264 AccessorInfo* info = AccessorInfo::cast(obj); 265 if (info->all_can_read()) { 266 *attributes = result->GetAttributes(); 267 return GetPropertyWithCallback(receiver, 268 result->GetCallbackObject(), 269 name, 270 result->holder()); 271 } 272 } 273 break; 274 } 275 case NORMAL: 276 case FIELD: 277 case CONSTANT_FUNCTION: { 278 // Search ALL_CAN_READ accessors in prototype chain. 279 LookupResult r; 280 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r); 281 if (r.IsProperty()) { 282 return GetPropertyWithFailedAccessCheck(receiver, 283 &r, 284 name, 285 attributes); 286 } 287 break; 288 } 289 case INTERCEPTOR: { 290 // If the object has an interceptor, try real named properties. 291 // No access check in GetPropertyAttributeWithInterceptor. 292 LookupResult r; 293 result->holder()->LookupRealNamedProperty(name, &r); 294 if (r.IsProperty()) { 295 return GetPropertyWithFailedAccessCheck(receiver, 296 &r, 297 name, 298 attributes); 299 } 300 break; 301 } 302 default: 303 UNREACHABLE(); 304 } 305 } 306 307 // No accessible property found. 308 *attributes = ABSENT; 309 Heap* heap = name->GetHeap(); 310 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET); 311 return heap->undefined_value(); 312 } 313 314 315 PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck( 316 Object* receiver, 317 LookupResult* result, 318 String* name, 319 bool continue_search) { 320 if (result->IsProperty()) { 321 switch (result->type()) { 322 case CALLBACKS: { 323 // Only allow API accessors. 324 Object* obj = result->GetCallbackObject(); 325 if (obj->IsAccessorInfo()) { 326 AccessorInfo* info = AccessorInfo::cast(obj); 327 if (info->all_can_read()) { 328 return result->GetAttributes(); 329 } 330 } 331 break; 332 } 333 334 case NORMAL: 335 case FIELD: 336 case CONSTANT_FUNCTION: { 337 if (!continue_search) break; 338 // Search ALL_CAN_READ accessors in prototype chain. 339 LookupResult r; 340 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r); 341 if (r.IsProperty()) { 342 return GetPropertyAttributeWithFailedAccessCheck(receiver, 343 &r, 344 name, 345 continue_search); 346 } 347 break; 348 } 349 350 case INTERCEPTOR: { 351 // If the object has an interceptor, try real named properties. 352 // No access check in GetPropertyAttributeWithInterceptor. 353 LookupResult r; 354 if (continue_search) { 355 result->holder()->LookupRealNamedProperty(name, &r); 356 } else { 357 result->holder()->LocalLookupRealNamedProperty(name, &r); 358 } 359 if (r.IsProperty()) { 360 return GetPropertyAttributeWithFailedAccessCheck(receiver, 361 &r, 362 name, 363 continue_search); 364 } 365 break; 366 } 367 368 default: 369 UNREACHABLE(); 370 } 371 } 372 373 GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); 374 return ABSENT; 375 } 376 377 378 Object* JSObject::GetNormalizedProperty(LookupResult* result) { 379 ASSERT(!HasFastProperties()); 380 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); 381 if (IsGlobalObject()) { 382 value = JSGlobalPropertyCell::cast(value)->value(); 383 } 384 ASSERT(!value->IsJSGlobalPropertyCell()); 385 return value; 386 } 387 388 389 Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) { 390 ASSERT(!HasFastProperties()); 391 if (IsGlobalObject()) { 392 JSGlobalPropertyCell* cell = 393 JSGlobalPropertyCell::cast( 394 property_dictionary()->ValueAt(result->GetDictionaryEntry())); 395 cell->set_value(value); 396 } else { 397 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value); 398 } 399 return value; 400 } 401 402 403 MaybeObject* JSObject::SetNormalizedProperty(String* name, 404 Object* value, 405 PropertyDetails details) { 406 ASSERT(!HasFastProperties()); 407 int entry = property_dictionary()->FindEntry(name); 408 if (entry == StringDictionary::kNotFound) { 409 Object* store_value = value; 410 if (IsGlobalObject()) { 411 Heap* heap = name->GetHeap(); 412 MaybeObject* maybe_store_value = 413 heap->AllocateJSGlobalPropertyCell(value); 414 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value; 415 } 416 Object* dict; 417 { MaybeObject* maybe_dict = 418 property_dictionary()->Add(name, store_value, details); 419 if (!maybe_dict->ToObject(&dict)) return maybe_dict; 420 } 421 set_properties(StringDictionary::cast(dict)); 422 return value; 423 } 424 // Preserve enumeration index. 425 details = PropertyDetails(details.attributes(), 426 details.type(), 427 property_dictionary()->DetailsAt(entry).index()); 428 if (IsGlobalObject()) { 429 JSGlobalPropertyCell* cell = 430 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry)); 431 cell->set_value(value); 432 // Please note we have to update the property details. 433 property_dictionary()->DetailsAtPut(entry, details); 434 } else { 435 property_dictionary()->SetEntry(entry, name, value, details); 436 } 437 return value; 438 } 439 440 441 MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) { 442 ASSERT(!HasFastProperties()); 443 StringDictionary* dictionary = property_dictionary(); 444 int entry = dictionary->FindEntry(name); 445 if (entry != StringDictionary::kNotFound) { 446 // If we have a global object set the cell to the hole. 447 if (IsGlobalObject()) { 448 PropertyDetails details = dictionary->DetailsAt(entry); 449 if (details.IsDontDelete()) { 450 if (mode != FORCE_DELETION) return GetHeap()->false_value(); 451 // When forced to delete global properties, we have to make a 452 // map change to invalidate any ICs that think they can load 453 // from the DontDelete cell without checking if it contains 454 // the hole value. 455 Object* new_map; 456 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); 457 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 458 } 459 set_map(Map::cast(new_map)); 460 } 461 JSGlobalPropertyCell* cell = 462 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); 463 cell->set_value(cell->heap()->the_hole_value()); 464 dictionary->DetailsAtPut(entry, details.AsDeleted()); 465 } else { 466 return dictionary->DeleteProperty(entry, mode); 467 } 468 } 469 return GetHeap()->true_value(); 470 } 471 472 473 bool JSObject::IsDirty() { 474 Object* cons_obj = map()->constructor(); 475 if (!cons_obj->IsJSFunction()) 476 return true; 477 JSFunction* fun = JSFunction::cast(cons_obj); 478 if (!fun->shared()->IsApiFunction()) 479 return true; 480 // If the object is fully fast case and has the same map it was 481 // created with then no changes can have been made to it. 482 return map() != fun->initial_map() 483 || !HasFastElements() 484 || !HasFastProperties(); 485 } 486 487 488 MaybeObject* Object::GetProperty(Object* receiver, 489 LookupResult* result, 490 String* name, 491 PropertyAttributes* attributes) { 492 // Make sure that the top context does not change when doing 493 // callbacks or interceptor calls. 494 AssertNoContextChange ncc; 495 Heap* heap = name->GetHeap(); 496 497 // Traverse the prototype chain from the current object (this) to 498 // the holder and check for access rights. This avoid traversing the 499 // objects more than once in case of interceptors, because the 500 // holder will always be the interceptor holder and the search may 501 // only continue with a current object just after the interceptor 502 // holder in the prototype chain. 503 Object* last = result->IsProperty() ? result->holder() : heap->null_value(); 504 for (Object* current = this; true; current = current->GetPrototype()) { 505 if (current->IsAccessCheckNeeded()) { 506 // Check if we're allowed to read from the current object. Note 507 // that even though we may not actually end up loading the named 508 // property from the current object, we still check that we have 509 // access to it. 510 JSObject* checked = JSObject::cast(current); 511 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) { 512 return checked->GetPropertyWithFailedAccessCheck(receiver, 513 result, 514 name, 515 attributes); 516 } 517 } 518 // Stop traversing the chain once we reach the last object in the 519 // chain; either the holder of the result or null in case of an 520 // absent property. 521 if (current == last) break; 522 } 523 524 if (!result->IsProperty()) { 525 *attributes = ABSENT; 526 return heap->undefined_value(); 527 } 528 *attributes = result->GetAttributes(); 529 Object* value; 530 JSObject* holder = result->holder(); 531 switch (result->type()) { 532 case NORMAL: 533 value = holder->GetNormalizedProperty(result); 534 ASSERT(!value->IsTheHole() || result->IsReadOnly()); 535 return value->IsTheHole() ? heap->undefined_value() : value; 536 case FIELD: 537 value = holder->FastPropertyAt(result->GetFieldIndex()); 538 ASSERT(!value->IsTheHole() || result->IsReadOnly()); 539 return value->IsTheHole() ? heap->undefined_value() : value; 540 case CONSTANT_FUNCTION: 541 return result->GetConstantFunction(); 542 case CALLBACKS: 543 return GetPropertyWithCallback(receiver, 544 result->GetCallbackObject(), 545 name, 546 holder); 547 case INTERCEPTOR: { 548 JSObject* recvr = JSObject::cast(receiver); 549 return holder->GetPropertyWithInterceptor(recvr, name, attributes); 550 } 551 default: 552 UNREACHABLE(); 553 return NULL; 554 } 555 } 556 557 558 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { 559 Object* holder = NULL; 560 if (IsSmi()) { 561 Context* global_context = Isolate::Current()->context()->global_context(); 562 holder = global_context->number_function()->instance_prototype(); 563 } else { 564 HeapObject* heap_object = HeapObject::cast(this); 565 566 if (heap_object->IsJSObject()) { 567 return JSObject::cast(this)->GetElementWithReceiver(receiver, index); 568 } 569 Heap* heap = heap_object->GetHeap(); 570 Isolate* isolate = heap->isolate(); 571 572 Context* global_context = isolate->context()->global_context(); 573 if (heap_object->IsString()) { 574 holder = global_context->string_function()->instance_prototype(); 575 } else if (heap_object->IsHeapNumber()) { 576 holder = global_context->number_function()->instance_prototype(); 577 } else if (heap_object->IsBoolean()) { 578 holder = global_context->boolean_function()->instance_prototype(); 579 } else { 580 // Undefined and null have no indexed properties. 581 ASSERT(heap_object->IsUndefined() || heap_object->IsNull()); 582 return heap->undefined_value(); 583 } 584 } 585 586 return JSObject::cast(holder)->GetElementWithReceiver(receiver, index); 587 } 588 589 590 Object* Object::GetPrototype() { 591 if (IsSmi()) { 592 Heap* heap = Isolate::Current()->heap(); 593 Context* context = heap->isolate()->context()->global_context(); 594 return context->number_function()->instance_prototype(); 595 } 596 597 HeapObject* heap_object = HeapObject::cast(this); 598 599 // The object is either a number, a string, a boolean, or a real JS object. 600 if (heap_object->IsJSObject()) { 601 return JSObject::cast(this)->map()->prototype(); 602 } 603 Heap* heap = heap_object->GetHeap(); 604 Context* context = heap->isolate()->context()->global_context(); 605 606 if (heap_object->IsHeapNumber()) { 607 return context->number_function()->instance_prototype(); 608 } 609 if (heap_object->IsString()) { 610 return context->string_function()->instance_prototype(); 611 } 612 if (heap_object->IsBoolean()) { 613 return context->boolean_function()->instance_prototype(); 614 } else { 615 return heap->null_value(); 616 } 617 } 618 619 620 void Object::ShortPrint(FILE* out) { 621 HeapStringAllocator allocator; 622 StringStream accumulator(&allocator); 623 ShortPrint(&accumulator); 624 accumulator.OutputToFile(out); 625 } 626 627 628 void Object::ShortPrint(StringStream* accumulator) { 629 if (IsSmi()) { 630 Smi::cast(this)->SmiPrint(accumulator); 631 } else if (IsFailure()) { 632 Failure::cast(this)->FailurePrint(accumulator); 633 } else { 634 HeapObject::cast(this)->HeapObjectShortPrint(accumulator); 635 } 636 } 637 638 639 void Smi::SmiPrint(FILE* out) { 640 PrintF(out, "%d", value()); 641 } 642 643 644 void Smi::SmiPrint(StringStream* accumulator) { 645 accumulator->Add("%d", value()); 646 } 647 648 649 void Failure::FailurePrint(StringStream* accumulator) { 650 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value())); 651 } 652 653 654 void Failure::FailurePrint(FILE* out) { 655 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value())); 656 } 657 658 659 // Should a word be prefixed by 'a' or 'an' in order to read naturally in 660 // English? Returns false for non-ASCII or words that don't start with 661 // a capital letter. The a/an rule follows pronunciation in English. 662 // We don't use the BBC's overcorrect "an historic occasion" though if 663 // you speak a dialect you may well say "an 'istoric occasion". 664 static bool AnWord(String* str) { 665 if (str->length() == 0) return false; // A nothing. 666 int c0 = str->Get(0); 667 int c1 = str->length() > 1 ? str->Get(1) : 0; 668 if (c0 == 'U') { 669 if (c1 > 'Z') { 670 return true; // An Umpire, but a UTF8String, a U. 671 } 672 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { 673 return true; // An Ape, an ABCBook. 674 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && 675 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || 676 c0 == 'S' || c0 == 'X')) { 677 return true; // An MP3File, an M. 678 } 679 return false; 680 } 681 682 683 MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) { 684 #ifdef DEBUG 685 // Do not attempt to flatten in debug mode when allocation is not 686 // allowed. This is to avoid an assertion failure when allocating. 687 // Flattening strings is the only case where we always allow 688 // allocation because no GC is performed if the allocation fails. 689 if (!HEAP->IsAllocationAllowed()) return this; 690 #endif 691 692 Heap* heap = GetHeap(); 693 switch (StringShape(this).representation_tag()) { 694 case kConsStringTag: { 695 ConsString* cs = ConsString::cast(this); 696 if (cs->second()->length() == 0) { 697 return cs->first(); 698 } 699 // There's little point in putting the flat string in new space if the 700 // cons string is in old space. It can never get GCed until there is 701 // an old space GC. 702 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED; 703 int len = length(); 704 Object* object; 705 String* result; 706 if (IsAsciiRepresentation()) { 707 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure); 708 if (!maybe_object->ToObject(&object)) return maybe_object; 709 } 710 result = String::cast(object); 711 String* first = cs->first(); 712 int first_length = first->length(); 713 char* dest = SeqAsciiString::cast(result)->GetChars(); 714 WriteToFlat(first, dest, 0, first_length); 715 String* second = cs->second(); 716 WriteToFlat(second, 717 dest + first_length, 718 0, 719 len - first_length); 720 } else { 721 { MaybeObject* maybe_object = 722 heap->AllocateRawTwoByteString(len, tenure); 723 if (!maybe_object->ToObject(&object)) return maybe_object; 724 } 725 result = String::cast(object); 726 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); 727 String* first = cs->first(); 728 int first_length = first->length(); 729 WriteToFlat(first, dest, 0, first_length); 730 String* second = cs->second(); 731 WriteToFlat(second, 732 dest + first_length, 733 0, 734 len - first_length); 735 } 736 cs->set_first(result); 737 cs->set_second(heap->empty_string()); 738 return result; 739 } 740 default: 741 return this; 742 } 743 } 744 745 746 bool String::MakeExternal(v8::String::ExternalStringResource* resource) { 747 // Externalizing twice leaks the external resource, so it's 748 // prohibited by the API. 749 ASSERT(!this->IsExternalString()); 750 #ifdef DEBUG 751 if (FLAG_enable_slow_asserts) { 752 // Assert that the resource and the string are equivalent. 753 ASSERT(static_cast<size_t>(this->length()) == resource->length()); 754 ScopedVector<uc16> smart_chars(this->length()); 755 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 756 ASSERT(memcmp(smart_chars.start(), 757 resource->data(), 758 resource->length() * sizeof(smart_chars[0])) == 0); 759 } 760 #endif // DEBUG 761 Heap* heap = GetHeap(); 762 int size = this->Size(); // Byte size of the original string. 763 if (size < ExternalString::kSize) { 764 // The string is too small to fit an external String in its place. This can 765 // only happen for zero length strings. 766 return false; 767 } 768 ASSERT(size >= ExternalString::kSize); 769 bool is_ascii = this->IsAsciiRepresentation(); 770 bool is_symbol = this->IsSymbol(); 771 int length = this->length(); 772 int hash_field = this->hash_field(); 773 774 // Morph the object to an external string by adjusting the map and 775 // reinitializing the fields. 776 this->set_map(is_ascii ? 777 heap->external_string_with_ascii_data_map() : 778 heap->external_string_map()); 779 ExternalTwoByteString* self = ExternalTwoByteString::cast(this); 780 self->set_length(length); 781 self->set_hash_field(hash_field); 782 self->set_resource(resource); 783 // Additionally make the object into an external symbol if the original string 784 // was a symbol to start with. 785 if (is_symbol) { 786 self->Hash(); // Force regeneration of the hash value. 787 // Now morph this external string into a external symbol. 788 this->set_map(is_ascii ? 789 heap->external_symbol_with_ascii_data_map() : 790 heap->external_symbol_map()); 791 } 792 793 // Fill the remainder of the string with dead wood. 794 int new_size = this->Size(); // Byte size of the external String object. 795 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); 796 return true; 797 } 798 799 800 bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) { 801 #ifdef DEBUG 802 if (FLAG_enable_slow_asserts) { 803 // Assert that the resource and the string are equivalent. 804 ASSERT(static_cast<size_t>(this->length()) == resource->length()); 805 ScopedVector<char> smart_chars(this->length()); 806 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 807 ASSERT(memcmp(smart_chars.start(), 808 resource->data(), 809 resource->length() * sizeof(smart_chars[0])) == 0); 810 } 811 #endif // DEBUG 812 Heap* heap = GetHeap(); 813 int size = this->Size(); // Byte size of the original string. 814 if (size < ExternalString::kSize) { 815 // The string is too small to fit an external String in its place. This can 816 // only happen for zero length strings. 817 return false; 818 } 819 ASSERT(size >= ExternalString::kSize); 820 bool is_symbol = this->IsSymbol(); 821 int length = this->length(); 822 int hash_field = this->hash_field(); 823 824 // Morph the object to an external string by adjusting the map and 825 // reinitializing the fields. 826 this->set_map(heap->external_ascii_string_map()); 827 ExternalAsciiString* self = ExternalAsciiString::cast(this); 828 self->set_length(length); 829 self->set_hash_field(hash_field); 830 self->set_resource(resource); 831 // Additionally make the object into an external symbol if the original string 832 // was a symbol to start with. 833 if (is_symbol) { 834 self->Hash(); // Force regeneration of the hash value. 835 // Now morph this external string into a external symbol. 836 this->set_map(heap->external_ascii_symbol_map()); 837 } 838 839 // Fill the remainder of the string with dead wood. 840 int new_size = this->Size(); // Byte size of the external String object. 841 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); 842 return true; 843 } 844 845 846 void String::StringShortPrint(StringStream* accumulator) { 847 int len = length(); 848 if (len > kMaxShortPrintLength) { 849 accumulator->Add("<Very long string[%u]>", len); 850 return; 851 } 852 853 if (!LooksValid()) { 854 accumulator->Add("<Invalid String>"); 855 return; 856 } 857 858 StringInputBuffer buf(this); 859 860 bool truncated = false; 861 if (len > kMaxShortPrintLength) { 862 len = kMaxShortPrintLength; 863 truncated = true; 864 } 865 bool ascii = true; 866 for (int i = 0; i < len; i++) { 867 int c = buf.GetNext(); 868 869 if (c < 32 || c >= 127) { 870 ascii = false; 871 } 872 } 873 buf.Reset(this); 874 if (ascii) { 875 accumulator->Add("<String[%u]: ", length()); 876 for (int i = 0; i < len; i++) { 877 accumulator->Put(buf.GetNext()); 878 } 879 accumulator->Put('>'); 880 } else { 881 // Backslash indicates that the string contains control 882 // characters and that backslashes are therefore escaped. 883 accumulator->Add("<String[%u]\\: ", length()); 884 for (int i = 0; i < len; i++) { 885 int c = buf.GetNext(); 886 if (c == '\n') { 887 accumulator->Add("\\n"); 888 } else if (c == '\r') { 889 accumulator->Add("\\r"); 890 } else if (c == '\\') { 891 accumulator->Add("\\\\"); 892 } else if (c < 32 || c > 126) { 893 accumulator->Add("\\x%02x", c); 894 } else { 895 accumulator->Put(c); 896 } 897 } 898 if (truncated) { 899 accumulator->Put('.'); 900 accumulator->Put('.'); 901 accumulator->Put('.'); 902 } 903 accumulator->Put('>'); 904 } 905 return; 906 } 907 908 909 void JSObject::JSObjectShortPrint(StringStream* accumulator) { 910 switch (map()->instance_type()) { 911 case JS_ARRAY_TYPE: { 912 double length = JSArray::cast(this)->length()->Number(); 913 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length)); 914 break; 915 } 916 case JS_REGEXP_TYPE: { 917 accumulator->Add("<JS RegExp>"); 918 break; 919 } 920 case JS_FUNCTION_TYPE: { 921 Object* fun_name = JSFunction::cast(this)->shared()->name(); 922 bool printed = false; 923 if (fun_name->IsString()) { 924 String* str = String::cast(fun_name); 925 if (str->length() > 0) { 926 accumulator->Add("<JS Function "); 927 accumulator->Put(str); 928 accumulator->Put('>'); 929 printed = true; 930 } 931 } 932 if (!printed) { 933 accumulator->Add("<JS Function>"); 934 } 935 break; 936 } 937 // All other JSObjects are rather similar to each other (JSObject, 938 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue). 939 default: { 940 Map* map_of_this = map(); 941 Heap* heap = map_of_this->heap(); 942 Object* constructor = map_of_this->constructor(); 943 bool printed = false; 944 if (constructor->IsHeapObject() && 945 !heap->Contains(HeapObject::cast(constructor))) { 946 accumulator->Add("!!!INVALID CONSTRUCTOR!!!"); 947 } else { 948 bool global_object = IsJSGlobalProxy(); 949 if (constructor->IsJSFunction()) { 950 if (!heap->Contains(JSFunction::cast(constructor)->shared())) { 951 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!"); 952 } else { 953 Object* constructor_name = 954 JSFunction::cast(constructor)->shared()->name(); 955 if (constructor_name->IsString()) { 956 String* str = String::cast(constructor_name); 957 if (str->length() > 0) { 958 bool vowel = AnWord(str); 959 accumulator->Add("<%sa%s ", 960 global_object ? "Global Object: " : "", 961 vowel ? "n" : ""); 962 accumulator->Put(str); 963 accumulator->Put('>'); 964 printed = true; 965 } 966 } 967 } 968 } 969 if (!printed) { 970 accumulator->Add("<JS %sObject", global_object ? "Global " : ""); 971 } 972 } 973 if (IsJSValue()) { 974 accumulator->Add(" value = "); 975 JSValue::cast(this)->value()->ShortPrint(accumulator); 976 } 977 accumulator->Put('>'); 978 break; 979 } 980 } 981 } 982 983 984 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { 985 // if (!HEAP->InNewSpace(this)) PrintF("*", this); 986 Heap* heap = GetHeap(); 987 if (!heap->Contains(this)) { 988 accumulator->Add("!!!INVALID POINTER!!!"); 989 return; 990 } 991 if (!heap->Contains(map())) { 992 accumulator->Add("!!!INVALID MAP!!!"); 993 return; 994 } 995 996 accumulator->Add("%p ", this); 997 998 if (IsString()) { 999 String::cast(this)->StringShortPrint(accumulator); 1000 return; 1001 } 1002 if (IsJSObject()) { 1003 JSObject::cast(this)->JSObjectShortPrint(accumulator); 1004 return; 1005 } 1006 switch (map()->instance_type()) { 1007 case MAP_TYPE: 1008 accumulator->Add("<Map>"); 1009 break; 1010 case FIXED_ARRAY_TYPE: 1011 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length()); 1012 break; 1013 case BYTE_ARRAY_TYPE: 1014 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length()); 1015 break; 1016 case EXTERNAL_PIXEL_ARRAY_TYPE: 1017 accumulator->Add("<ExternalPixelArray[%u]>", 1018 ExternalPixelArray::cast(this)->length()); 1019 break; 1020 case EXTERNAL_BYTE_ARRAY_TYPE: 1021 accumulator->Add("<ExternalByteArray[%u]>", 1022 ExternalByteArray::cast(this)->length()); 1023 break; 1024 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: 1025 accumulator->Add("<ExternalUnsignedByteArray[%u]>", 1026 ExternalUnsignedByteArray::cast(this)->length()); 1027 break; 1028 case EXTERNAL_SHORT_ARRAY_TYPE: 1029 accumulator->Add("<ExternalShortArray[%u]>", 1030 ExternalShortArray::cast(this)->length()); 1031 break; 1032 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: 1033 accumulator->Add("<ExternalUnsignedShortArray[%u]>", 1034 ExternalUnsignedShortArray::cast(this)->length()); 1035 break; 1036 case EXTERNAL_INT_ARRAY_TYPE: 1037 accumulator->Add("<ExternalIntArray[%u]>", 1038 ExternalIntArray::cast(this)->length()); 1039 break; 1040 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: 1041 accumulator->Add("<ExternalUnsignedIntArray[%u]>", 1042 ExternalUnsignedIntArray::cast(this)->length()); 1043 break; 1044 case EXTERNAL_FLOAT_ARRAY_TYPE: 1045 accumulator->Add("<ExternalFloatArray[%u]>", 1046 ExternalFloatArray::cast(this)->length()); 1047 break; 1048 case SHARED_FUNCTION_INFO_TYPE: 1049 accumulator->Add("<SharedFunctionInfo>"); 1050 break; 1051 case JS_MESSAGE_OBJECT_TYPE: 1052 accumulator->Add("<JSMessageObject>"); 1053 break; 1054 #define MAKE_STRUCT_CASE(NAME, Name, name) \ 1055 case NAME##_TYPE: \ 1056 accumulator->Put('<'); \ 1057 accumulator->Add(#Name); \ 1058 accumulator->Put('>'); \ 1059 break; 1060 STRUCT_LIST(MAKE_STRUCT_CASE) 1061 #undef MAKE_STRUCT_CASE 1062 case CODE_TYPE: 1063 accumulator->Add("<Code>"); 1064 break; 1065 case ODDBALL_TYPE: { 1066 if (IsUndefined()) 1067 accumulator->Add("<undefined>"); 1068 else if (IsTheHole()) 1069 accumulator->Add("<the hole>"); 1070 else if (IsNull()) 1071 accumulator->Add("<null>"); 1072 else if (IsTrue()) 1073 accumulator->Add("<true>"); 1074 else if (IsFalse()) 1075 accumulator->Add("<false>"); 1076 else 1077 accumulator->Add("<Odd Oddball>"); 1078 break; 1079 } 1080 case HEAP_NUMBER_TYPE: 1081 accumulator->Add("<Number: "); 1082 HeapNumber::cast(this)->HeapNumberPrint(accumulator); 1083 accumulator->Put('>'); 1084 break; 1085 case PROXY_TYPE: 1086 accumulator->Add("<Proxy>"); 1087 break; 1088 case JS_GLOBAL_PROPERTY_CELL_TYPE: 1089 accumulator->Add("Cell for "); 1090 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator); 1091 break; 1092 default: 1093 accumulator->Add("<Other heap object (%d)>", map()->instance_type()); 1094 break; 1095 } 1096 } 1097 1098 1099 void HeapObject::Iterate(ObjectVisitor* v) { 1100 // Handle header 1101 IteratePointer(v, kMapOffset); 1102 // Handle object body 1103 Map* m = map(); 1104 IterateBody(m->instance_type(), SizeFromMap(m), v); 1105 } 1106 1107 1108 void HeapObject::IterateBody(InstanceType type, int object_size, 1109 ObjectVisitor* v) { 1110 // Avoiding <Type>::cast(this) because it accesses the map pointer field. 1111 // During GC, the map pointer field is encoded. 1112 if (type < FIRST_NONSTRING_TYPE) { 1113 switch (type & kStringRepresentationMask) { 1114 case kSeqStringTag: 1115 break; 1116 case kConsStringTag: 1117 ConsString::BodyDescriptor::IterateBody(this, v); 1118 break; 1119 case kExternalStringTag: 1120 if ((type & kStringEncodingMask) == kAsciiStringTag) { 1121 reinterpret_cast<ExternalAsciiString*>(this)-> 1122 ExternalAsciiStringIterateBody(v); 1123 } else { 1124 reinterpret_cast<ExternalTwoByteString*>(this)-> 1125 ExternalTwoByteStringIterateBody(v); 1126 } 1127 break; 1128 } 1129 return; 1130 } 1131 1132 switch (type) { 1133 case FIXED_ARRAY_TYPE: 1134 FixedArray::BodyDescriptor::IterateBody(this, object_size, v); 1135 break; 1136 case JS_OBJECT_TYPE: 1137 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 1138 case JS_VALUE_TYPE: 1139 case JS_ARRAY_TYPE: 1140 case JS_REGEXP_TYPE: 1141 case JS_GLOBAL_PROXY_TYPE: 1142 case JS_GLOBAL_OBJECT_TYPE: 1143 case JS_BUILTINS_OBJECT_TYPE: 1144 case JS_MESSAGE_OBJECT_TYPE: 1145 JSObject::BodyDescriptor::IterateBody(this, object_size, v); 1146 break; 1147 case JS_FUNCTION_TYPE: 1148 reinterpret_cast<JSFunction*>(this) 1149 ->JSFunctionIterateBody(object_size, v); 1150 break; 1151 case ODDBALL_TYPE: 1152 Oddball::BodyDescriptor::IterateBody(this, v); 1153 break; 1154 case PROXY_TYPE: 1155 reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v); 1156 break; 1157 case MAP_TYPE: 1158 Map::BodyDescriptor::IterateBody(this, v); 1159 break; 1160 case CODE_TYPE: 1161 reinterpret_cast<Code*>(this)->CodeIterateBody(v); 1162 break; 1163 case JS_GLOBAL_PROPERTY_CELL_TYPE: 1164 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v); 1165 break; 1166 case HEAP_NUMBER_TYPE: 1167 case FILLER_TYPE: 1168 case BYTE_ARRAY_TYPE: 1169 case EXTERNAL_PIXEL_ARRAY_TYPE: 1170 case EXTERNAL_BYTE_ARRAY_TYPE: 1171 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: 1172 case EXTERNAL_SHORT_ARRAY_TYPE: 1173 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: 1174 case EXTERNAL_INT_ARRAY_TYPE: 1175 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: 1176 case EXTERNAL_FLOAT_ARRAY_TYPE: 1177 break; 1178 case SHARED_FUNCTION_INFO_TYPE: 1179 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v); 1180 break; 1181 1182 #define MAKE_STRUCT_CASE(NAME, Name, name) \ 1183 case NAME##_TYPE: 1184 STRUCT_LIST(MAKE_STRUCT_CASE) 1185 #undef MAKE_STRUCT_CASE 1186 StructBodyDescriptor::IterateBody(this, object_size, v); 1187 break; 1188 default: 1189 PrintF("Unknown type: %d\n", type); 1190 UNREACHABLE(); 1191 } 1192 } 1193 1194 1195 Object* HeapNumber::HeapNumberToBoolean() { 1196 // NaN, +0, and -0 should return the false object 1197 #if __BYTE_ORDER == __LITTLE_ENDIAN 1198 union IeeeDoubleLittleEndianArchType u; 1199 #elif __BYTE_ORDER == __BIG_ENDIAN 1200 union IeeeDoubleBigEndianArchType u; 1201 #endif 1202 u.d = value(); 1203 if (u.bits.exp == 2047) { 1204 // Detect NaN for IEEE double precision floating point. 1205 if ((u.bits.man_low | u.bits.man_high) != 0) 1206 return GetHeap()->false_value(); 1207 } 1208 if (u.bits.exp == 0) { 1209 // Detect +0, and -0 for IEEE double precision floating point. 1210 if ((u.bits.man_low | u.bits.man_high) == 0) 1211 return GetHeap()->false_value(); 1212 } 1213 return GetHeap()->true_value(); 1214 } 1215 1216 1217 void HeapNumber::HeapNumberPrint(FILE* out) { 1218 PrintF(out, "%.16g", Number()); 1219 } 1220 1221 1222 void HeapNumber::HeapNumberPrint(StringStream* accumulator) { 1223 // The Windows version of vsnprintf can allocate when printing a %g string 1224 // into a buffer that may not be big enough. We don't want random memory 1225 // allocation when producing post-crash stack traces, so we print into a 1226 // buffer that is plenty big enough for any floating point number, then 1227 // print that using vsnprintf (which may truncate but never allocate if 1228 // there is no more space in the buffer). 1229 EmbeddedVector<char, 100> buffer; 1230 OS::SNPrintF(buffer, "%.16g", Number()); 1231 accumulator->Add("%s", buffer.start()); 1232 } 1233 1234 1235 String* JSObject::class_name() { 1236 if (IsJSFunction()) { 1237 return GetHeap()->function_class_symbol(); 1238 } 1239 if (map()->constructor()->IsJSFunction()) { 1240 JSFunction* constructor = JSFunction::cast(map()->constructor()); 1241 return String::cast(constructor->shared()->instance_class_name()); 1242 } 1243 // If the constructor is not present, return "Object". 1244 return GetHeap()->Object_symbol(); 1245 } 1246 1247 1248 String* JSObject::constructor_name() { 1249 if (map()->constructor()->IsJSFunction()) { 1250 JSFunction* constructor = JSFunction::cast(map()->constructor()); 1251 String* name = String::cast(constructor->shared()->name()); 1252 if (name->length() > 0) return name; 1253 String* inferred_name = constructor->shared()->inferred_name(); 1254 if (inferred_name->length() > 0) return inferred_name; 1255 Object* proto = GetPrototype(); 1256 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name(); 1257 } 1258 // If the constructor is not present, return "Object". 1259 return GetHeap()->Object_symbol(); 1260 } 1261 1262 1263 MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, 1264 String* name, 1265 Object* value) { 1266 int index = new_map->PropertyIndexFor(name); 1267 if (map()->unused_property_fields() == 0) { 1268 ASSERT(map()->unused_property_fields() == 0); 1269 int new_unused = new_map->unused_property_fields(); 1270 Object* values; 1271 { MaybeObject* maybe_values = 1272 properties()->CopySize(properties()->length() + new_unused + 1); 1273 if (!maybe_values->ToObject(&values)) return maybe_values; 1274 } 1275 set_properties(FixedArray::cast(values)); 1276 } 1277 set_map(new_map); 1278 return FastPropertyAtPut(index, value); 1279 } 1280 1281 1282 static bool IsIdentifier(UnicodeCache* cache, 1283 unibrow::CharacterStream* buffer) { 1284 // Checks whether the buffer contains an identifier (no escape). 1285 if (!buffer->has_more()) return false; 1286 if (!cache->IsIdentifierStart(buffer->GetNext())) { 1287 return false; 1288 } 1289 while (buffer->has_more()) { 1290 if (!cache->IsIdentifierPart(buffer->GetNext())) { 1291 return false; 1292 } 1293 } 1294 return true; 1295 } 1296 1297 1298 MaybeObject* JSObject::AddFastProperty(String* name, 1299 Object* value, 1300 PropertyAttributes attributes) { 1301 ASSERT(!IsJSGlobalProxy()); 1302 1303 // Normalize the object if the name is an actual string (not the 1304 // hidden symbols) and is not a real identifier. 1305 Isolate* isolate = GetHeap()->isolate(); 1306 StringInputBuffer buffer(name); 1307 if (!IsIdentifier(isolate->unicode_cache(), &buffer) 1308 && name != isolate->heap()->hidden_symbol()) { 1309 Object* obj; 1310 { MaybeObject* maybe_obj = 1311 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1312 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1313 } 1314 return AddSlowProperty(name, value, attributes); 1315 } 1316 1317 DescriptorArray* old_descriptors = map()->instance_descriptors(); 1318 // Compute the new index for new field. 1319 int index = map()->NextFreePropertyIndex(); 1320 1321 // Allocate new instance descriptors with (name, index) added 1322 FieldDescriptor new_field(name, index, attributes); 1323 Object* new_descriptors; 1324 { MaybeObject* maybe_new_descriptors = 1325 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS); 1326 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { 1327 return maybe_new_descriptors; 1328 } 1329 } 1330 1331 // Only allow map transition if the object isn't the global object and there 1332 // is not a transition for the name, or there's a transition for the name but 1333 // it's unrelated to properties. 1334 int descriptor_index = old_descriptors->Search(name); 1335 1336 // External array transitions are stored in the descriptor for property "", 1337 // which is not a identifier and should have forced a switch to slow 1338 // properties above. 1339 ASSERT(descriptor_index == DescriptorArray::kNotFound || 1340 old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION); 1341 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound || 1342 old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION; 1343 bool allow_map_transition = 1344 can_insert_transition && 1345 (isolate->context()->global_context()->object_function()->map() != map()); 1346 1347 ASSERT(index < map()->inobject_properties() || 1348 (index - map()->inobject_properties()) < properties()->length() || 1349 map()->unused_property_fields() == 0); 1350 // Allocate a new map for the object. 1351 Object* r; 1352 { MaybeObject* maybe_r = map()->CopyDropDescriptors(); 1353 if (!maybe_r->ToObject(&r)) return maybe_r; 1354 } 1355 Map* new_map = Map::cast(r); 1356 if (allow_map_transition) { 1357 // Allocate new instance descriptors for the old map with map transition. 1358 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); 1359 Object* r; 1360 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); 1361 if (!maybe_r->ToObject(&r)) return maybe_r; 1362 } 1363 old_descriptors = DescriptorArray::cast(r); 1364 } 1365 1366 if (map()->unused_property_fields() == 0) { 1367 if (properties()->length() > MaxFastProperties()) { 1368 Object* obj; 1369 { MaybeObject* maybe_obj = 1370 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1371 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1372 } 1373 return AddSlowProperty(name, value, attributes); 1374 } 1375 // Make room for the new value 1376 Object* values; 1377 { MaybeObject* maybe_values = 1378 properties()->CopySize(properties()->length() + kFieldsAdded); 1379 if (!maybe_values->ToObject(&values)) return maybe_values; 1380 } 1381 set_properties(FixedArray::cast(values)); 1382 new_map->set_unused_property_fields(kFieldsAdded - 1); 1383 } else { 1384 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); 1385 } 1386 // We have now allocated all the necessary objects. 1387 // All the changes can be applied at once, so they are atomic. 1388 map()->set_instance_descriptors(old_descriptors); 1389 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); 1390 set_map(new_map); 1391 return FastPropertyAtPut(index, value); 1392 } 1393 1394 1395 MaybeObject* JSObject::AddConstantFunctionProperty( 1396 String* name, 1397 JSFunction* function, 1398 PropertyAttributes attributes) { 1399 ASSERT(!GetHeap()->InNewSpace(function)); 1400 1401 // Allocate new instance descriptors with (name, function) added 1402 ConstantFunctionDescriptor d(name, function, attributes); 1403 Object* new_descriptors; 1404 { MaybeObject* maybe_new_descriptors = 1405 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS); 1406 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { 1407 return maybe_new_descriptors; 1408 } 1409 } 1410 1411 // Allocate a new map for the object. 1412 Object* new_map; 1413 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); 1414 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 1415 } 1416 1417 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors); 1418 Map::cast(new_map)->set_instance_descriptors(descriptors); 1419 Map* old_map = map(); 1420 set_map(Map::cast(new_map)); 1421 1422 // If the old map is the global object map (from new Object()), 1423 // then transitions are not added to it, so we are done. 1424 Heap* heap = old_map->heap(); 1425 if (old_map == heap->isolate()->context()->global_context()-> 1426 object_function()->map()) { 1427 return function; 1428 } 1429 1430 // Do not add CONSTANT_TRANSITIONS to global objects 1431 if (IsGlobalObject()) { 1432 return function; 1433 } 1434 1435 // Add a CONSTANT_TRANSITION descriptor to the old map, 1436 // so future assignments to this property on other objects 1437 // of the same type will create a normal field, not a constant function. 1438 // Don't do this for special properties, with non-trival attributes. 1439 if (attributes != NONE) { 1440 return function; 1441 } 1442 ConstTransitionDescriptor mark(name, Map::cast(new_map)); 1443 { MaybeObject* maybe_new_descriptors = 1444 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS); 1445 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { 1446 // We have accomplished the main goal, so return success. 1447 return function; 1448 } 1449 } 1450 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); 1451 1452 return function; 1453 } 1454 1455 1456 // Add property in slow mode 1457 MaybeObject* JSObject::AddSlowProperty(String* name, 1458 Object* value, 1459 PropertyAttributes attributes) { 1460 ASSERT(!HasFastProperties()); 1461 StringDictionary* dict = property_dictionary(); 1462 Object* store_value = value; 1463 if (IsGlobalObject()) { 1464 // In case name is an orphaned property reuse the cell. 1465 int entry = dict->FindEntry(name); 1466 if (entry != StringDictionary::kNotFound) { 1467 store_value = dict->ValueAt(entry); 1468 JSGlobalPropertyCell::cast(store_value)->set_value(value); 1469 // Assign an enumeration index to the property and update 1470 // SetNextEnumerationIndex. 1471 int index = dict->NextEnumerationIndex(); 1472 PropertyDetails details = PropertyDetails(attributes, NORMAL, index); 1473 dict->SetNextEnumerationIndex(index + 1); 1474 dict->SetEntry(entry, name, store_value, details); 1475 return value; 1476 } 1477 Heap* heap = GetHeap(); 1478 { MaybeObject* maybe_store_value = 1479 heap->AllocateJSGlobalPropertyCell(value); 1480 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value; 1481 } 1482 JSGlobalPropertyCell::cast(store_value)->set_value(value); 1483 } 1484 PropertyDetails details = PropertyDetails(attributes, NORMAL); 1485 Object* result; 1486 { MaybeObject* maybe_result = dict->Add(name, store_value, details); 1487 if (!maybe_result->ToObject(&result)) return maybe_result; 1488 } 1489 if (dict != result) set_properties(StringDictionary::cast(result)); 1490 return value; 1491 } 1492 1493 1494 MaybeObject* JSObject::AddProperty(String* name, 1495 Object* value, 1496 PropertyAttributes attributes, 1497 StrictModeFlag strict_mode) { 1498 ASSERT(!IsJSGlobalProxy()); 1499 Map* map_of_this = map(); 1500 Heap* heap = map_of_this->heap(); 1501 if (!map_of_this->is_extensible()) { 1502 if (strict_mode == kNonStrictMode) { 1503 return heap->undefined_value(); 1504 } else { 1505 Handle<Object> args[1] = {Handle<String>(name)}; 1506 return heap->isolate()->Throw( 1507 *FACTORY->NewTypeError("object_not_extensible", 1508 HandleVector(args, 1))); 1509 } 1510 } 1511 if (HasFastProperties()) { 1512 // Ensure the descriptor array does not get too big. 1513 if (map_of_this->instance_descriptors()->number_of_descriptors() < 1514 DescriptorArray::kMaxNumberOfDescriptors) { 1515 if (value->IsJSFunction() && !heap->InNewSpace(value)) { 1516 return AddConstantFunctionProperty(name, 1517 JSFunction::cast(value), 1518 attributes); 1519 } else { 1520 return AddFastProperty(name, value, attributes); 1521 } 1522 } else { 1523 // Normalize the object to prevent very large instance descriptors. 1524 // This eliminates unwanted N^2 allocation and lookup behavior. 1525 Object* obj; 1526 { MaybeObject* maybe_obj = 1527 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1528 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1529 } 1530 } 1531 } 1532 return AddSlowProperty(name, value, attributes); 1533 } 1534 1535 1536 MaybeObject* JSObject::SetPropertyPostInterceptor( 1537 String* name, 1538 Object* value, 1539 PropertyAttributes attributes, 1540 StrictModeFlag strict_mode) { 1541 // Check local property, ignore interceptor. 1542 LookupResult result; 1543 LocalLookupRealNamedProperty(name, &result); 1544 if (result.IsFound()) { 1545 // An existing property, a map transition or a null descriptor was 1546 // found. Use set property to handle all these cases. 1547 return SetProperty(&result, name, value, attributes, strict_mode); 1548 } 1549 // Add a new real property. 1550 return AddProperty(name, value, attributes, strict_mode); 1551 } 1552 1553 1554 MaybeObject* JSObject::ReplaceSlowProperty(String* name, 1555 Object* value, 1556 PropertyAttributes attributes) { 1557 StringDictionary* dictionary = property_dictionary(); 1558 int old_index = dictionary->FindEntry(name); 1559 int new_enumeration_index = 0; // 0 means "Use the next available index." 1560 if (old_index != -1) { 1561 // All calls to ReplaceSlowProperty have had all transitions removed. 1562 ASSERT(!dictionary->DetailsAt(old_index).IsTransition()); 1563 new_enumeration_index = dictionary->DetailsAt(old_index).index(); 1564 } 1565 1566 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); 1567 return SetNormalizedProperty(name, value, new_details); 1568 } 1569 1570 1571 MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition( 1572 String* name, 1573 Object* new_value, 1574 PropertyAttributes attributes) { 1575 Map* old_map = map(); 1576 Object* result; 1577 { MaybeObject* maybe_result = 1578 ConvertDescriptorToField(name, new_value, attributes); 1579 if (!maybe_result->ToObject(&result)) return maybe_result; 1580 } 1581 // If we get to this point we have succeeded - do not return failure 1582 // after this point. Later stuff is optional. 1583 if (!HasFastProperties()) { 1584 return result; 1585 } 1586 // Do not add transitions to the map of "new Object()". 1587 if (map() == old_map->heap()->isolate()->context()->global_context()-> 1588 object_function()->map()) { 1589 return result; 1590 } 1591 1592 MapTransitionDescriptor transition(name, 1593 map(), 1594 attributes); 1595 Object* new_descriptors; 1596 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()-> 1597 CopyInsert(&transition, KEEP_TRANSITIONS); 1598 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { 1599 return result; // Yes, return _result_. 1600 } 1601 } 1602 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); 1603 return result; 1604 } 1605 1606 1607 MaybeObject* JSObject::ConvertDescriptorToField(String* name, 1608 Object* new_value, 1609 PropertyAttributes attributes) { 1610 if (map()->unused_property_fields() == 0 && 1611 properties()->length() > MaxFastProperties()) { 1612 Object* obj; 1613 { MaybeObject* maybe_obj = 1614 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1615 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1616 } 1617 return ReplaceSlowProperty(name, new_value, attributes); 1618 } 1619 1620 int index = map()->NextFreePropertyIndex(); 1621 FieldDescriptor new_field(name, index, attributes); 1622 // Make a new DescriptorArray replacing an entry with FieldDescriptor. 1623 Object* descriptors_unchecked; 1624 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()-> 1625 CopyInsert(&new_field, REMOVE_TRANSITIONS); 1626 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) { 1627 return maybe_descriptors_unchecked; 1628 } 1629 } 1630 DescriptorArray* new_descriptors = 1631 DescriptorArray::cast(descriptors_unchecked); 1632 1633 // Make a new map for the object. 1634 Object* new_map_unchecked; 1635 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors(); 1636 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) { 1637 return maybe_new_map_unchecked; 1638 } 1639 } 1640 Map* new_map = Map::cast(new_map_unchecked); 1641 new_map->set_instance_descriptors(new_descriptors); 1642 1643 // Make new properties array if necessary. 1644 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer. 1645 int new_unused_property_fields = map()->unused_property_fields() - 1; 1646 if (map()->unused_property_fields() == 0) { 1647 new_unused_property_fields = kFieldsAdded - 1; 1648 Object* new_properties_object; 1649 { MaybeObject* maybe_new_properties_object = 1650 properties()->CopySize(properties()->length() + kFieldsAdded); 1651 if (!maybe_new_properties_object->ToObject(&new_properties_object)) { 1652 return maybe_new_properties_object; 1653 } 1654 } 1655 new_properties = FixedArray::cast(new_properties_object); 1656 } 1657 1658 // Update pointers to commit changes. 1659 // Object points to the new map. 1660 new_map->set_unused_property_fields(new_unused_property_fields); 1661 set_map(new_map); 1662 if (new_properties) { 1663 set_properties(FixedArray::cast(new_properties)); 1664 } 1665 return FastPropertyAtPut(index, new_value); 1666 } 1667 1668 1669 1670 MaybeObject* JSObject::SetPropertyWithInterceptor( 1671 String* name, 1672 Object* value, 1673 PropertyAttributes attributes, 1674 StrictModeFlag strict_mode) { 1675 Isolate* isolate = GetIsolate(); 1676 HandleScope scope(isolate); 1677 Handle<JSObject> this_handle(this); 1678 Handle<String> name_handle(name); 1679 Handle<Object> value_handle(value, isolate); 1680 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); 1681 if (!interceptor->setter()->IsUndefined()) { 1682 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name)); 1683 CustomArguments args(isolate, interceptor->data(), this, this); 1684 v8::AccessorInfo info(args.end()); 1685 v8::NamedPropertySetter setter = 1686 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter()); 1687 v8::Handle<v8::Value> result; 1688 { 1689 // Leaving JavaScript. 1690 VMState state(isolate, EXTERNAL); 1691 Handle<Object> value_unhole(value->IsTheHole() ? 1692 isolate->heap()->undefined_value() : 1693 value, 1694 isolate); 1695 result = setter(v8::Utils::ToLocal(name_handle), 1696 v8::Utils::ToLocal(value_unhole), 1697 info); 1698 } 1699 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1700 if (!result.IsEmpty()) return *value_handle; 1701 } 1702 MaybeObject* raw_result = 1703 this_handle->SetPropertyPostInterceptor(*name_handle, 1704 *value_handle, 1705 attributes, 1706 strict_mode); 1707 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1708 return raw_result; 1709 } 1710 1711 1712 MaybeObject* JSObject::SetProperty(String* name, 1713 Object* value, 1714 PropertyAttributes attributes, 1715 StrictModeFlag strict_mode) { 1716 LookupResult result; 1717 LocalLookup(name, &result); 1718 return SetProperty(&result, name, value, attributes, strict_mode); 1719 } 1720 1721 1722 MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, 1723 String* name, 1724 Object* value, 1725 JSObject* holder) { 1726 Isolate* isolate = GetIsolate(); 1727 HandleScope scope(isolate); 1728 1729 // We should never get here to initialize a const with the hole 1730 // value since a const declaration would conflict with the setter. 1731 ASSERT(!value->IsTheHole()); 1732 Handle<Object> value_handle(value, isolate); 1733 1734 // To accommodate both the old and the new api we switch on the 1735 // data structure used to store the callbacks. Eventually proxy 1736 // callbacks should be phased out. 1737 if (structure->IsProxy()) { 1738 AccessorDescriptor* callback = 1739 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy()); 1740 MaybeObject* obj = (callback->setter)(this, value, callback->data); 1741 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1742 if (obj->IsFailure()) return obj; 1743 return *value_handle; 1744 } 1745 1746 if (structure->IsAccessorInfo()) { 1747 // api style callbacks 1748 AccessorInfo* data = AccessorInfo::cast(structure); 1749 Object* call_obj = data->setter(); 1750 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj); 1751 if (call_fun == NULL) return value; 1752 Handle<String> key(name); 1753 LOG(isolate, ApiNamedPropertyAccess("store", this, name)); 1754 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder)); 1755 v8::AccessorInfo info(args.end()); 1756 { 1757 // Leaving JavaScript. 1758 VMState state(isolate, EXTERNAL); 1759 call_fun(v8::Utils::ToLocal(key), 1760 v8::Utils::ToLocal(value_handle), 1761 info); 1762 } 1763 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1764 return *value_handle; 1765 } 1766 1767 if (structure->IsFixedArray()) { 1768 Object* setter = FixedArray::cast(structure)->get(kSetterIndex); 1769 if (setter->IsJSFunction()) { 1770 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); 1771 } else { 1772 Handle<String> key(name); 1773 Handle<Object> holder_handle(holder, isolate); 1774 Handle<Object> args[2] = { key, holder_handle }; 1775 return isolate->Throw( 1776 *isolate->factory()->NewTypeError("no_setter_in_callback", 1777 HandleVector(args, 2))); 1778 } 1779 } 1780 1781 UNREACHABLE(); 1782 return NULL; 1783 } 1784 1785 1786 MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter, 1787 Object* value) { 1788 Isolate* isolate = GetIsolate(); 1789 Handle<Object> value_handle(value, isolate); 1790 Handle<JSFunction> fun(JSFunction::cast(setter), isolate); 1791 Handle<JSObject> self(this, isolate); 1792 #ifdef ENABLE_DEBUGGER_SUPPORT 1793 Debug* debug = isolate->debug(); 1794 // Handle stepping into a setter if step into is active. 1795 if (debug->StepInActive()) { 1796 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false); 1797 } 1798 #endif 1799 bool has_pending_exception; 1800 Object** argv[] = { value_handle.location() }; 1801 Execution::Call(fun, self, 1, argv, &has_pending_exception); 1802 // Check for pending exception and return the result. 1803 if (has_pending_exception) return Failure::Exception(); 1804 return *value_handle; 1805 } 1806 1807 1808 void JSObject::LookupCallbackSetterInPrototypes(String* name, 1809 LookupResult* result) { 1810 Heap* heap = GetHeap(); 1811 for (Object* pt = GetPrototype(); 1812 pt != heap->null_value(); 1813 pt = pt->GetPrototype()) { 1814 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); 1815 if (result->IsProperty()) { 1816 if (result->type() == CALLBACKS && !result->IsReadOnly()) return; 1817 // Found non-callback or read-only callback, stop looking. 1818 break; 1819 } 1820 } 1821 result->NotFound(); 1822 } 1823 1824 1825 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index, 1826 Object* value, 1827 bool* found) { 1828 Heap* heap = GetHeap(); 1829 for (Object* pt = GetPrototype(); 1830 pt != heap->null_value(); 1831 pt = pt->GetPrototype()) { 1832 if (!JSObject::cast(pt)->HasDictionaryElements()) { 1833 continue; 1834 } 1835 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); 1836 int entry = dictionary->FindEntry(index); 1837 if (entry != NumberDictionary::kNotFound) { 1838 PropertyDetails details = dictionary->DetailsAt(entry); 1839 if (details.type() == CALLBACKS) { 1840 *found = true; 1841 return SetElementWithCallback( 1842 dictionary->ValueAt(entry), index, value, JSObject::cast(pt)); 1843 } 1844 } 1845 } 1846 *found = false; 1847 return heap->the_hole_value(); 1848 } 1849 1850 1851 void JSObject::LookupInDescriptor(String* name, LookupResult* result) { 1852 DescriptorArray* descriptors = map()->instance_descriptors(); 1853 int number = descriptors->SearchWithCache(name); 1854 if (number != DescriptorArray::kNotFound) { 1855 result->DescriptorResult(this, descriptors->GetDetails(number), number); 1856 } else { 1857 result->NotFound(); 1858 } 1859 } 1860 1861 1862 void Map::LookupInDescriptors(JSObject* holder, 1863 String* name, 1864 LookupResult* result) { 1865 DescriptorArray* descriptors = instance_descriptors(); 1866 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache(); 1867 int number = cache->Lookup(descriptors, name); 1868 if (number == DescriptorLookupCache::kAbsent) { 1869 number = descriptors->Search(name); 1870 cache->Update(descriptors, name, number); 1871 } 1872 if (number != DescriptorArray::kNotFound) { 1873 result->DescriptorResult(holder, descriptors->GetDetails(number), number); 1874 } else { 1875 result->NotFound(); 1876 } 1877 } 1878 1879 1880 MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type, 1881 bool safe_to_add_transition) { 1882 Heap* current_heap = heap(); 1883 DescriptorArray* descriptors = instance_descriptors(); 1884 String* external_array_sentinel_name = current_heap->empty_symbol(); 1885 1886 if (safe_to_add_transition) { 1887 // It's only safe to manipulate the descriptor array if it would be 1888 // safe to add a transition. 1889 1890 ASSERT(!is_shared()); // no transitions can be added to shared maps. 1891 // Check if the external array transition already exists. 1892 DescriptorLookupCache* cache = 1893 current_heap->isolate()->descriptor_lookup_cache(); 1894 int index = cache->Lookup(descriptors, external_array_sentinel_name); 1895 if (index == DescriptorLookupCache::kAbsent) { 1896 index = descriptors->Search(external_array_sentinel_name); 1897 cache->Update(descriptors, 1898 external_array_sentinel_name, 1899 index); 1900 } 1901 1902 // If the transition already exists, check the type. If there is a match, 1903 // return it. 1904 if (index != DescriptorArray::kNotFound) { 1905 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index))); 1906 if (details.type() == EXTERNAL_ARRAY_TRANSITION && 1907 details.array_type() == array_type) { 1908 return descriptors->GetValue(index); 1909 } else { 1910 safe_to_add_transition = false; 1911 } 1912 } 1913 } 1914 1915 // No transition to an existing external array map. Make a new one. 1916 Object* obj; 1917 { MaybeObject* maybe_map = CopyDropTransitions(); 1918 if (!maybe_map->ToObject(&obj)) return maybe_map; 1919 } 1920 Map* new_map = Map::cast(obj); 1921 1922 new_map->set_has_fast_elements(false); 1923 new_map->set_has_external_array_elements(true); 1924 GetIsolate()->counters()->map_to_external_array_elements()->Increment(); 1925 1926 // Only remember the map transition if the object's map is NOT equal to the 1927 // global object_function's map and there is not an already existing 1928 // non-matching external array transition. 1929 bool allow_map_transition = 1930 safe_to_add_transition && 1931 (GetIsolate()->context()->global_context()->object_function()->map() != 1932 map()); 1933 if (allow_map_transition) { 1934 // Allocate new instance descriptors for the old map with map transition. 1935 ExternalArrayTransitionDescriptor desc(external_array_sentinel_name, 1936 Map::cast(new_map), 1937 array_type); 1938 Object* new_descriptors; 1939 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert( 1940 &desc, 1941 KEEP_TRANSITIONS); 1942 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { 1943 return maybe_new_descriptors; 1944 } 1945 descriptors = DescriptorArray::cast(new_descriptors); 1946 set_instance_descriptors(descriptors); 1947 } 1948 1949 return new_map; 1950 } 1951 1952 1953 void JSObject::LocalLookupRealNamedProperty(String* name, 1954 LookupResult* result) { 1955 if (IsJSGlobalProxy()) { 1956 Object* proto = GetPrototype(); 1957 if (proto->IsNull()) return result->NotFound(); 1958 ASSERT(proto->IsJSGlobalObject()); 1959 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result); 1960 } 1961 1962 if (HasFastProperties()) { 1963 LookupInDescriptor(name, result); 1964 if (result->IsFound()) { 1965 // A property, a map transition or a null descriptor was found. 1966 // We return all of these result types because 1967 // LocalLookupRealNamedProperty is used when setting properties 1968 // where map transitions and null descriptors are handled. 1969 ASSERT(result->holder() == this && result->type() != NORMAL); 1970 // Disallow caching for uninitialized constants. These can only 1971 // occur as fields. 1972 if (result->IsReadOnly() && result->type() == FIELD && 1973 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) { 1974 result->DisallowCaching(); 1975 } 1976 return; 1977 } 1978 } else { 1979 int entry = property_dictionary()->FindEntry(name); 1980 if (entry != StringDictionary::kNotFound) { 1981 Object* value = property_dictionary()->ValueAt(entry); 1982 if (IsGlobalObject()) { 1983 PropertyDetails d = property_dictionary()->DetailsAt(entry); 1984 if (d.IsDeleted()) { 1985 result->NotFound(); 1986 return; 1987 } 1988 value = JSGlobalPropertyCell::cast(value)->value(); 1989 } 1990 // Make sure to disallow caching for uninitialized constants 1991 // found in the dictionary-mode objects. 1992 if (value->IsTheHole()) result->DisallowCaching(); 1993 result->DictionaryResult(this, entry); 1994 return; 1995 } 1996 } 1997 result->NotFound(); 1998 } 1999 2000 2001 void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) { 2002 LocalLookupRealNamedProperty(name, result); 2003 if (result->IsProperty()) return; 2004 2005 LookupRealNamedPropertyInPrototypes(name, result); 2006 } 2007 2008 2009 void JSObject::LookupRealNamedPropertyInPrototypes(String* name, 2010 LookupResult* result) { 2011 Heap* heap = GetHeap(); 2012 for (Object* pt = GetPrototype(); 2013 pt != heap->null_value(); 2014 pt = JSObject::cast(pt)->GetPrototype()) { 2015 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); 2016 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return; 2017 } 2018 result->NotFound(); 2019 } 2020 2021 2022 // We only need to deal with CALLBACKS and INTERCEPTORS 2023 MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result, 2024 String* name, 2025 Object* value, 2026 bool check_prototype) { 2027 if (check_prototype && !result->IsProperty()) { 2028 LookupCallbackSetterInPrototypes(name, result); 2029 } 2030 2031 if (result->IsProperty()) { 2032 if (!result->IsReadOnly()) { 2033 switch (result->type()) { 2034 case CALLBACKS: { 2035 Object* obj = result->GetCallbackObject(); 2036 if (obj->IsAccessorInfo()) { 2037 AccessorInfo* info = AccessorInfo::cast(obj); 2038 if (info->all_can_write()) { 2039 return SetPropertyWithCallback(result->GetCallbackObject(), 2040 name, 2041 value, 2042 result->holder()); 2043 } 2044 } 2045 break; 2046 } 2047 case INTERCEPTOR: { 2048 // Try lookup real named properties. Note that only property can be 2049 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain. 2050 LookupResult r; 2051 LookupRealNamedProperty(name, &r); 2052 if (r.IsProperty()) { 2053 return SetPropertyWithFailedAccessCheck(&r, name, value, 2054 check_prototype); 2055 } 2056 break; 2057 } 2058 default: { 2059 break; 2060 } 2061 } 2062 } 2063 } 2064 2065 HandleScope scope; 2066 Handle<Object> value_handle(value); 2067 Heap* heap = GetHeap(); 2068 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); 2069 return *value_handle; 2070 } 2071 2072 2073 MaybeObject* JSObject::SetProperty(LookupResult* result, 2074 String* name, 2075 Object* value, 2076 PropertyAttributes attributes, 2077 StrictModeFlag strict_mode) { 2078 Heap* heap = GetHeap(); 2079 // Make sure that the top context does not change when doing callbacks or 2080 // interceptor calls. 2081 AssertNoContextChange ncc; 2082 2083 // Optimization for 2-byte strings often used as keys in a decompression 2084 // dictionary. We make these short keys into symbols to avoid constantly 2085 // reallocating them. 2086 if (!name->IsSymbol() && name->length() <= 2) { 2087 Object* symbol_version; 2088 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name); 2089 if (maybe_symbol_version->ToObject(&symbol_version)) { 2090 name = String::cast(symbol_version); 2091 } 2092 } 2093 } 2094 2095 // Check access rights if needed. 2096 if (IsAccessCheckNeeded() 2097 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) { 2098 return SetPropertyWithFailedAccessCheck(result, name, value, true); 2099 } 2100 2101 if (IsJSGlobalProxy()) { 2102 Object* proto = GetPrototype(); 2103 if (proto->IsNull()) return value; 2104 ASSERT(proto->IsJSGlobalObject()); 2105 return JSObject::cast(proto)->SetProperty( 2106 result, name, value, attributes, strict_mode); 2107 } 2108 2109 if (!result->IsProperty() && !IsJSContextExtensionObject()) { 2110 // We could not find a local property so let's check whether there is an 2111 // accessor that wants to handle the property. 2112 LookupResult accessor_result; 2113 LookupCallbackSetterInPrototypes(name, &accessor_result); 2114 if (accessor_result.IsProperty()) { 2115 return SetPropertyWithCallback(accessor_result.GetCallbackObject(), 2116 name, 2117 value, 2118 accessor_result.holder()); 2119 } 2120 } 2121 if (!result->IsFound()) { 2122 // Neither properties nor transitions found. 2123 return AddProperty(name, value, attributes, strict_mode); 2124 } 2125 if (result->IsReadOnly() && result->IsProperty()) { 2126 if (strict_mode == kStrictMode) { 2127 HandleScope scope; 2128 Handle<String> key(name); 2129 Handle<Object> holder(this); 2130 Handle<Object> args[2] = { key, holder }; 2131 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( 2132 "strict_read_only_property", HandleVector(args, 2))); 2133 } else { 2134 return value; 2135 } 2136 } 2137 // This is a real property that is not read-only, or it is a 2138 // transition or null descriptor and there are no setters in the prototypes. 2139 switch (result->type()) { 2140 case NORMAL: 2141 return SetNormalizedProperty(result, value); 2142 case FIELD: 2143 return FastPropertyAtPut(result->GetFieldIndex(), value); 2144 case MAP_TRANSITION: 2145 if (attributes == result->GetAttributes()) { 2146 // Only use map transition if the attributes match. 2147 return AddFastPropertyUsingMap(result->GetTransitionMap(), 2148 name, 2149 value); 2150 } 2151 return ConvertDescriptorToField(name, value, attributes); 2152 case CONSTANT_FUNCTION: 2153 // Only replace the function if necessary. 2154 if (value == result->GetConstantFunction()) return value; 2155 // Preserve the attributes of this existing property. 2156 attributes = result->GetAttributes(); 2157 return ConvertDescriptorToField(name, value, attributes); 2158 case CALLBACKS: 2159 return SetPropertyWithCallback(result->GetCallbackObject(), 2160 name, 2161 value, 2162 result->holder()); 2163 case INTERCEPTOR: 2164 return SetPropertyWithInterceptor(name, value, attributes, strict_mode); 2165 case CONSTANT_TRANSITION: { 2166 // If the same constant function is being added we can simply 2167 // transition to the target map. 2168 Map* target_map = result->GetTransitionMap(); 2169 DescriptorArray* target_descriptors = target_map->instance_descriptors(); 2170 int number = target_descriptors->SearchWithCache(name); 2171 ASSERT(number != DescriptorArray::kNotFound); 2172 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION); 2173 JSFunction* function = 2174 JSFunction::cast(target_descriptors->GetValue(number)); 2175 ASSERT(!HEAP->InNewSpace(function)); 2176 if (value == function) { 2177 set_map(target_map); 2178 return value; 2179 } 2180 // Otherwise, replace with a MAP_TRANSITION to a new map with a 2181 // FIELD, even if the value is a constant function. 2182 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 2183 } 2184 case NULL_DESCRIPTOR: 2185 case EXTERNAL_ARRAY_TRANSITION: 2186 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 2187 default: 2188 UNREACHABLE(); 2189 } 2190 UNREACHABLE(); 2191 return value; 2192 } 2193 2194 2195 // Set a real local property, even if it is READ_ONLY. If the property is not 2196 // present, add it with attributes NONE. This code is an exact clone of 2197 // SetProperty, with the check for IsReadOnly and the check for a 2198 // callback setter removed. The two lines looking up the LookupResult 2199 // result are also added. If one of the functions is changed, the other 2200 // should be. 2201 MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( 2202 String* name, 2203 Object* value, 2204 PropertyAttributes attributes) { 2205 2206 // Make sure that the top context does not change when doing callbacks or 2207 // interceptor calls. 2208 AssertNoContextChange ncc; 2209 LookupResult result; 2210 LocalLookup(name, &result); 2211 // Check access rights if needed. 2212 if (IsAccessCheckNeeded()) { 2213 Heap* heap = GetHeap(); 2214 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) { 2215 return SetPropertyWithFailedAccessCheck(&result, name, value, false); 2216 } 2217 } 2218 2219 if (IsJSGlobalProxy()) { 2220 Object* proto = GetPrototype(); 2221 if (proto->IsNull()) return value; 2222 ASSERT(proto->IsJSGlobalObject()); 2223 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( 2224 name, 2225 value, 2226 attributes); 2227 } 2228 2229 // Check for accessor in prototype chain removed here in clone. 2230 if (!result.IsFound()) { 2231 // Neither properties nor transitions found. 2232 return AddProperty(name, value, attributes, kNonStrictMode); 2233 } 2234 2235 PropertyDetails details = PropertyDetails(attributes, NORMAL); 2236 2237 // Check of IsReadOnly removed from here in clone. 2238 switch (result.type()) { 2239 case NORMAL: 2240 return SetNormalizedProperty(name, value, details); 2241 case FIELD: 2242 return FastPropertyAtPut(result.GetFieldIndex(), value); 2243 case MAP_TRANSITION: 2244 if (attributes == result.GetAttributes()) { 2245 // Only use map transition if the attributes match. 2246 return AddFastPropertyUsingMap(result.GetTransitionMap(), 2247 name, 2248 value); 2249 } 2250 return ConvertDescriptorToField(name, value, attributes); 2251 case CONSTANT_FUNCTION: 2252 // Only replace the function if necessary. 2253 if (value == result.GetConstantFunction()) return value; 2254 // Preserve the attributes of this existing property. 2255 attributes = result.GetAttributes(); 2256 return ConvertDescriptorToField(name, value, attributes); 2257 case CALLBACKS: 2258 case INTERCEPTOR: 2259 // Override callback in clone 2260 return ConvertDescriptorToField(name, value, attributes); 2261 case CONSTANT_TRANSITION: 2262 // Replace with a MAP_TRANSITION to a new map with a FIELD, even 2263 // if the value is a function. 2264 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 2265 case NULL_DESCRIPTOR: 2266 case EXTERNAL_ARRAY_TRANSITION: 2267 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 2268 default: 2269 UNREACHABLE(); 2270 } 2271 UNREACHABLE(); 2272 return value; 2273 } 2274 2275 2276 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( 2277 JSObject* receiver, 2278 String* name, 2279 bool continue_search) { 2280 // Check local property, ignore interceptor. 2281 LookupResult result; 2282 LocalLookupRealNamedProperty(name, &result); 2283 if (result.IsProperty()) return result.GetAttributes(); 2284 2285 if (continue_search) { 2286 // Continue searching via the prototype chain. 2287 Object* pt = GetPrototype(); 2288 if (!pt->IsNull()) { 2289 return JSObject::cast(pt)-> 2290 GetPropertyAttributeWithReceiver(receiver, name); 2291 } 2292 } 2293 return ABSENT; 2294 } 2295 2296 2297 PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor( 2298 JSObject* receiver, 2299 String* name, 2300 bool continue_search) { 2301 Isolate* isolate = GetIsolate(); 2302 2303 // Make sure that the top context does not change when doing 2304 // callbacks or interceptor calls. 2305 AssertNoContextChange ncc; 2306 2307 HandleScope scope(isolate); 2308 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); 2309 Handle<JSObject> receiver_handle(receiver); 2310 Handle<JSObject> holder_handle(this); 2311 Handle<String> name_handle(name); 2312 CustomArguments args(isolate, interceptor->data(), receiver, this); 2313 v8::AccessorInfo info(args.end()); 2314 if (!interceptor->query()->IsUndefined()) { 2315 v8::NamedPropertyQuery query = 2316 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query()); 2317 LOG(isolate, 2318 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name)); 2319 v8::Handle<v8::Integer> result; 2320 { 2321 // Leaving JavaScript. 2322 VMState state(isolate, EXTERNAL); 2323 result = query(v8::Utils::ToLocal(name_handle), info); 2324 } 2325 if (!result.IsEmpty()) { 2326 ASSERT(result->IsInt32()); 2327 return static_cast<PropertyAttributes>(result->Int32Value()); 2328 } 2329 } else if (!interceptor->getter()->IsUndefined()) { 2330 v8::NamedPropertyGetter getter = 2331 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); 2332 LOG(isolate, 2333 ApiNamedPropertyAccess("interceptor-named-get-has", this, name)); 2334 v8::Handle<v8::Value> result; 2335 { 2336 // Leaving JavaScript. 2337 VMState state(isolate, EXTERNAL); 2338 result = getter(v8::Utils::ToLocal(name_handle), info); 2339 } 2340 if (!result.IsEmpty()) return DONT_ENUM; 2341 } 2342 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle, 2343 *name_handle, 2344 continue_search); 2345 } 2346 2347 2348 PropertyAttributes JSObject::GetPropertyAttributeWithReceiver( 2349 JSObject* receiver, 2350 String* key) { 2351 uint32_t index = 0; 2352 if (key->AsArrayIndex(&index)) { 2353 if (HasElementWithReceiver(receiver, index)) return NONE; 2354 return ABSENT; 2355 } 2356 // Named property. 2357 LookupResult result; 2358 Lookup(key, &result); 2359 return GetPropertyAttribute(receiver, &result, key, true); 2360 } 2361 2362 2363 PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver, 2364 LookupResult* result, 2365 String* name, 2366 bool continue_search) { 2367 // Check access rights if needed. 2368 if (IsAccessCheckNeeded()) { 2369 Heap* heap = GetHeap(); 2370 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) { 2371 return GetPropertyAttributeWithFailedAccessCheck(receiver, 2372 result, 2373 name, 2374 continue_search); 2375 } 2376 } 2377 if (result->IsProperty()) { 2378 switch (result->type()) { 2379 case NORMAL: // fall through 2380 case FIELD: 2381 case CONSTANT_FUNCTION: 2382 case CALLBACKS: 2383 return result->GetAttributes(); 2384 case INTERCEPTOR: 2385 return result->holder()-> 2386 GetPropertyAttributeWithInterceptor(receiver, name, continue_search); 2387 default: 2388 UNREACHABLE(); 2389 } 2390 } 2391 return ABSENT; 2392 } 2393 2394 2395 PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) { 2396 // Check whether the name is an array index. 2397 uint32_t index = 0; 2398 if (name->AsArrayIndex(&index)) { 2399 if (HasLocalElement(index)) return NONE; 2400 return ABSENT; 2401 } 2402 // Named property. 2403 LookupResult result; 2404 LocalLookup(name, &result); 2405 return GetPropertyAttribute(this, &result, name, false); 2406 } 2407 2408 2409 MaybeObject* NormalizedMapCache::Get(JSObject* obj, 2410 PropertyNormalizationMode mode) { 2411 Isolate* isolate = obj->GetIsolate(); 2412 Map* fast = obj->map(); 2413 int index = Hash(fast) % kEntries; 2414 Object* result = get(index); 2415 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) { 2416 #ifdef DEBUG 2417 if (FLAG_enable_slow_asserts) { 2418 // The cached map should match newly created normalized map bit-by-bit. 2419 Object* fresh; 2420 { MaybeObject* maybe_fresh = 2421 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); 2422 if (maybe_fresh->ToObject(&fresh)) { 2423 ASSERT(memcmp(Map::cast(fresh)->address(), 2424 Map::cast(result)->address(), 2425 Map::kSize) == 0); 2426 } 2427 } 2428 } 2429 #endif 2430 return result; 2431 } 2432 2433 { MaybeObject* maybe_result = 2434 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); 2435 if (!maybe_result->ToObject(&result)) return maybe_result; 2436 } 2437 set(index, result); 2438 isolate->counters()->normalized_maps()->Increment(); 2439 2440 return result; 2441 } 2442 2443 2444 void NormalizedMapCache::Clear() { 2445 int entries = length(); 2446 for (int i = 0; i != entries; i++) { 2447 set_undefined(i); 2448 } 2449 } 2450 2451 2452 int NormalizedMapCache::Hash(Map* fast) { 2453 // For performance reasons we only hash the 3 most variable fields of a map: 2454 // constructor, prototype and bit_field2. 2455 2456 // Shift away the tag. 2457 int hash = (static_cast<uint32_t>( 2458 reinterpret_cast<uintptr_t>(fast->constructor())) >> 2); 2459 2460 // XOR-ing the prototype and constructor directly yields too many zero bits 2461 // when the two pointers are close (which is fairly common). 2462 // To avoid this we shift the prototype 4 bits relatively to the constructor. 2463 hash ^= (static_cast<uint32_t>( 2464 reinterpret_cast<uintptr_t>(fast->prototype())) << 2); 2465 2466 return hash ^ (hash >> 16) ^ fast->bit_field2(); 2467 } 2468 2469 2470 bool NormalizedMapCache::CheckHit(Map* slow, 2471 Map* fast, 2472 PropertyNormalizationMode mode) { 2473 #ifdef DEBUG 2474 slow->SharedMapVerify(); 2475 #endif 2476 return 2477 slow->constructor() == fast->constructor() && 2478 slow->prototype() == fast->prototype() && 2479 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? 2480 0 : 2481 fast->inobject_properties()) && 2482 slow->instance_type() == fast->instance_type() && 2483 slow->bit_field() == fast->bit_field() && 2484 (slow->bit_field2() & ~(1<<Map::kIsShared)) == fast->bit_field2(); 2485 } 2486 2487 2488 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) { 2489 if (map()->is_shared()) { 2490 // Fast case maps are never marked as shared. 2491 ASSERT(!HasFastProperties()); 2492 // Replace the map with an identical copy that can be safely modified. 2493 Object* obj; 2494 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, 2495 UNIQUE_NORMALIZED_MAP); 2496 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2497 } 2498 GetIsolate()->counters()->normalized_maps()->Increment(); 2499 2500 set_map(Map::cast(obj)); 2501 } 2502 return map()->UpdateCodeCache(name, code); 2503 } 2504 2505 2506 MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, 2507 int expected_additional_properties) { 2508 if (!HasFastProperties()) return this; 2509 2510 // The global object is always normalized. 2511 ASSERT(!IsGlobalObject()); 2512 // JSGlobalProxy must never be normalized 2513 ASSERT(!IsJSGlobalProxy()); 2514 2515 Map* map_of_this = map(); 2516 2517 // Allocate new content. 2518 int property_count = map_of_this->NumberOfDescribedProperties(); 2519 if (expected_additional_properties > 0) { 2520 property_count += expected_additional_properties; 2521 } else { 2522 property_count += 2; // Make space for two more properties. 2523 } 2524 Object* obj; 2525 { MaybeObject* maybe_obj = 2526 StringDictionary::Allocate(property_count); 2527 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2528 } 2529 StringDictionary* dictionary = StringDictionary::cast(obj); 2530 2531 DescriptorArray* descs = map_of_this->instance_descriptors(); 2532 for (int i = 0; i < descs->number_of_descriptors(); i++) { 2533 PropertyDetails details(descs->GetDetails(i)); 2534 switch (details.type()) { 2535 case CONSTANT_FUNCTION: { 2536 PropertyDetails d = 2537 PropertyDetails(details.attributes(), NORMAL, details.index()); 2538 Object* value = descs->GetConstantFunction(i); 2539 Object* result; 2540 { MaybeObject* maybe_result = 2541 dictionary->Add(descs->GetKey(i), value, d); 2542 if (!maybe_result->ToObject(&result)) return maybe_result; 2543 } 2544 dictionary = StringDictionary::cast(result); 2545 break; 2546 } 2547 case FIELD: { 2548 PropertyDetails d = 2549 PropertyDetails(details.attributes(), NORMAL, details.index()); 2550 Object* value = FastPropertyAt(descs->GetFieldIndex(i)); 2551 Object* result; 2552 { MaybeObject* maybe_result = 2553 dictionary->Add(descs->GetKey(i), value, d); 2554 if (!maybe_result->ToObject(&result)) return maybe_result; 2555 } 2556 dictionary = StringDictionary::cast(result); 2557 break; 2558 } 2559 case CALLBACKS: { 2560 PropertyDetails d = 2561 PropertyDetails(details.attributes(), CALLBACKS, details.index()); 2562 Object* value = descs->GetCallbacksObject(i); 2563 Object* result; 2564 { MaybeObject* maybe_result = 2565 dictionary->Add(descs->GetKey(i), value, d); 2566 if (!maybe_result->ToObject(&result)) return maybe_result; 2567 } 2568 dictionary = StringDictionary::cast(result); 2569 break; 2570 } 2571 case MAP_TRANSITION: 2572 case CONSTANT_TRANSITION: 2573 case NULL_DESCRIPTOR: 2574 case INTERCEPTOR: 2575 break; 2576 default: 2577 UNREACHABLE(); 2578 } 2579 } 2580 2581 Heap* current_heap = map_of_this->heap(); 2582 2583 // Copy the next enumeration index from instance descriptor. 2584 int index = map_of_this->instance_descriptors()->NextEnumerationIndex(); 2585 dictionary->SetNextEnumerationIndex(index); 2586 2587 { MaybeObject* maybe_obj = 2588 current_heap->isolate()->context()->global_context()-> 2589 normalized_map_cache()->Get(this, mode); 2590 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2591 } 2592 Map* new_map = Map::cast(obj); 2593 2594 // We have now successfully allocated all the necessary objects. 2595 // Changes can now be made with the guarantee that all of them take effect. 2596 2597 // Resize the object in the heap if necessary. 2598 int new_instance_size = new_map->instance_size(); 2599 int instance_size_delta = map_of_this->instance_size() - new_instance_size; 2600 ASSERT(instance_size_delta >= 0); 2601 current_heap->CreateFillerObjectAt(this->address() + new_instance_size, 2602 instance_size_delta); 2603 2604 set_map(new_map); 2605 new_map->set_instance_descriptors(current_heap->empty_descriptor_array()); 2606 2607 set_properties(dictionary); 2608 2609 current_heap->isolate()->counters()->props_to_dictionary()->Increment(); 2610 2611 #ifdef DEBUG 2612 if (FLAG_trace_normalization) { 2613 PrintF("Object properties have been normalized:\n"); 2614 Print(); 2615 } 2616 #endif 2617 return this; 2618 } 2619 2620 2621 MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) { 2622 if (HasFastProperties()) return this; 2623 ASSERT(!IsGlobalObject()); 2624 return property_dictionary()-> 2625 TransformPropertiesToFastFor(this, unused_property_fields); 2626 } 2627 2628 2629 MaybeObject* JSObject::NormalizeElements() { 2630 ASSERT(!HasExternalArrayElements()); 2631 if (HasDictionaryElements()) return this; 2632 Map* old_map = map(); 2633 ASSERT(old_map->has_fast_elements()); 2634 2635 Object* obj; 2636 { MaybeObject* maybe_obj = old_map->GetSlowElementsMap(); 2637 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2638 } 2639 Map* new_map = Map::cast(obj); 2640 2641 // Get number of entries. 2642 FixedArray* array = FixedArray::cast(elements()); 2643 2644 // Compute the effective length. 2645 int length = IsJSArray() ? 2646 Smi::cast(JSArray::cast(this)->length())->value() : 2647 array->length(); 2648 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length); 2649 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2650 } 2651 NumberDictionary* dictionary = NumberDictionary::cast(obj); 2652 // Copy entries. 2653 for (int i = 0; i < length; i++) { 2654 Object* value = array->get(i); 2655 if (!value->IsTheHole()) { 2656 PropertyDetails details = PropertyDetails(NONE, NORMAL); 2657 Object* result; 2658 { MaybeObject* maybe_result = 2659 dictionary->AddNumberEntry(i, array->get(i), details); 2660 if (!maybe_result->ToObject(&result)) return maybe_result; 2661 } 2662 dictionary = NumberDictionary::cast(result); 2663 } 2664 } 2665 // Switch to using the dictionary as the backing storage for 2666 // elements. Set the new map first to satify the elements type 2667 // assert in set_elements(). 2668 set_map(new_map); 2669 set_elements(dictionary); 2670 2671 new_map->heap()->isolate()->counters()->elements_to_dictionary()-> 2672 Increment(); 2673 2674 #ifdef DEBUG 2675 if (FLAG_trace_normalization) { 2676 PrintF("Object elements have been normalized:\n"); 2677 Print(); 2678 } 2679 #endif 2680 2681 return this; 2682 } 2683 2684 2685 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, 2686 DeleteMode mode) { 2687 // Check local property, ignore interceptor. 2688 LookupResult result; 2689 LocalLookupRealNamedProperty(name, &result); 2690 if (!result.IsProperty()) return GetHeap()->true_value(); 2691 2692 // Normalize object if needed. 2693 Object* obj; 2694 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 2695 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2696 } 2697 2698 return DeleteNormalizedProperty(name, mode); 2699 } 2700 2701 2702 MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) { 2703 Isolate* isolate = GetIsolate(); 2704 HandleScope scope(isolate); 2705 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); 2706 Handle<String> name_handle(name); 2707 Handle<JSObject> this_handle(this); 2708 if (!interceptor->deleter()->IsUndefined()) { 2709 v8::NamedPropertyDeleter deleter = 2710 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter()); 2711 LOG(isolate, 2712 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name)); 2713 CustomArguments args(isolate, interceptor->data(), this, this); 2714 v8::AccessorInfo info(args.end()); 2715 v8::Handle<v8::Boolean> result; 2716 { 2717 // Leaving JavaScript. 2718 VMState state(isolate, EXTERNAL); 2719 result = deleter(v8::Utils::ToLocal(name_handle), info); 2720 } 2721 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 2722 if (!result.IsEmpty()) { 2723 ASSERT(result->IsBoolean()); 2724 return *v8::Utils::OpenHandle(*result); 2725 } 2726 } 2727 MaybeObject* raw_result = 2728 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); 2729 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 2730 return raw_result; 2731 } 2732 2733 2734 MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index, 2735 DeleteMode mode) { 2736 ASSERT(!HasExternalArrayElements()); 2737 switch (GetElementsKind()) { 2738 case FAST_ELEMENTS: { 2739 Object* obj; 2740 { MaybeObject* maybe_obj = EnsureWritableFastElements(); 2741 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2742 } 2743 uint32_t length = IsJSArray() ? 2744 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : 2745 static_cast<uint32_t>(FixedArray::cast(elements())->length()); 2746 if (index < length) { 2747 FixedArray::cast(elements())->set_the_hole(index); 2748 } 2749 break; 2750 } 2751 case DICTIONARY_ELEMENTS: { 2752 NumberDictionary* dictionary = element_dictionary(); 2753 int entry = dictionary->FindEntry(index); 2754 if (entry != NumberDictionary::kNotFound) { 2755 return dictionary->DeleteProperty(entry, mode); 2756 } 2757 break; 2758 } 2759 default: 2760 UNREACHABLE(); 2761 break; 2762 } 2763 return GetHeap()->true_value(); 2764 } 2765 2766 2767 MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) { 2768 Isolate* isolate = GetIsolate(); 2769 Heap* heap = isolate->heap(); 2770 // Make sure that the top context does not change when doing 2771 // callbacks or interceptor calls. 2772 AssertNoContextChange ncc; 2773 HandleScope scope(isolate); 2774 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); 2775 if (interceptor->deleter()->IsUndefined()) return heap->false_value(); 2776 v8::IndexedPropertyDeleter deleter = 2777 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter()); 2778 Handle<JSObject> this_handle(this); 2779 LOG(isolate, 2780 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index)); 2781 CustomArguments args(isolate, interceptor->data(), this, this); 2782 v8::AccessorInfo info(args.end()); 2783 v8::Handle<v8::Boolean> result; 2784 { 2785 // Leaving JavaScript. 2786 VMState state(isolate, EXTERNAL); 2787 result = deleter(index, info); 2788 } 2789 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 2790 if (!result.IsEmpty()) { 2791 ASSERT(result->IsBoolean()); 2792 return *v8::Utils::OpenHandle(*result); 2793 } 2794 MaybeObject* raw_result = 2795 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); 2796 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 2797 return raw_result; 2798 } 2799 2800 2801 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { 2802 Isolate* isolate = GetIsolate(); 2803 // Check access rights if needed. 2804 if (IsAccessCheckNeeded() && 2805 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { 2806 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); 2807 return isolate->heap()->false_value(); 2808 } 2809 2810 if (IsJSGlobalProxy()) { 2811 Object* proto = GetPrototype(); 2812 if (proto->IsNull()) return isolate->heap()->false_value(); 2813 ASSERT(proto->IsJSGlobalObject()); 2814 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); 2815 } 2816 2817 if (HasIndexedInterceptor()) { 2818 // Skip interceptor if forcing deletion. 2819 if (mode == FORCE_DELETION) { 2820 return DeleteElementPostInterceptor(index, mode); 2821 } 2822 return DeleteElementWithInterceptor(index); 2823 } 2824 2825 switch (GetElementsKind()) { 2826 case FAST_ELEMENTS: { 2827 Object* obj; 2828 { MaybeObject* maybe_obj = EnsureWritableFastElements(); 2829 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2830 } 2831 uint32_t length = IsJSArray() ? 2832 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : 2833 static_cast<uint32_t>(FixedArray::cast(elements())->length()); 2834 if (index < length) { 2835 FixedArray::cast(elements())->set_the_hole(index); 2836 } 2837 break; 2838 } 2839 case EXTERNAL_PIXEL_ELEMENTS: 2840 case EXTERNAL_BYTE_ELEMENTS: 2841 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 2842 case EXTERNAL_SHORT_ELEMENTS: 2843 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 2844 case EXTERNAL_INT_ELEMENTS: 2845 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 2846 case EXTERNAL_FLOAT_ELEMENTS: 2847 // Pixel and external array elements cannot be deleted. Just 2848 // silently ignore here. 2849 break; 2850 case DICTIONARY_ELEMENTS: { 2851 NumberDictionary* dictionary = element_dictionary(); 2852 int entry = dictionary->FindEntry(index); 2853 if (entry != NumberDictionary::kNotFound) { 2854 Object* result = dictionary->DeleteProperty(entry, mode); 2855 if (mode == STRICT_DELETION && result == 2856 isolate->heap()->false_value()) { 2857 // In strict mode, deleting a non-configurable property throws 2858 // exception. dictionary->DeleteProperty will return false_value() 2859 // if a non-configurable property is being deleted. 2860 HandleScope scope; 2861 Handle<Object> i = isolate->factory()->NewNumberFromUint(index); 2862 Handle<Object> args[2] = { i, Handle<Object>(this) }; 2863 return isolate->Throw(*isolate->factory()->NewTypeError( 2864 "strict_delete_property", HandleVector(args, 2))); 2865 } 2866 } 2867 break; 2868 } 2869 default: 2870 UNREACHABLE(); 2871 break; 2872 } 2873 return isolate->heap()->true_value(); 2874 } 2875 2876 2877 MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { 2878 Isolate* isolate = GetIsolate(); 2879 // ECMA-262, 3rd, 8.6.2.5 2880 ASSERT(name->IsString()); 2881 2882 // Check access rights if needed. 2883 if (IsAccessCheckNeeded() && 2884 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) { 2885 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); 2886 return isolate->heap()->false_value(); 2887 } 2888 2889 if (IsJSGlobalProxy()) { 2890 Object* proto = GetPrototype(); 2891 if (proto->IsNull()) return isolate->heap()->false_value(); 2892 ASSERT(proto->IsJSGlobalObject()); 2893 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode); 2894 } 2895 2896 uint32_t index = 0; 2897 if (name->AsArrayIndex(&index)) { 2898 return DeleteElement(index, mode); 2899 } else { 2900 LookupResult result; 2901 LocalLookup(name, &result); 2902 if (!result.IsProperty()) return isolate->heap()->true_value(); 2903 // Ignore attributes if forcing a deletion. 2904 if (result.IsDontDelete() && mode != FORCE_DELETION) { 2905 if (mode == STRICT_DELETION) { 2906 // Deleting a non-configurable property in strict mode. 2907 HandleScope scope(isolate); 2908 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; 2909 return isolate->Throw(*isolate->factory()->NewTypeError( 2910 "strict_delete_property", HandleVector(args, 2))); 2911 } 2912 return isolate->heap()->false_value(); 2913 } 2914 // Check for interceptor. 2915 if (result.type() == INTERCEPTOR) { 2916 // Skip interceptor if forcing a deletion. 2917 if (mode == FORCE_DELETION) { 2918 return DeletePropertyPostInterceptor(name, mode); 2919 } 2920 return DeletePropertyWithInterceptor(name); 2921 } 2922 // Normalize object if needed. 2923 Object* obj; 2924 { MaybeObject* maybe_obj = 2925 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 2926 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2927 } 2928 // Make sure the properties are normalized before removing the entry. 2929 return DeleteNormalizedProperty(name, mode); 2930 } 2931 } 2932 2933 2934 // Check whether this object references another object. 2935 bool JSObject::ReferencesObject(Object* obj) { 2936 Map* map_of_this = map(); 2937 Heap* heap = map_of_this->heap(); 2938 AssertNoAllocation no_alloc; 2939 2940 // Is the object the constructor for this object? 2941 if (map_of_this->constructor() == obj) { 2942 return true; 2943 } 2944 2945 // Is the object the prototype for this object? 2946 if (map_of_this->prototype() == obj) { 2947 return true; 2948 } 2949 2950 // Check if the object is among the named properties. 2951 Object* key = SlowReverseLookup(obj); 2952 if (!key->IsUndefined()) { 2953 return true; 2954 } 2955 2956 // Check if the object is among the indexed properties. 2957 switch (GetElementsKind()) { 2958 case EXTERNAL_PIXEL_ELEMENTS: 2959 case EXTERNAL_BYTE_ELEMENTS: 2960 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 2961 case EXTERNAL_SHORT_ELEMENTS: 2962 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 2963 case EXTERNAL_INT_ELEMENTS: 2964 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 2965 case EXTERNAL_FLOAT_ELEMENTS: 2966 // Raw pixels and external arrays do not reference other 2967 // objects. 2968 break; 2969 case FAST_ELEMENTS: { 2970 int length = IsJSArray() ? 2971 Smi::cast(JSArray::cast(this)->length())->value() : 2972 FixedArray::cast(elements())->length(); 2973 for (int i = 0; i < length; i++) { 2974 Object* element = FixedArray::cast(elements())->get(i); 2975 if (!element->IsTheHole() && element == obj) { 2976 return true; 2977 } 2978 } 2979 break; 2980 } 2981 case DICTIONARY_ELEMENTS: { 2982 key = element_dictionary()->SlowReverseLookup(obj); 2983 if (!key->IsUndefined()) { 2984 return true; 2985 } 2986 break; 2987 } 2988 default: 2989 UNREACHABLE(); 2990 break; 2991 } 2992 2993 // For functions check the context. 2994 if (IsJSFunction()) { 2995 // Get the constructor function for arguments array. 2996 JSObject* arguments_boilerplate = 2997 heap->isolate()->context()->global_context()-> 2998 arguments_boilerplate(); 2999 JSFunction* arguments_function = 3000 JSFunction::cast(arguments_boilerplate->map()->constructor()); 3001 3002 // Get the context and don't check if it is the global context. 3003 JSFunction* f = JSFunction::cast(this); 3004 Context* context = f->context(); 3005 if (context->IsGlobalContext()) { 3006 return false; 3007 } 3008 3009 // Check the non-special context slots. 3010 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) { 3011 // Only check JS objects. 3012 if (context->get(i)->IsJSObject()) { 3013 JSObject* ctxobj = JSObject::cast(context->get(i)); 3014 // If it is an arguments array check the content. 3015 if (ctxobj->map()->constructor() == arguments_function) { 3016 if (ctxobj->ReferencesObject(obj)) { 3017 return true; 3018 } 3019 } else if (ctxobj == obj) { 3020 return true; 3021 } 3022 } 3023 } 3024 3025 // Check the context extension if any. 3026 if (context->has_extension()) { 3027 return context->extension()->ReferencesObject(obj); 3028 } 3029 } 3030 3031 // No references to object. 3032 return false; 3033 } 3034 3035 3036 MaybeObject* JSObject::PreventExtensions() { 3037 Isolate* isolate = GetIsolate(); 3038 if (IsAccessCheckNeeded() && 3039 !isolate->MayNamedAccess(this, 3040 isolate->heap()->undefined_value(), 3041 v8::ACCESS_KEYS)) { 3042 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS); 3043 return isolate->heap()->false_value(); 3044 } 3045 3046 if (IsJSGlobalProxy()) { 3047 Object* proto = GetPrototype(); 3048 if (proto->IsNull()) return this; 3049 ASSERT(proto->IsJSGlobalObject()); 3050 return JSObject::cast(proto)->PreventExtensions(); 3051 } 3052 3053 // If there are fast elements we normalize. 3054 if (HasFastElements()) { 3055 Object* ok; 3056 { MaybeObject* maybe_ok = NormalizeElements(); 3057 if (!maybe_ok->ToObject(&ok)) return maybe_ok; 3058 } 3059 } 3060 // Make sure that we never go back to fast case. 3061 element_dictionary()->set_requires_slow_elements(); 3062 3063 // Do a map transition, other objects with this map may still 3064 // be extensible. 3065 Object* new_map; 3066 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); 3067 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 3068 } 3069 Map::cast(new_map)->set_is_extensible(false); 3070 set_map(Map::cast(new_map)); 3071 ASSERT(!map()->is_extensible()); 3072 return new_map; 3073 } 3074 3075 3076 // Tests for the fast common case for property enumeration: 3077 // - This object and all prototypes has an enum cache (which means that it has 3078 // no interceptors and needs no access checks). 3079 // - This object has no elements. 3080 // - No prototype has enumerable properties/elements. 3081 bool JSObject::IsSimpleEnum() { 3082 Heap* heap = GetHeap(); 3083 for (Object* o = this; 3084 o != heap->null_value(); 3085 o = JSObject::cast(o)->GetPrototype()) { 3086 JSObject* curr = JSObject::cast(o); 3087 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false; 3088 ASSERT(!curr->HasNamedInterceptor()); 3089 ASSERT(!curr->HasIndexedInterceptor()); 3090 ASSERT(!curr->IsAccessCheckNeeded()); 3091 if (curr->NumberOfEnumElements() > 0) return false; 3092 if (curr != this) { 3093 FixedArray* curr_fixed_array = 3094 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache()); 3095 if (curr_fixed_array->length() > 0) return false; 3096 } 3097 } 3098 return true; 3099 } 3100 3101 3102 int Map::NumberOfDescribedProperties() { 3103 int result = 0; 3104 DescriptorArray* descs = instance_descriptors(); 3105 for (int i = 0; i < descs->number_of_descriptors(); i++) { 3106 if (descs->IsProperty(i)) result++; 3107 } 3108 return result; 3109 } 3110 3111 3112 int Map::PropertyIndexFor(String* name) { 3113 DescriptorArray* descs = instance_descriptors(); 3114 for (int i = 0; i < descs->number_of_descriptors(); i++) { 3115 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) { 3116 return descs->GetFieldIndex(i); 3117 } 3118 } 3119 return -1; 3120 } 3121 3122 3123 int Map::NextFreePropertyIndex() { 3124 int max_index = -1; 3125 DescriptorArray* descs = instance_descriptors(); 3126 for (int i = 0; i < descs->number_of_descriptors(); i++) { 3127 if (descs->GetType(i) == FIELD) { 3128 int current_index = descs->GetFieldIndex(i); 3129 if (current_index > max_index) max_index = current_index; 3130 } 3131 } 3132 return max_index + 1; 3133 } 3134 3135 3136 AccessorDescriptor* Map::FindAccessor(String* name) { 3137 DescriptorArray* descs = instance_descriptors(); 3138 for (int i = 0; i < descs->number_of_descriptors(); i++) { 3139 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { 3140 return descs->GetCallbacks(i); 3141 } 3142 } 3143 return NULL; 3144 } 3145 3146 3147 void JSObject::LocalLookup(String* name, LookupResult* result) { 3148 ASSERT(name->IsString()); 3149 3150 Heap* heap = GetHeap(); 3151 3152 if (IsJSGlobalProxy()) { 3153 Object* proto = GetPrototype(); 3154 if (proto->IsNull()) return result->NotFound(); 3155 ASSERT(proto->IsJSGlobalObject()); 3156 return JSObject::cast(proto)->LocalLookup(name, result); 3157 } 3158 3159 // Do not use inline caching if the object is a non-global object 3160 // that requires access checks. 3161 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) { 3162 result->DisallowCaching(); 3163 } 3164 3165 // Check __proto__ before interceptor. 3166 if (name->Equals(heap->Proto_symbol()) && 3167 !IsJSContextExtensionObject()) { 3168 result->ConstantResult(this); 3169 return; 3170 } 3171 3172 // Check for lookup interceptor except when bootstrapping. 3173 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) { 3174 result->InterceptorResult(this); 3175 return; 3176 } 3177 3178 LocalLookupRealNamedProperty(name, result); 3179 } 3180 3181 3182 void JSObject::Lookup(String* name, LookupResult* result) { 3183 // Ecma-262 3rd 8.6.2.4 3184 Heap* heap = GetHeap(); 3185 for (Object* current = this; 3186 current != heap->null_value(); 3187 current = JSObject::cast(current)->GetPrototype()) { 3188 JSObject::cast(current)->LocalLookup(name, result); 3189 if (result->IsProperty()) return; 3190 } 3191 result->NotFound(); 3192 } 3193 3194 3195 // Search object and it's prototype chain for callback properties. 3196 void JSObject::LookupCallback(String* name, LookupResult* result) { 3197 Heap* heap = GetHeap(); 3198 for (Object* current = this; 3199 current != heap->null_value(); 3200 current = JSObject::cast(current)->GetPrototype()) { 3201 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); 3202 if (result->IsProperty() && result->type() == CALLBACKS) return; 3203 } 3204 result->NotFound(); 3205 } 3206 3207 3208 MaybeObject* JSObject::DefineGetterSetter(String* name, 3209 PropertyAttributes attributes) { 3210 Heap* heap = GetHeap(); 3211 // Make sure that the top context does not change when doing callbacks or 3212 // interceptor calls. 3213 AssertNoContextChange ncc; 3214 3215 // Try to flatten before operating on the string. 3216 name->TryFlatten(); 3217 3218 if (!CanSetCallback(name)) { 3219 return heap->undefined_value(); 3220 } 3221 3222 uint32_t index = 0; 3223 bool is_element = name->AsArrayIndex(&index); 3224 3225 if (is_element) { 3226 switch (GetElementsKind()) { 3227 case FAST_ELEMENTS: 3228 break; 3229 case EXTERNAL_PIXEL_ELEMENTS: 3230 case EXTERNAL_BYTE_ELEMENTS: 3231 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 3232 case EXTERNAL_SHORT_ELEMENTS: 3233 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 3234 case EXTERNAL_INT_ELEMENTS: 3235 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 3236 case EXTERNAL_FLOAT_ELEMENTS: 3237 // Ignore getters and setters on pixel and external array 3238 // elements. 3239 return heap->undefined_value(); 3240 case DICTIONARY_ELEMENTS: { 3241 // Lookup the index. 3242 NumberDictionary* dictionary = element_dictionary(); 3243 int entry = dictionary->FindEntry(index); 3244 if (entry != NumberDictionary::kNotFound) { 3245 Object* result = dictionary->ValueAt(entry); 3246 PropertyDetails details = dictionary->DetailsAt(entry); 3247 if (details.IsReadOnly()) return heap->undefined_value(); 3248 if (details.type() == CALLBACKS) { 3249 if (result->IsFixedArray()) { 3250 return result; 3251 } 3252 // Otherwise allow to override it. 3253 } 3254 } 3255 break; 3256 } 3257 default: 3258 UNREACHABLE(); 3259 break; 3260 } 3261 } else { 3262 // Lookup the name. 3263 LookupResult result; 3264 LocalLookup(name, &result); 3265 if (result.IsProperty()) { 3266 if (result.IsReadOnly()) return heap->undefined_value(); 3267 if (result.type() == CALLBACKS) { 3268 Object* obj = result.GetCallbackObject(); 3269 // Need to preserve old getters/setters. 3270 if (obj->IsFixedArray()) { 3271 // Use set to update attributes. 3272 return SetPropertyCallback(name, obj, attributes); 3273 } 3274 } 3275 } 3276 } 3277 3278 // Allocate the fixed array to hold getter and setter. 3279 Object* structure; 3280 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED); 3281 if (!maybe_structure->ToObject(&structure)) return maybe_structure; 3282 } 3283 3284 if (is_element) { 3285 return SetElementCallback(index, structure, attributes); 3286 } else { 3287 return SetPropertyCallback(name, structure, attributes); 3288 } 3289 } 3290 3291 3292 bool JSObject::CanSetCallback(String* name) { 3293 ASSERT(!IsAccessCheckNeeded() 3294 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET)); 3295 3296 // Check if there is an API defined callback object which prohibits 3297 // callback overwriting in this object or it's prototype chain. 3298 // This mechanism is needed for instance in a browser setting, where 3299 // certain accessors such as window.location should not be allowed 3300 // to be overwritten because allowing overwriting could potentially 3301 // cause security problems. 3302 LookupResult callback_result; 3303 LookupCallback(name, &callback_result); 3304 if (callback_result.IsProperty()) { 3305 Object* obj = callback_result.GetCallbackObject(); 3306 if (obj->IsAccessorInfo() && 3307 AccessorInfo::cast(obj)->prohibits_overwriting()) { 3308 return false; 3309 } 3310 } 3311 3312 return true; 3313 } 3314 3315 3316 MaybeObject* JSObject::SetElementCallback(uint32_t index, 3317 Object* structure, 3318 PropertyAttributes attributes) { 3319 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); 3320 3321 // Normalize elements to make this operation simple. 3322 Object* ok; 3323 { MaybeObject* maybe_ok = NormalizeElements(); 3324 if (!maybe_ok->ToObject(&ok)) return maybe_ok; 3325 } 3326 3327 // Update the dictionary with the new CALLBACKS property. 3328 Object* dict; 3329 { MaybeObject* maybe_dict = 3330 element_dictionary()->Set(index, structure, details); 3331 if (!maybe_dict->ToObject(&dict)) return maybe_dict; 3332 } 3333 3334 NumberDictionary* elements = NumberDictionary::cast(dict); 3335 elements->set_requires_slow_elements(); 3336 // Set the potential new dictionary on the object. 3337 set_elements(elements); 3338 3339 return structure; 3340 } 3341 3342 3343 MaybeObject* JSObject::SetPropertyCallback(String* name, 3344 Object* structure, 3345 PropertyAttributes attributes) { 3346 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); 3347 3348 bool convert_back_to_fast = HasFastProperties() && 3349 (map()->instance_descriptors()->number_of_descriptors() 3350 < DescriptorArray::kMaxNumberOfDescriptors); 3351 3352 // Normalize object to make this operation simple. 3353 Object* ok; 3354 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 3355 if (!maybe_ok->ToObject(&ok)) return maybe_ok; 3356 } 3357 3358 // For the global object allocate a new map to invalidate the global inline 3359 // caches which have a global property cell reference directly in the code. 3360 if (IsGlobalObject()) { 3361 Object* new_map; 3362 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); 3363 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 3364 } 3365 set_map(Map::cast(new_map)); 3366 // When running crankshaft, changing the map is not enough. We 3367 // need to deoptimize all functions that rely on this global 3368 // object. 3369 Deoptimizer::DeoptimizeGlobalObject(this); 3370 } 3371 3372 // Update the dictionary with the new CALLBACKS property. 3373 Object* result; 3374 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details); 3375 if (!maybe_result->ToObject(&result)) return maybe_result; 3376 } 3377 3378 if (convert_back_to_fast) { 3379 { MaybeObject* maybe_ok = TransformToFastProperties(0); 3380 if (!maybe_ok->ToObject(&ok)) return maybe_ok; 3381 } 3382 } 3383 return result; 3384 } 3385 3386 MaybeObject* JSObject::DefineAccessor(String* name, 3387 bool is_getter, 3388 Object* fun, 3389 PropertyAttributes attributes) { 3390 ASSERT(fun->IsJSFunction() || fun->IsUndefined()); 3391 Isolate* isolate = GetIsolate(); 3392 // Check access rights if needed. 3393 if (IsAccessCheckNeeded() && 3394 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { 3395 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); 3396 return isolate->heap()->undefined_value(); 3397 } 3398 3399 if (IsJSGlobalProxy()) { 3400 Object* proto = GetPrototype(); 3401 if (proto->IsNull()) return this; 3402 ASSERT(proto->IsJSGlobalObject()); 3403 return JSObject::cast(proto)->DefineAccessor(name, is_getter, 3404 fun, attributes); 3405 } 3406 3407 Object* array; 3408 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes); 3409 if (!maybe_array->ToObject(&array)) return maybe_array; 3410 } 3411 if (array->IsUndefined()) return array; 3412 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun); 3413 return this; 3414 } 3415 3416 3417 MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { 3418 Isolate* isolate = GetIsolate(); 3419 String* name = String::cast(info->name()); 3420 // Check access rights if needed. 3421 if (IsAccessCheckNeeded() && 3422 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { 3423 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); 3424 return isolate->heap()->undefined_value(); 3425 } 3426 3427 if (IsJSGlobalProxy()) { 3428 Object* proto = GetPrototype(); 3429 if (proto->IsNull()) return this; 3430 ASSERT(proto->IsJSGlobalObject()); 3431 return JSObject::cast(proto)->DefineAccessor(info); 3432 } 3433 3434 // Make sure that the top context does not change when doing callbacks or 3435 // interceptor calls. 3436 AssertNoContextChange ncc; 3437 3438 // Try to flatten before operating on the string. 3439 name->TryFlatten(); 3440 3441 if (!CanSetCallback(name)) { 3442 return isolate->heap()->undefined_value(); 3443 } 3444 3445 uint32_t index = 0; 3446 bool is_element = name->AsArrayIndex(&index); 3447 3448 if (is_element) { 3449 if (IsJSArray()) return isolate->heap()->undefined_value(); 3450 3451 // Accessors overwrite previous callbacks (cf. with getters/setters). 3452 switch (GetElementsKind()) { 3453 case FAST_ELEMENTS: 3454 break; 3455 case EXTERNAL_PIXEL_ELEMENTS: 3456 case EXTERNAL_BYTE_ELEMENTS: 3457 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 3458 case EXTERNAL_SHORT_ELEMENTS: 3459 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 3460 case EXTERNAL_INT_ELEMENTS: 3461 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 3462 case EXTERNAL_FLOAT_ELEMENTS: 3463 // Ignore getters and setters on pixel and external array 3464 // elements. 3465 return isolate->heap()->undefined_value(); 3466 case DICTIONARY_ELEMENTS: 3467 break; 3468 default: 3469 UNREACHABLE(); 3470 break; 3471 } 3472 3473 Object* ok; 3474 { MaybeObject* maybe_ok = 3475 SetElementCallback(index, info, info->property_attributes()); 3476 if (!maybe_ok->ToObject(&ok)) return maybe_ok; 3477 } 3478 } else { 3479 // Lookup the name. 3480 LookupResult result; 3481 LocalLookup(name, &result); 3482 // ES5 forbids turning a property into an accessor if it's not 3483 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5). 3484 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) { 3485 return isolate->heap()->undefined_value(); 3486 } 3487 Object* ok; 3488 { MaybeObject* maybe_ok = 3489 SetPropertyCallback(name, info, info->property_attributes()); 3490 if (!maybe_ok->ToObject(&ok)) return maybe_ok; 3491 } 3492 } 3493 3494 return this; 3495 } 3496 3497 3498 Object* JSObject::LookupAccessor(String* name, bool is_getter) { 3499 Heap* heap = GetHeap(); 3500 3501 // Make sure that the top context does not change when doing callbacks or 3502 // interceptor calls. 3503 AssertNoContextChange ncc; 3504 3505 // Check access rights if needed. 3506 if (IsAccessCheckNeeded() && 3507 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) { 3508 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); 3509 return heap->undefined_value(); 3510 } 3511 3512 // Make the lookup and include prototypes. 3513 int accessor_index = is_getter ? kGetterIndex : kSetterIndex; 3514 uint32_t index = 0; 3515 if (name->AsArrayIndex(&index)) { 3516 for (Object* obj = this; 3517 obj != heap->null_value(); 3518 obj = JSObject::cast(obj)->GetPrototype()) { 3519 JSObject* js_object = JSObject::cast(obj); 3520 if (js_object->HasDictionaryElements()) { 3521 NumberDictionary* dictionary = js_object->element_dictionary(); 3522 int entry = dictionary->FindEntry(index); 3523 if (entry != NumberDictionary::kNotFound) { 3524 Object* element = dictionary->ValueAt(entry); 3525 PropertyDetails details = dictionary->DetailsAt(entry); 3526 if (details.type() == CALLBACKS) { 3527 if (element->IsFixedArray()) { 3528 return FixedArray::cast(element)->get(accessor_index); 3529 } 3530 } 3531 } 3532 } 3533 } 3534 } else { 3535 for (Object* obj = this; 3536 obj != heap->null_value(); 3537 obj = JSObject::cast(obj)->GetPrototype()) { 3538 LookupResult result; 3539 JSObject::cast(obj)->LocalLookup(name, &result); 3540 if (result.IsProperty()) { 3541 if (result.IsReadOnly()) return heap->undefined_value(); 3542 if (result.type() == CALLBACKS) { 3543 Object* obj = result.GetCallbackObject(); 3544 if (obj->IsFixedArray()) { 3545 return FixedArray::cast(obj)->get(accessor_index); 3546 } 3547 } 3548 } 3549 } 3550 } 3551 return heap->undefined_value(); 3552 } 3553 3554 3555 Object* JSObject::SlowReverseLookup(Object* value) { 3556 if (HasFastProperties()) { 3557 DescriptorArray* descs = map()->instance_descriptors(); 3558 for (int i = 0; i < descs->number_of_descriptors(); i++) { 3559 if (descs->GetType(i) == FIELD) { 3560 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) { 3561 return descs->GetKey(i); 3562 } 3563 } else if (descs->GetType(i) == CONSTANT_FUNCTION) { 3564 if (descs->GetConstantFunction(i) == value) { 3565 return descs->GetKey(i); 3566 } 3567 } 3568 } 3569 return GetHeap()->undefined_value(); 3570 } else { 3571 return property_dictionary()->SlowReverseLookup(value); 3572 } 3573 } 3574 3575 3576 MaybeObject* Map::CopyDropDescriptors() { 3577 Heap* heap = GetHeap(); 3578 Object* result; 3579 { MaybeObject* maybe_result = 3580 heap->AllocateMap(instance_type(), instance_size()); 3581 if (!maybe_result->ToObject(&result)) return maybe_result; 3582 } 3583 Map::cast(result)->set_prototype(prototype()); 3584 Map::cast(result)->set_constructor(constructor()); 3585 // Don't copy descriptors, so map transitions always remain a forest. 3586 // If we retained the same descriptors we would have two maps 3587 // pointing to the same transition which is bad because the garbage 3588 // collector relies on being able to reverse pointers from transitions 3589 // to maps. If properties need to be retained use CopyDropTransitions. 3590 Map::cast(result)->set_instance_descriptors( 3591 heap->empty_descriptor_array()); 3592 // Please note instance_type and instance_size are set when allocated. 3593 Map::cast(result)->set_inobject_properties(inobject_properties()); 3594 Map::cast(result)->set_unused_property_fields(unused_property_fields()); 3595 3596 // If the map has pre-allocated properties always start out with a descriptor 3597 // array describing these properties. 3598 if (pre_allocated_property_fields() > 0) { 3599 ASSERT(constructor()->IsJSFunction()); 3600 JSFunction* ctor = JSFunction::cast(constructor()); 3601 Object* descriptors; 3602 { MaybeObject* maybe_descriptors = 3603 ctor->initial_map()->instance_descriptors()->RemoveTransitions(); 3604 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; 3605 } 3606 Map::cast(result)->set_instance_descriptors( 3607 DescriptorArray::cast(descriptors)); 3608 Map::cast(result)->set_pre_allocated_property_fields( 3609 pre_allocated_property_fields()); 3610 } 3611 Map::cast(result)->set_bit_field(bit_field()); 3612 Map::cast(result)->set_bit_field2(bit_field2()); 3613 Map::cast(result)->set_is_shared(false); 3614 Map::cast(result)->ClearCodeCache(heap); 3615 return result; 3616 } 3617 3618 3619 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, 3620 NormalizedMapSharingMode sharing) { 3621 int new_instance_size = instance_size(); 3622 if (mode == CLEAR_INOBJECT_PROPERTIES) { 3623 new_instance_size -= inobject_properties() * kPointerSize; 3624 } 3625 3626 Object* result; 3627 { MaybeObject* maybe_result = 3628 GetHeap()->AllocateMap(instance_type(), new_instance_size); 3629 if (!maybe_result->ToObject(&result)) return maybe_result; 3630 } 3631 3632 if (mode != CLEAR_INOBJECT_PROPERTIES) { 3633 Map::cast(result)->set_inobject_properties(inobject_properties()); 3634 } 3635 3636 Map::cast(result)->set_prototype(prototype()); 3637 Map::cast(result)->set_constructor(constructor()); 3638 3639 Map::cast(result)->set_bit_field(bit_field()); 3640 Map::cast(result)->set_bit_field2(bit_field2()); 3641 3642 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP); 3643 3644 #ifdef DEBUG 3645 if (Map::cast(result)->is_shared()) { 3646 Map::cast(result)->SharedMapVerify(); 3647 } 3648 #endif 3649 3650 return result; 3651 } 3652 3653 3654 MaybeObject* Map::CopyDropTransitions() { 3655 Object* new_map; 3656 { MaybeObject* maybe_new_map = CopyDropDescriptors(); 3657 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 3658 } 3659 Object* descriptors; 3660 { MaybeObject* maybe_descriptors = 3661 instance_descriptors()->RemoveTransitions(); 3662 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; 3663 } 3664 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); 3665 return new_map; 3666 } 3667 3668 3669 MaybeObject* Map::UpdateCodeCache(String* name, Code* code) { 3670 // Allocate the code cache if not present. 3671 if (code_cache()->IsFixedArray()) { 3672 Object* result; 3673 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache(); 3674 if (!maybe_result->ToObject(&result)) return maybe_result; 3675 } 3676 set_code_cache(result); 3677 } 3678 3679 // Update the code cache. 3680 return CodeCache::cast(code_cache())->Update(name, code); 3681 } 3682 3683 3684 Object* Map::FindInCodeCache(String* name, Code::Flags flags) { 3685 // Do a lookup if a code cache exists. 3686 if (!code_cache()->IsFixedArray()) { 3687 return CodeCache::cast(code_cache())->Lookup(name, flags); 3688 } else { 3689 return GetHeap()->undefined_value(); 3690 } 3691 } 3692 3693 3694 int Map::IndexInCodeCache(Object* name, Code* code) { 3695 // Get the internal index if a code cache exists. 3696 if (!code_cache()->IsFixedArray()) { 3697 return CodeCache::cast(code_cache())->GetIndex(name, code); 3698 } 3699 return -1; 3700 } 3701 3702 3703 void Map::RemoveFromCodeCache(String* name, Code* code, int index) { 3704 // No GC is supposed to happen between a call to IndexInCodeCache and 3705 // RemoveFromCodeCache so the code cache must be there. 3706 ASSERT(!code_cache()->IsFixedArray()); 3707 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); 3708 } 3709 3710 3711 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { 3712 // Traverse the transition tree without using a stack. We do this by 3713 // reversing the pointers in the maps and descriptor arrays. 3714 Map* current = this; 3715 Map* meta_map = heap()->meta_map(); 3716 Object** map_or_index_field = NULL; 3717 while (current != meta_map) { 3718 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( 3719 *RawField(current, Map::kInstanceDescriptorsOffset)); 3720 if (!d->IsEmpty()) { 3721 FixedArray* contents = reinterpret_cast<FixedArray*>( 3722 d->get(DescriptorArray::kContentArrayIndex)); 3723 map_or_index_field = RawField(contents, HeapObject::kMapOffset); 3724 Object* map_or_index = *map_or_index_field; 3725 bool map_done = true; // Controls a nested continue statement. 3726 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0; 3727 i < contents->length(); 3728 i += 2) { 3729 PropertyDetails details(Smi::cast(contents->get(i + 1))); 3730 if (details.IsTransition()) { 3731 // Found a map in the transition array. We record our progress in 3732 // the transition array by recording the current map in the map field 3733 // of the next map and recording the index in the transition array in 3734 // the map field of the array. 3735 Map* next = Map::cast(contents->get(i)); 3736 next->set_map(current); 3737 *map_or_index_field = Smi::FromInt(i + 2); 3738 current = next; 3739 map_done = false; 3740 break; 3741 } 3742 } 3743 if (!map_done) continue; 3744 } else { 3745 map_or_index_field = NULL; 3746 } 3747 // That was the regular transitions, now for the prototype transitions. 3748 FixedArray* prototype_transitions = 3749 current->unchecked_prototype_transitions(); 3750 Object** proto_map_or_index_field = 3751 RawField(prototype_transitions, HeapObject::kMapOffset); 3752 Object* map_or_index = *proto_map_or_index_field; 3753 const int start = 2; 3754 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start; 3755 if (i < prototype_transitions->length()) { 3756 // Found a map in the prototype transition array. Record progress in 3757 // an analogous way to the regular transitions array above. 3758 Object* perhaps_map = prototype_transitions->get(i); 3759 if (perhaps_map->IsMap()) { 3760 Map* next = Map::cast(perhaps_map); 3761 next->set_map(current); 3762 *proto_map_or_index_field = 3763 Smi::FromInt(i + 2); 3764 current = next; 3765 continue; 3766 } 3767 } 3768 *proto_map_or_index_field = heap()->fixed_array_map(); 3769 if (map_or_index_field != NULL) { 3770 *map_or_index_field = heap()->fixed_array_map(); 3771 } 3772 3773 // The callback expects a map to have a real map as its map, so we save 3774 // the map field, which is being used to track the traversal and put the 3775 // correct map (the meta_map) in place while we do the callback. 3776 Map* prev = current->map(); 3777 current->set_map(meta_map); 3778 callback(current, data); 3779 current = prev; 3780 } 3781 } 3782 3783 3784 MaybeObject* CodeCache::Update(String* name, Code* code) { 3785 ASSERT(code->ic_state() == MONOMORPHIC); 3786 3787 // The number of monomorphic stubs for normal load/store/call IC's can grow to 3788 // a large number and therefore they need to go into a hash table. They are 3789 // used to load global properties from cells. 3790 if (code->type() == NORMAL) { 3791 // Make sure that a hash table is allocated for the normal load code cache. 3792 if (normal_type_cache()->IsUndefined()) { 3793 Object* result; 3794 { MaybeObject* maybe_result = 3795 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize); 3796 if (!maybe_result->ToObject(&result)) return maybe_result; 3797 } 3798 set_normal_type_cache(result); 3799 } 3800 return UpdateNormalTypeCache(name, code); 3801 } else { 3802 ASSERT(default_cache()->IsFixedArray()); 3803 return UpdateDefaultCache(name, code); 3804 } 3805 } 3806 3807 3808 MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) { 3809 // When updating the default code cache we disregard the type encoded in the 3810 // flags. This allows call constant stubs to overwrite call field 3811 // stubs, etc. 3812 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); 3813 3814 // First check whether we can update existing code cache without 3815 // extending it. 3816 FixedArray* cache = default_cache(); 3817 int length = cache->length(); 3818 int deleted_index = -1; 3819 for (int i = 0; i < length; i += kCodeCacheEntrySize) { 3820 Object* key = cache->get(i); 3821 if (key->IsNull()) { 3822 if (deleted_index < 0) deleted_index = i; 3823 continue; 3824 } 3825 if (key->IsUndefined()) { 3826 if (deleted_index >= 0) i = deleted_index; 3827 cache->set(i + kCodeCacheEntryNameOffset, name); 3828 cache->set(i + kCodeCacheEntryCodeOffset, code); 3829 return this; 3830 } 3831 if (name->Equals(String::cast(key))) { 3832 Code::Flags found = 3833 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags(); 3834 if (Code::RemoveTypeFromFlags(found) == flags) { 3835 cache->set(i + kCodeCacheEntryCodeOffset, code); 3836 return this; 3837 } 3838 } 3839 } 3840 3841 // Reached the end of the code cache. If there were deleted 3842 // elements, reuse the space for the first of them. 3843 if (deleted_index >= 0) { 3844 cache->set(deleted_index + kCodeCacheEntryNameOffset, name); 3845 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code); 3846 return this; 3847 } 3848 3849 // Extend the code cache with some new entries (at least one). Must be a 3850 // multiple of the entry size. 3851 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize; 3852 new_length = new_length - new_length % kCodeCacheEntrySize; 3853 ASSERT((new_length % kCodeCacheEntrySize) == 0); 3854 Object* result; 3855 { MaybeObject* maybe_result = cache->CopySize(new_length); 3856 if (!maybe_result->ToObject(&result)) return maybe_result; 3857 } 3858 3859 // Add the (name, code) pair to the new cache. 3860 cache = FixedArray::cast(result); 3861 cache->set(length + kCodeCacheEntryNameOffset, name); 3862 cache->set(length + kCodeCacheEntryCodeOffset, code); 3863 set_default_cache(cache); 3864 return this; 3865 } 3866 3867 3868 MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) { 3869 // Adding a new entry can cause a new cache to be allocated. 3870 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); 3871 Object* new_cache; 3872 { MaybeObject* maybe_new_cache = cache->Put(name, code); 3873 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache; 3874 } 3875 set_normal_type_cache(new_cache); 3876 return this; 3877 } 3878 3879 3880 Object* CodeCache::Lookup(String* name, Code::Flags flags) { 3881 if (Code::ExtractTypeFromFlags(flags) == NORMAL) { 3882 return LookupNormalTypeCache(name, flags); 3883 } else { 3884 return LookupDefaultCache(name, flags); 3885 } 3886 } 3887 3888 3889 Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) { 3890 FixedArray* cache = default_cache(); 3891 int length = cache->length(); 3892 for (int i = 0; i < length; i += kCodeCacheEntrySize) { 3893 Object* key = cache->get(i + kCodeCacheEntryNameOffset); 3894 // Skip deleted elements. 3895 if (key->IsNull()) continue; 3896 if (key->IsUndefined()) return key; 3897 if (name->Equals(String::cast(key))) { 3898 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset)); 3899 if (code->flags() == flags) { 3900 return code; 3901 } 3902 } 3903 } 3904 return GetHeap()->undefined_value(); 3905 } 3906 3907 3908 Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) { 3909 if (!normal_type_cache()->IsUndefined()) { 3910 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); 3911 return cache->Lookup(name, flags); 3912 } else { 3913 return GetHeap()->undefined_value(); 3914 } 3915 } 3916 3917 3918 int CodeCache::GetIndex(Object* name, Code* code) { 3919 if (code->type() == NORMAL) { 3920 if (normal_type_cache()->IsUndefined()) return -1; 3921 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); 3922 return cache->GetIndex(String::cast(name), code->flags()); 3923 } 3924 3925 FixedArray* array = default_cache(); 3926 int len = array->length(); 3927 for (int i = 0; i < len; i += kCodeCacheEntrySize) { 3928 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1; 3929 } 3930 return -1; 3931 } 3932 3933 3934 void CodeCache::RemoveByIndex(Object* name, Code* code, int index) { 3935 if (code->type() == NORMAL) { 3936 ASSERT(!normal_type_cache()->IsUndefined()); 3937 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); 3938 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index); 3939 cache->RemoveByIndex(index); 3940 } else { 3941 FixedArray* array = default_cache(); 3942 ASSERT(array->length() >= index && array->get(index)->IsCode()); 3943 // Use null instead of undefined for deleted elements to distinguish 3944 // deleted elements from unused elements. This distinction is used 3945 // when looking up in the cache and when updating the cache. 3946 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset); 3947 array->set_null(index - 1); // Name. 3948 array->set_null(index); // Code. 3949 } 3950 } 3951 3952 3953 // The key in the code cache hash table consists of the property name and the 3954 // code object. The actual match is on the name and the code flags. If a key 3955 // is created using the flags and not a code object it can only be used for 3956 // lookup not to create a new entry. 3957 class CodeCacheHashTableKey : public HashTableKey { 3958 public: 3959 CodeCacheHashTableKey(String* name, Code::Flags flags) 3960 : name_(name), flags_(flags), code_(NULL) { } 3961 3962 CodeCacheHashTableKey(String* name, Code* code) 3963 : name_(name), 3964 flags_(code->flags()), 3965 code_(code) { } 3966 3967 3968 bool IsMatch(Object* other) { 3969 if (!other->IsFixedArray()) return false; 3970 FixedArray* pair = FixedArray::cast(other); 3971 String* name = String::cast(pair->get(0)); 3972 Code::Flags flags = Code::cast(pair->get(1))->flags(); 3973 if (flags != flags_) { 3974 return false; 3975 } 3976 return name_->Equals(name); 3977 } 3978 3979 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) { 3980 return name->Hash() ^ flags; 3981 } 3982 3983 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); } 3984 3985 uint32_t HashForObject(Object* obj) { 3986 FixedArray* pair = FixedArray::cast(obj); 3987 String* name = String::cast(pair->get(0)); 3988 Code* code = Code::cast(pair->get(1)); 3989 return NameFlagsHashHelper(name, code->flags()); 3990 } 3991 3992 MUST_USE_RESULT MaybeObject* AsObject() { 3993 ASSERT(code_ != NULL); 3994 Object* obj; 3995 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2); 3996 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 3997 } 3998 FixedArray* pair = FixedArray::cast(obj); 3999 pair->set(0, name_); 4000 pair->set(1, code_); 4001 return pair; 4002 } 4003 4004 private: 4005 String* name_; 4006 Code::Flags flags_; 4007 Code* code_; 4008 }; 4009 4010 4011 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { 4012 CodeCacheHashTableKey key(name, flags); 4013 int entry = FindEntry(&key); 4014 if (entry == kNotFound) return GetHeap()->undefined_value(); 4015 return get(EntryToIndex(entry) + 1); 4016 } 4017 4018 4019 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) { 4020 CodeCacheHashTableKey key(name, code); 4021 Object* obj; 4022 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); 4023 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 4024 } 4025 4026 // Don't use this, as the table might have grown. 4027 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); 4028 4029 int entry = cache->FindInsertionEntry(key.Hash()); 4030 Object* k; 4031 { MaybeObject* maybe_k = key.AsObject(); 4032 if (!maybe_k->ToObject(&k)) return maybe_k; 4033 } 4034 4035 cache->set(EntryToIndex(entry), k); 4036 cache->set(EntryToIndex(entry) + 1, code); 4037 cache->ElementAdded(); 4038 return cache; 4039 } 4040 4041 4042 int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) { 4043 CodeCacheHashTableKey key(name, flags); 4044 int entry = FindEntry(&key); 4045 return (entry == kNotFound) ? -1 : entry; 4046 } 4047 4048 4049 void CodeCacheHashTable::RemoveByIndex(int index) { 4050 ASSERT(index >= 0); 4051 Heap* heap = GetHeap(); 4052 set(EntryToIndex(index), heap->null_value()); 4053 set(EntryToIndex(index) + 1, heap->null_value()); 4054 ElementRemoved(); 4055 } 4056 4057 4058 static bool HasKey(FixedArray* array, Object* key) { 4059 int len0 = array->length(); 4060 for (int i = 0; i < len0; i++) { 4061 Object* element = array->get(i); 4062 if (element->IsSmi() && key->IsSmi() && (element == key)) return true; 4063 if (element->IsString() && 4064 key->IsString() && String::cast(element)->Equals(String::cast(key))) { 4065 return true; 4066 } 4067 } 4068 return false; 4069 } 4070 4071 4072 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { 4073 ASSERT(!array->HasExternalArrayElements()); 4074 switch (array->GetElementsKind()) { 4075 case JSObject::FAST_ELEMENTS: 4076 return UnionOfKeys(FixedArray::cast(array->elements())); 4077 case JSObject::DICTIONARY_ELEMENTS: { 4078 NumberDictionary* dict = array->element_dictionary(); 4079 int size = dict->NumberOfElements(); 4080 4081 // Allocate a temporary fixed array. 4082 Object* object; 4083 { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size); 4084 if (!maybe_object->ToObject(&object)) return maybe_object; 4085 } 4086 FixedArray* key_array = FixedArray::cast(object); 4087 4088 int capacity = dict->Capacity(); 4089 int pos = 0; 4090 // Copy the elements from the JSArray to the temporary fixed array. 4091 for (int i = 0; i < capacity; i++) { 4092 if (dict->IsKey(dict->KeyAt(i))) { 4093 key_array->set(pos++, dict->ValueAt(i)); 4094 } 4095 } 4096 // Compute the union of this and the temporary fixed array. 4097 return UnionOfKeys(key_array); 4098 } 4099 default: 4100 UNREACHABLE(); 4101 } 4102 UNREACHABLE(); 4103 return GetHeap()->null_value(); // Failure case needs to "return" a value. 4104 } 4105 4106 4107 MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { 4108 int len0 = length(); 4109 #ifdef DEBUG 4110 if (FLAG_enable_slow_asserts) { 4111 for (int i = 0; i < len0; i++) { 4112 ASSERT(get(i)->IsString() || get(i)->IsNumber()); 4113 } 4114 } 4115 #endif 4116 int len1 = other->length(); 4117 // Optimize if 'other' is empty. 4118 // We cannot optimize if 'this' is empty, as other may have holes 4119 // or non keys. 4120 if (len1 == 0) return this; 4121 4122 // Compute how many elements are not in this. 4123 int extra = 0; 4124 for (int y = 0; y < len1; y++) { 4125 Object* value = other->get(y); 4126 if (!value->IsTheHole() && !HasKey(this, value)) extra++; 4127 } 4128 4129 if (extra == 0) return this; 4130 4131 // Allocate the result 4132 Object* obj; 4133 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra); 4134 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 4135 } 4136 // Fill in the content 4137 AssertNoAllocation no_gc; 4138 FixedArray* result = FixedArray::cast(obj); 4139 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); 4140 for (int i = 0; i < len0; i++) { 4141 Object* e = get(i); 4142 ASSERT(e->IsString() || e->IsNumber()); 4143 result->set(i, e, mode); 4144 } 4145 // Fill in the extra keys. 4146 int index = 0; 4147 for (int y = 0; y < len1; y++) { 4148 Object* value = other->get(y); 4149 if (!value->IsTheHole() && !HasKey(this, value)) { 4150 Object* e = other->get(y); 4151 ASSERT(e->IsString() || e->IsNumber()); 4152 result->set(len0 + index, e, mode); 4153 index++; 4154 } 4155 } 4156 ASSERT(extra == index); 4157 return result; 4158 } 4159 4160 4161 MaybeObject* FixedArray::CopySize(int new_length) { 4162 Heap* heap = GetHeap(); 4163 if (new_length == 0) return heap->empty_fixed_array(); 4164 Object* obj; 4165 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length); 4166 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 4167 } 4168 FixedArray* result = FixedArray::cast(obj); 4169 // Copy the content 4170 AssertNoAllocation no_gc; 4171 int len = length(); 4172 if (new_length < len) len = new_length; 4173 result->set_map(map()); 4174 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); 4175 for (int i = 0; i < len; i++) { 4176 result->set(i, get(i), mode); 4177 } 4178 return result; 4179 } 4180 4181 4182 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) { 4183 AssertNoAllocation no_gc; 4184 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc); 4185 for (int index = 0; index < len; index++) { 4186 dest->set(dest_pos+index, get(pos+index), mode); 4187 } 4188 } 4189 4190 4191 #ifdef DEBUG 4192 bool FixedArray::IsEqualTo(FixedArray* other) { 4193 if (length() != other->length()) return false; 4194 for (int i = 0 ; i < length(); ++i) { 4195 if (get(i) != other->get(i)) return false; 4196 } 4197 return true; 4198 } 4199 #endif 4200 4201 4202 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { 4203 Heap* heap = Isolate::Current()->heap(); 4204 if (number_of_descriptors == 0) { 4205 return heap->empty_descriptor_array(); 4206 } 4207 // Allocate the array of keys. 4208 Object* array; 4209 { MaybeObject* maybe_array = 4210 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors)); 4211 if (!maybe_array->ToObject(&array)) return maybe_array; 4212 } 4213 // Do not use DescriptorArray::cast on incomplete object. 4214 FixedArray* result = FixedArray::cast(array); 4215 4216 // Allocate the content array and set it in the descriptor array. 4217 { MaybeObject* maybe_array = 4218 heap->AllocateFixedArray(number_of_descriptors << 1); 4219 if (!maybe_array->ToObject(&array)) return maybe_array; 4220 } 4221 result->set(kContentArrayIndex, array); 4222 result->set(kEnumerationIndexIndex, 4223 Smi::FromInt(PropertyDetails::kInitialIndex)); 4224 return result; 4225 } 4226 4227 4228 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, 4229 FixedArray* new_cache) { 4230 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); 4231 if (HasEnumCache()) { 4232 FixedArray::cast(get(kEnumerationIndexIndex))-> 4233 set(kEnumCacheBridgeCacheIndex, new_cache); 4234 } else { 4235 if (IsEmpty()) return; // Do nothing for empty descriptor array. 4236 FixedArray::cast(bridge_storage)-> 4237 set(kEnumCacheBridgeCacheIndex, new_cache); 4238 fast_set(FixedArray::cast(bridge_storage), 4239 kEnumCacheBridgeEnumIndex, 4240 get(kEnumerationIndexIndex)); 4241 set(kEnumerationIndexIndex, bridge_storage); 4242 } 4243 } 4244 4245 4246 MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor, 4247 TransitionFlag transition_flag) { 4248 // Transitions are only kept when inserting another transition. 4249 // This precondition is not required by this function's implementation, but 4250 // is currently required by the semantics of maps, so we check it. 4251 // Conversely, we filter after replacing, so replacing a transition and 4252 // removing all other transitions is not supported. 4253 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS; 4254 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition()); 4255 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR); 4256 4257 // Ensure the key is a symbol. 4258 Object* result; 4259 { MaybeObject* maybe_result = descriptor->KeyToSymbol(); 4260 if (!maybe_result->ToObject(&result)) return maybe_result; 4261 } 4262 4263 int transitions = 0; 4264 int null_descriptors = 0; 4265 if (remove_transitions) { 4266 for (int i = 0; i < number_of_descriptors(); i++) { 4267 if (IsTransition(i)) transitions++; 4268 if (IsNullDescriptor(i)) null_descriptors++; 4269 } 4270 } else { 4271 for (int i = 0; i < number_of_descriptors(); i++) { 4272 if (IsNullDescriptor(i)) null_descriptors++; 4273 } 4274 } 4275 int new_size = number_of_descriptors() - transitions - null_descriptors; 4276 4277 // If key is in descriptor, we replace it in-place when filtering. 4278 // Count a null descriptor for key as inserted, not replaced. 4279 int index = Search(descriptor->GetKey()); 4280 const bool inserting = (index == kNotFound); 4281 const bool replacing = !inserting; 4282 bool keep_enumeration_index = false; 4283 if (inserting) { 4284 ++new_size; 4285 } 4286 if (replacing) { 4287 // We are replacing an existing descriptor. We keep the enumeration 4288 // index of a visible property. 4289 PropertyType t = PropertyDetails(GetDetails(index)).type(); 4290 if (t == CONSTANT_FUNCTION || 4291 t == FIELD || 4292 t == CALLBACKS || 4293 t == INTERCEPTOR) { 4294 keep_enumeration_index = true; 4295 } else if (remove_transitions) { 4296 // Replaced descriptor has been counted as removed if it is 4297 // a transition that will be replaced. Adjust count in this case. 4298 ++new_size; 4299 } 4300 } 4301 { MaybeObject* maybe_result = Allocate(new_size); 4302 if (!maybe_result->ToObject(&result)) return maybe_result; 4303 } 4304 DescriptorArray* new_descriptors = DescriptorArray::cast(result); 4305 // Set the enumeration index in the descriptors and set the enumeration index 4306 // in the result. 4307 int enumeration_index = NextEnumerationIndex(); 4308 if (!descriptor->GetDetails().IsTransition()) { 4309 if (keep_enumeration_index) { 4310 descriptor->SetEnumerationIndex( 4311 PropertyDetails(GetDetails(index)).index()); 4312 } else { 4313 descriptor->SetEnumerationIndex(enumeration_index); 4314 ++enumeration_index; 4315 } 4316 } 4317 new_descriptors->SetNextEnumerationIndex(enumeration_index); 4318 4319 // Copy the descriptors, filtering out transitions and null descriptors, 4320 // and inserting or replacing a descriptor. 4321 uint32_t descriptor_hash = descriptor->GetKey()->Hash(); 4322 int from_index = 0; 4323 int to_index = 0; 4324 4325 for (; from_index < number_of_descriptors(); from_index++) { 4326 String* key = GetKey(from_index); 4327 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) { 4328 break; 4329 } 4330 if (IsNullDescriptor(from_index)) continue; 4331 if (remove_transitions && IsTransition(from_index)) continue; 4332 new_descriptors->CopyFrom(to_index++, this, from_index); 4333 } 4334 4335 new_descriptors->Set(to_index++, descriptor); 4336 if (replacing) from_index++; 4337 4338 for (; from_index < number_of_descriptors(); from_index++) { 4339 if (IsNullDescriptor(from_index)) continue; 4340 if (remove_transitions && IsTransition(from_index)) continue; 4341 new_descriptors->CopyFrom(to_index++, this, from_index); 4342 } 4343 4344 ASSERT(to_index == new_descriptors->number_of_descriptors()); 4345 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); 4346 4347 return new_descriptors; 4348 } 4349 4350 4351 MaybeObject* DescriptorArray::RemoveTransitions() { 4352 // Remove all transitions and null descriptors. Return a copy of the array 4353 // with all transitions removed, or a Failure object if the new array could 4354 // not be allocated. 4355 4356 // Compute the size of the map transition entries to be removed. 4357 int num_removed = 0; 4358 for (int i = 0; i < number_of_descriptors(); i++) { 4359 if (!IsProperty(i)) num_removed++; 4360 } 4361 4362 // Allocate the new descriptor array. 4363 Object* result; 4364 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed); 4365 if (!maybe_result->ToObject(&result)) return maybe_result; 4366 } 4367 DescriptorArray* new_descriptors = DescriptorArray::cast(result); 4368 4369 // Copy the content. 4370 int next_descriptor = 0; 4371 for (int i = 0; i < number_of_descriptors(); i++) { 4372 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i); 4373 } 4374 ASSERT(next_descriptor == new_descriptors->number_of_descriptors()); 4375 4376 return new_descriptors; 4377 } 4378 4379 4380 void DescriptorArray::SortUnchecked() { 4381 // In-place heap sort. 4382 int len = number_of_descriptors(); 4383 4384 // Bottom-up max-heap construction. 4385 // Index of the last node with children 4386 const int max_parent_index = (len / 2) - 1; 4387 for (int i = max_parent_index; i >= 0; --i) { 4388 int parent_index = i; 4389 const uint32_t parent_hash = GetKey(i)->Hash(); 4390 while (parent_index <= max_parent_index) { 4391 int child_index = 2 * parent_index + 1; 4392 uint32_t child_hash = GetKey(child_index)->Hash(); 4393 if (child_index + 1 < len) { 4394 uint32_t right_child_hash = GetKey(child_index + 1)->Hash(); 4395 if (right_child_hash > child_hash) { 4396 child_index++; 4397 child_hash = right_child_hash; 4398 } 4399 } 4400 if (child_hash <= parent_hash) break; 4401 Swap(parent_index, child_index); 4402 // Now element at child_index could be < its children. 4403 parent_index = child_index; // parent_hash remains correct. 4404 } 4405 } 4406 4407 // Extract elements and create sorted array. 4408 for (int i = len - 1; i > 0; --i) { 4409 // Put max element at the back of the array. 4410 Swap(0, i); 4411 // Sift down the new top element. 4412 int parent_index = 0; 4413 const uint32_t parent_hash = GetKey(parent_index)->Hash(); 4414 const int max_parent_index = (i / 2) - 1; 4415 while (parent_index <= max_parent_index) { 4416 int child_index = parent_index * 2 + 1; 4417 uint32_t child_hash = GetKey(child_index)->Hash(); 4418 if (child_index + 1 < i) { 4419 uint32_t right_child_hash = GetKey(child_index + 1)->Hash(); 4420 if (right_child_hash > child_hash) { 4421 child_index++; 4422 child_hash = right_child_hash; 4423 } 4424 } 4425 if (child_hash <= parent_hash) break; 4426 Swap(parent_index, child_index); 4427 parent_index = child_index; 4428 } 4429 } 4430 } 4431 4432 4433 void DescriptorArray::Sort() { 4434 SortUnchecked(); 4435 SLOW_ASSERT(IsSortedNoDuplicates()); 4436 } 4437 4438 4439 int DescriptorArray::BinarySearch(String* name, int low, int high) { 4440 uint32_t hash = name->Hash(); 4441 4442 while (low <= high) { 4443 int mid = (low + high) / 2; 4444 String* mid_name = GetKey(mid); 4445 uint32_t mid_hash = mid_name->Hash(); 4446 4447 if (mid_hash > hash) { 4448 high = mid - 1; 4449 continue; 4450 } 4451 if (mid_hash < hash) { 4452 low = mid + 1; 4453 continue; 4454 } 4455 // Found an element with the same hash-code. 4456 ASSERT(hash == mid_hash); 4457 // There might be more, so we find the first one and 4458 // check them all to see if we have a match. 4459 if (name == mid_name && !is_null_descriptor(mid)) return mid; 4460 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--; 4461 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) { 4462 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid; 4463 } 4464 break; 4465 } 4466 return kNotFound; 4467 } 4468 4469 4470 int DescriptorArray::LinearSearch(String* name, int len) { 4471 uint32_t hash = name->Hash(); 4472 for (int number = 0; number < len; number++) { 4473 String* entry = GetKey(number); 4474 if ((entry->Hash() == hash) && 4475 name->Equals(entry) && 4476 !is_null_descriptor(number)) { 4477 return number; 4478 } 4479 } 4480 return kNotFound; 4481 } 4482 4483 4484 MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count, 4485 PretenureFlag pretenure) { 4486 ASSERT(deopt_entry_count > 0); 4487 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count), 4488 pretenure); 4489 } 4490 4491 4492 MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points, 4493 PretenureFlag pretenure) { 4494 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array(); 4495 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points), 4496 pretenure); 4497 } 4498 4499 4500 #ifdef DEBUG 4501 bool DescriptorArray::IsEqualTo(DescriptorArray* other) { 4502 if (IsEmpty()) return other->IsEmpty(); 4503 if (other->IsEmpty()) return false; 4504 if (length() != other->length()) return false; 4505 for (int i = 0; i < length(); ++i) { 4506 if (get(i) != other->get(i) && i != kContentArrayIndex) return false; 4507 } 4508 return GetContentArray()->IsEqualTo(other->GetContentArray()); 4509 } 4510 #endif 4511 4512 4513 bool String::LooksValid() { 4514 if (!Isolate::Current()->heap()->Contains(this)) return false; 4515 return true; 4516 } 4517 4518 4519 int String::Utf8Length() { 4520 if (IsAsciiRepresentation()) return length(); 4521 // Attempt to flatten before accessing the string. It probably 4522 // doesn't make Utf8Length faster, but it is very likely that 4523 // the string will be accessed later (for example by WriteUtf8) 4524 // so it's still a good idea. 4525 Heap* heap = GetHeap(); 4526 TryFlatten(); 4527 Access<StringInputBuffer> buffer( 4528 heap->isolate()->objects_string_input_buffer()); 4529 buffer->Reset(0, this); 4530 int result = 0; 4531 while (buffer->has_more()) 4532 result += unibrow::Utf8::Length(buffer->GetNext()); 4533 return result; 4534 } 4535 4536 4537 Vector<const char> String::ToAsciiVector() { 4538 ASSERT(IsAsciiRepresentation()); 4539 ASSERT(IsFlat()); 4540 4541 int offset = 0; 4542 int length = this->length(); 4543 StringRepresentationTag string_tag = StringShape(this).representation_tag(); 4544 String* string = this; 4545 if (string_tag == kConsStringTag) { 4546 ConsString* cons = ConsString::cast(string); 4547 ASSERT(cons->second()->length() == 0); 4548 string = cons->first(); 4549 string_tag = StringShape(string).representation_tag(); 4550 } 4551 if (string_tag == kSeqStringTag) { 4552 SeqAsciiString* seq = SeqAsciiString::cast(string); 4553 char* start = seq->GetChars(); 4554 return Vector<const char>(start + offset, length); 4555 } 4556 ASSERT(string_tag == kExternalStringTag); 4557 ExternalAsciiString* ext = ExternalAsciiString::cast(string); 4558 const char* start = ext->resource()->data(); 4559 return Vector<const char>(start + offset, length); 4560 } 4561 4562 4563 Vector<const uc16> String::ToUC16Vector() { 4564 ASSERT(IsTwoByteRepresentation()); 4565 ASSERT(IsFlat()); 4566 4567 int offset = 0; 4568 int length = this->length(); 4569 StringRepresentationTag string_tag = StringShape(this).representation_tag(); 4570 String* string = this; 4571 if (string_tag == kConsStringTag) { 4572 ConsString* cons = ConsString::cast(string); 4573 ASSERT(cons->second()->length() == 0); 4574 string = cons->first(); 4575 string_tag = StringShape(string).representation_tag(); 4576 } 4577 if (string_tag == kSeqStringTag) { 4578 SeqTwoByteString* seq = SeqTwoByteString::cast(string); 4579 return Vector<const uc16>(seq->GetChars() + offset, length); 4580 } 4581 ASSERT(string_tag == kExternalStringTag); 4582 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); 4583 const uc16* start = 4584 reinterpret_cast<const uc16*>(ext->resource()->data()); 4585 return Vector<const uc16>(start + offset, length); 4586 } 4587 4588 4589 SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls, 4590 RobustnessFlag robust_flag, 4591 int offset, 4592 int length, 4593 int* length_return) { 4594 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { 4595 return SmartPointer<char>(NULL); 4596 } 4597 Heap* heap = GetHeap(); 4598 4599 // Negative length means the to the end of the string. 4600 if (length < 0) length = kMaxInt - offset; 4601 4602 // Compute the size of the UTF-8 string. Start at the specified offset. 4603 Access<StringInputBuffer> buffer( 4604 heap->isolate()->objects_string_input_buffer()); 4605 buffer->Reset(offset, this); 4606 int character_position = offset; 4607 int utf8_bytes = 0; 4608 while (buffer->has_more()) { 4609 uint16_t character = buffer->GetNext(); 4610 if (character_position < offset + length) { 4611 utf8_bytes += unibrow::Utf8::Length(character); 4612 } 4613 character_position++; 4614 } 4615 4616 if (length_return) { 4617 *length_return = utf8_bytes; 4618 } 4619 4620 char* result = NewArray<char>(utf8_bytes + 1); 4621 4622 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset. 4623 buffer->Rewind(); 4624 buffer->Seek(offset); 4625 character_position = offset; 4626 int utf8_byte_position = 0; 4627 while (buffer->has_more()) { 4628 uint16_t character = buffer->GetNext(); 4629 if (character_position < offset + length) { 4630 if (allow_nulls == DISALLOW_NULLS && character == 0) { 4631 character = ' '; 4632 } 4633 utf8_byte_position += 4634 unibrow::Utf8::Encode(result + utf8_byte_position, character); 4635 } 4636 character_position++; 4637 } 4638 result[utf8_byte_position] = 0; 4639 return SmartPointer<char>(result); 4640 } 4641 4642 4643 SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls, 4644 RobustnessFlag robust_flag, 4645 int* length_return) { 4646 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); 4647 } 4648 4649 4650 const uc16* String::GetTwoByteData() { 4651 return GetTwoByteData(0); 4652 } 4653 4654 4655 const uc16* String::GetTwoByteData(unsigned start) { 4656 ASSERT(!IsAsciiRepresentation()); 4657 switch (StringShape(this).representation_tag()) { 4658 case kSeqStringTag: 4659 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); 4660 case kExternalStringTag: 4661 return ExternalTwoByteString::cast(this)-> 4662 ExternalTwoByteStringGetData(start); 4663 case kConsStringTag: 4664 UNREACHABLE(); 4665 return NULL; 4666 } 4667 UNREACHABLE(); 4668 return NULL; 4669 } 4670 4671 4672 SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) { 4673 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { 4674 return SmartPointer<uc16>(); 4675 } 4676 Heap* heap = GetHeap(); 4677 4678 Access<StringInputBuffer> buffer( 4679 heap->isolate()->objects_string_input_buffer()); 4680 buffer->Reset(this); 4681 4682 uc16* result = NewArray<uc16>(length() + 1); 4683 4684 int i = 0; 4685 while (buffer->has_more()) { 4686 uint16_t character = buffer->GetNext(); 4687 result[i++] = character; 4688 } 4689 result[i] = 0; 4690 return SmartPointer<uc16>(result); 4691 } 4692 4693 4694 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { 4695 return reinterpret_cast<uc16*>( 4696 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start; 4697 } 4698 4699 4700 void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, 4701 unsigned* offset_ptr, 4702 unsigned max_chars) { 4703 unsigned chars_read = 0; 4704 unsigned offset = *offset_ptr; 4705 while (chars_read < max_chars) { 4706 uint16_t c = *reinterpret_cast<uint16_t*>( 4707 reinterpret_cast<char*>(this) - 4708 kHeapObjectTag + kHeaderSize + offset * kShortSize); 4709 if (c <= kMaxAsciiCharCode) { 4710 // Fast case for ASCII characters. Cursor is an input output argument. 4711 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c, 4712 rbb->util_buffer, 4713 rbb->capacity, 4714 rbb->cursor)) { 4715 break; 4716 } 4717 } else { 4718 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c, 4719 rbb->util_buffer, 4720 rbb->capacity, 4721 rbb->cursor)) { 4722 break; 4723 } 4724 } 4725 offset++; 4726 chars_read++; 4727 } 4728 *offset_ptr = offset; 4729 rbb->remaining += chars_read; 4730 } 4731 4732 4733 const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock( 4734 unsigned* remaining, 4735 unsigned* offset_ptr, 4736 unsigned max_chars) { 4737 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) - 4738 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize; 4739 *remaining = max_chars; 4740 *offset_ptr += max_chars; 4741 return b; 4742 } 4743 4744 4745 // This will iterate unless the block of string data spans two 'halves' of 4746 // a ConsString, in which case it will recurse. Since the block of string 4747 // data to be read has a maximum size this limits the maximum recursion 4748 // depth to something sane. Since C++ does not have tail call recursion 4749 // elimination, the iteration must be explicit. Since this is not an 4750 // -IntoBuffer method it can delegate to one of the efficient 4751 // *AsciiStringReadBlock routines. 4752 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb, 4753 unsigned* offset_ptr, 4754 unsigned max_chars) { 4755 ConsString* current = this; 4756 unsigned offset = *offset_ptr; 4757 int offset_correction = 0; 4758 4759 while (true) { 4760 String* left = current->first(); 4761 unsigned left_length = (unsigned)left->length(); 4762 if (left_length > offset && 4763 (max_chars <= left_length - offset || 4764 (rbb->capacity <= left_length - offset && 4765 (max_chars = left_length - offset, true)))) { // comma operator! 4766 // Left hand side only - iterate unless we have reached the bottom of 4767 // the cons tree. The assignment on the left of the comma operator is 4768 // in order to make use of the fact that the -IntoBuffer routines can 4769 // produce at most 'capacity' characters. This enables us to postpone 4770 // the point where we switch to the -IntoBuffer routines (below) in order 4771 // to maximize the chances of delegating a big chunk of work to the 4772 // efficient *AsciiStringReadBlock routines. 4773 if (StringShape(left).IsCons()) { 4774 current = ConsString::cast(left); 4775 continue; 4776 } else { 4777 const unibrow::byte* answer = 4778 String::ReadBlock(left, rbb, &offset, max_chars); 4779 *offset_ptr = offset + offset_correction; 4780 return answer; 4781 } 4782 } else if (left_length <= offset) { 4783 // Right hand side only - iterate unless we have reached the bottom of 4784 // the cons tree. 4785 String* right = current->second(); 4786 offset -= left_length; 4787 offset_correction += left_length; 4788 if (StringShape(right).IsCons()) { 4789 current = ConsString::cast(right); 4790 continue; 4791 } else { 4792 const unibrow::byte* answer = 4793 String::ReadBlock(right, rbb, &offset, max_chars); 4794 *offset_ptr = offset + offset_correction; 4795 return answer; 4796 } 4797 } else { 4798 // The block to be read spans two sides of the ConsString, so we call the 4799 // -IntoBuffer version, which will recurse. The -IntoBuffer methods 4800 // are able to assemble data from several part strings because they use 4801 // the util_buffer to store their data and never return direct pointers 4802 // to their storage. We don't try to read more than the buffer capacity 4803 // here or we can get too much recursion. 4804 ASSERT(rbb->remaining == 0); 4805 ASSERT(rbb->cursor == 0); 4806 current->ConsStringReadBlockIntoBuffer( 4807 rbb, 4808 &offset, 4809 max_chars > rbb->capacity ? rbb->capacity : max_chars); 4810 *offset_ptr = offset + offset_correction; 4811 return rbb->util_buffer; 4812 } 4813 } 4814 } 4815 4816 4817 uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) { 4818 ASSERT(index >= 0 && index < length()); 4819 return resource()->data()[index]; 4820 } 4821 4822 4823 const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock( 4824 unsigned* remaining, 4825 unsigned* offset_ptr, 4826 unsigned max_chars) { 4827 // Cast const char* to unibrow::byte* (signedness difference). 4828 const unibrow::byte* b = 4829 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr; 4830 *remaining = max_chars; 4831 *offset_ptr += max_chars; 4832 return b; 4833 } 4834 4835 4836 const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData( 4837 unsigned start) { 4838 return resource()->data() + start; 4839 } 4840 4841 4842 uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) { 4843 ASSERT(index >= 0 && index < length()); 4844 return resource()->data()[index]; 4845 } 4846 4847 4848 void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer( 4849 ReadBlockBuffer* rbb, 4850 unsigned* offset_ptr, 4851 unsigned max_chars) { 4852 unsigned chars_read = 0; 4853 unsigned offset = *offset_ptr; 4854 const uint16_t* data = resource()->data(); 4855 while (chars_read < max_chars) { 4856 uint16_t c = data[offset]; 4857 if (c <= kMaxAsciiCharCode) { 4858 // Fast case for ASCII characters. Cursor is an input output argument. 4859 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c, 4860 rbb->util_buffer, 4861 rbb->capacity, 4862 rbb->cursor)) 4863 break; 4864 } else { 4865 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c, 4866 rbb->util_buffer, 4867 rbb->capacity, 4868 rbb->cursor)) 4869 break; 4870 } 4871 offset++; 4872 chars_read++; 4873 } 4874 *offset_ptr = offset; 4875 rbb->remaining += chars_read; 4876 } 4877 4878 4879 void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, 4880 unsigned* offset_ptr, 4881 unsigned max_chars) { 4882 unsigned capacity = rbb->capacity - rbb->cursor; 4883 if (max_chars > capacity) max_chars = capacity; 4884 memcpy(rbb->util_buffer + rbb->cursor, 4885 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize + 4886 *offset_ptr * kCharSize, 4887 max_chars); 4888 rbb->remaining += max_chars; 4889 *offset_ptr += max_chars; 4890 rbb->cursor += max_chars; 4891 } 4892 4893 4894 void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer( 4895 ReadBlockBuffer* rbb, 4896 unsigned* offset_ptr, 4897 unsigned max_chars) { 4898 unsigned capacity = rbb->capacity - rbb->cursor; 4899 if (max_chars > capacity) max_chars = capacity; 4900 memcpy(rbb->util_buffer + rbb->cursor, 4901 resource()->data() + *offset_ptr, 4902 max_chars); 4903 rbb->remaining += max_chars; 4904 *offset_ptr += max_chars; 4905 rbb->cursor += max_chars; 4906 } 4907 4908 4909 // This method determines the type of string involved and then copies 4910 // a whole chunk of characters into a buffer, or returns a pointer to a buffer 4911 // where they can be found. The pointer is not necessarily valid across a GC 4912 // (see AsciiStringReadBlock). 4913 const unibrow::byte* String::ReadBlock(String* input, 4914 ReadBlockBuffer* rbb, 4915 unsigned* offset_ptr, 4916 unsigned max_chars) { 4917 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length())); 4918 if (max_chars == 0) { 4919 rbb->remaining = 0; 4920 return NULL; 4921 } 4922 switch (StringShape(input).representation_tag()) { 4923 case kSeqStringTag: 4924 if (input->IsAsciiRepresentation()) { 4925 SeqAsciiString* str = SeqAsciiString::cast(input); 4926 return str->SeqAsciiStringReadBlock(&rbb->remaining, 4927 offset_ptr, 4928 max_chars); 4929 } else { 4930 SeqTwoByteString* str = SeqTwoByteString::cast(input); 4931 str->SeqTwoByteStringReadBlockIntoBuffer(rbb, 4932 offset_ptr, 4933 max_chars); 4934 return rbb->util_buffer; 4935 } 4936 case kConsStringTag: 4937 return ConsString::cast(input)->ConsStringReadBlock(rbb, 4938 offset_ptr, 4939 max_chars); 4940 case kExternalStringTag: 4941 if (input->IsAsciiRepresentation()) { 4942 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( 4943 &rbb->remaining, 4944 offset_ptr, 4945 max_chars); 4946 } else { 4947 ExternalTwoByteString::cast(input)-> 4948 ExternalTwoByteStringReadBlockIntoBuffer(rbb, 4949 offset_ptr, 4950 max_chars); 4951 return rbb->util_buffer; 4952 } 4953 default: 4954 break; 4955 } 4956 4957 UNREACHABLE(); 4958 return 0; 4959 } 4960 4961 4962 void Relocatable::PostGarbageCollectionProcessing() { 4963 Isolate* isolate = Isolate::Current(); 4964 Relocatable* current = isolate->relocatable_top(); 4965 while (current != NULL) { 4966 current->PostGarbageCollection(); 4967 current = current->prev_; 4968 } 4969 } 4970 4971 4972 // Reserve space for statics needing saving and restoring. 4973 int Relocatable::ArchiveSpacePerThread() { 4974 return sizeof(Isolate::Current()->relocatable_top()); 4975 } 4976 4977 4978 // Archive statics that are thread local. 4979 char* Relocatable::ArchiveState(char* to) { 4980 Isolate* isolate = Isolate::Current(); 4981 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top(); 4982 isolate->set_relocatable_top(NULL); 4983 return to + ArchiveSpacePerThread(); 4984 } 4985 4986 4987 // Restore statics that are thread local. 4988 char* Relocatable::RestoreState(char* from) { 4989 Isolate* isolate = Isolate::Current(); 4990 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from)); 4991 return from + ArchiveSpacePerThread(); 4992 } 4993 4994 4995 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) { 4996 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage); 4997 Iterate(v, top); 4998 return thread_storage + ArchiveSpacePerThread(); 4999 } 5000 5001 5002 void Relocatable::Iterate(ObjectVisitor* v) { 5003 Isolate* isolate = Isolate::Current(); 5004 Iterate(v, isolate->relocatable_top()); 5005 } 5006 5007 5008 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) { 5009 Relocatable* current = top; 5010 while (current != NULL) { 5011 current->IterateInstance(v); 5012 current = current->prev_; 5013 } 5014 } 5015 5016 5017 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str) 5018 : Relocatable(isolate), 5019 str_(str.location()), 5020 length_(str->length()) { 5021 PostGarbageCollection(); 5022 } 5023 5024 5025 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input) 5026 : Relocatable(isolate), 5027 str_(0), 5028 is_ascii_(true), 5029 length_(input.length()), 5030 start_(input.start()) { } 5031 5032 5033 void FlatStringReader::PostGarbageCollection() { 5034 if (str_ == NULL) return; 5035 Handle<String> str(str_); 5036 ASSERT(str->IsFlat()); 5037 is_ascii_ = str->IsAsciiRepresentation(); 5038 if (is_ascii_) { 5039 start_ = str->ToAsciiVector().start(); 5040 } else { 5041 start_ = str->ToUC16Vector().start(); 5042 } 5043 } 5044 5045 5046 void StringInputBuffer::Seek(unsigned pos) { 5047 Reset(pos, input_); 5048 } 5049 5050 5051 void SafeStringInputBuffer::Seek(unsigned pos) { 5052 Reset(pos, input_); 5053 } 5054 5055 5056 // This method determines the type of string involved and then copies 5057 // a whole chunk of characters into a buffer. It can be used with strings 5058 // that have been glued together to form a ConsString and which must cooperate 5059 // to fill up a buffer. 5060 void String::ReadBlockIntoBuffer(String* input, 5061 ReadBlockBuffer* rbb, 5062 unsigned* offset_ptr, 5063 unsigned max_chars) { 5064 ASSERT(*offset_ptr <= (unsigned)input->length()); 5065 if (max_chars == 0) return; 5066 5067 switch (StringShape(input).representation_tag()) { 5068 case kSeqStringTag: 5069 if (input->IsAsciiRepresentation()) { 5070 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, 5071 offset_ptr, 5072 max_chars); 5073 return; 5074 } else { 5075 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb, 5076 offset_ptr, 5077 max_chars); 5078 return; 5079 } 5080 case kConsStringTag: 5081 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb, 5082 offset_ptr, 5083 max_chars); 5084 return; 5085 case kExternalStringTag: 5086 if (input->IsAsciiRepresentation()) { 5087 ExternalAsciiString::cast(input)-> 5088 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); 5089 } else { 5090 ExternalTwoByteString::cast(input)-> 5091 ExternalTwoByteStringReadBlockIntoBuffer(rbb, 5092 offset_ptr, 5093 max_chars); 5094 } 5095 return; 5096 default: 5097 break; 5098 } 5099 5100 UNREACHABLE(); 5101 return; 5102 } 5103 5104 5105 const unibrow::byte* String::ReadBlock(String* input, 5106 unibrow::byte* util_buffer, 5107 unsigned capacity, 5108 unsigned* remaining, 5109 unsigned* offset_ptr) { 5110 ASSERT(*offset_ptr <= (unsigned)input->length()); 5111 unsigned chars = input->length() - *offset_ptr; 5112 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); 5113 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars); 5114 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); 5115 *remaining = rbb.remaining; 5116 return answer; 5117 } 5118 5119 5120 const unibrow::byte* String::ReadBlock(String** raw_input, 5121 unibrow::byte* util_buffer, 5122 unsigned capacity, 5123 unsigned* remaining, 5124 unsigned* offset_ptr) { 5125 Handle<String> input(raw_input); 5126 ASSERT(*offset_ptr <= (unsigned)input->length()); 5127 unsigned chars = input->length() - *offset_ptr; 5128 if (chars > capacity) chars = capacity; 5129 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); 5130 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars); 5131 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); 5132 *remaining = rbb.remaining; 5133 return rbb.util_buffer; 5134 } 5135 5136 5137 // This will iterate unless the block of string data spans two 'halves' of 5138 // a ConsString, in which case it will recurse. Since the block of string 5139 // data to be read has a maximum size this limits the maximum recursion 5140 // depth to something sane. Since C++ does not have tail call recursion 5141 // elimination, the iteration must be explicit. 5142 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, 5143 unsigned* offset_ptr, 5144 unsigned max_chars) { 5145 ConsString* current = this; 5146 unsigned offset = *offset_ptr; 5147 int offset_correction = 0; 5148 5149 while (true) { 5150 String* left = current->first(); 5151 unsigned left_length = (unsigned)left->length(); 5152 if (left_length > offset && 5153 max_chars <= left_length - offset) { 5154 // Left hand side only - iterate unless we have reached the bottom of 5155 // the cons tree. 5156 if (StringShape(left).IsCons()) { 5157 current = ConsString::cast(left); 5158 continue; 5159 } else { 5160 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars); 5161 *offset_ptr = offset + offset_correction; 5162 return; 5163 } 5164 } else if (left_length <= offset) { 5165 // Right hand side only - iterate unless we have reached the bottom of 5166 // the cons tree. 5167 offset -= left_length; 5168 offset_correction += left_length; 5169 String* right = current->second(); 5170 if (StringShape(right).IsCons()) { 5171 current = ConsString::cast(right); 5172 continue; 5173 } else { 5174 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars); 5175 *offset_ptr = offset + offset_correction; 5176 return; 5177 } 5178 } else { 5179 // The block to be read spans two sides of the ConsString, so we recurse. 5180 // First recurse on the left. 5181 max_chars -= left_length - offset; 5182 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset); 5183 // We may have reached the max or there may not have been enough space 5184 // in the buffer for the characters in the left hand side. 5185 if (offset == left_length) { 5186 // Recurse on the right. 5187 String* right = String::cast(current->second()); 5188 offset -= left_length; 5189 offset_correction += left_length; 5190 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars); 5191 } 5192 *offset_ptr = offset + offset_correction; 5193 return; 5194 } 5195 } 5196 } 5197 5198 5199 uint16_t ConsString::ConsStringGet(int index) { 5200 ASSERT(index >= 0 && index < this->length()); 5201 5202 // Check for a flattened cons string 5203 if (second()->length() == 0) { 5204 String* left = first(); 5205 return left->Get(index); 5206 } 5207 5208 String* string = String::cast(this); 5209 5210 while (true) { 5211 if (StringShape(string).IsCons()) { 5212 ConsString* cons_string = ConsString::cast(string); 5213 String* left = cons_string->first(); 5214 if (left->length() > index) { 5215 string = left; 5216 } else { 5217 index -= left->length(); 5218 string = cons_string->second(); 5219 } 5220 } else { 5221 return string->Get(index); 5222 } 5223 } 5224 5225 UNREACHABLE(); 5226 return 0; 5227 } 5228 5229 5230 template <typename sinkchar> 5231 void String::WriteToFlat(String* src, 5232 sinkchar* sink, 5233 int f, 5234 int t) { 5235 String* source = src; 5236 int from = f; 5237 int to = t; 5238 while (true) { 5239 ASSERT(0 <= from && from <= to && to <= source->length()); 5240 switch (StringShape(source).full_representation_tag()) { 5241 case kAsciiStringTag | kExternalStringTag: { 5242 CopyChars(sink, 5243 ExternalAsciiString::cast(source)->resource()->data() + from, 5244 to - from); 5245 return; 5246 } 5247 case kTwoByteStringTag | kExternalStringTag: { 5248 const uc16* data = 5249 ExternalTwoByteString::cast(source)->resource()->data(); 5250 CopyChars(sink, 5251 data + from, 5252 to - from); 5253 return; 5254 } 5255 case kAsciiStringTag | kSeqStringTag: { 5256 CopyChars(sink, 5257 SeqAsciiString::cast(source)->GetChars() + from, 5258 to - from); 5259 return; 5260 } 5261 case kTwoByteStringTag | kSeqStringTag: { 5262 CopyChars(sink, 5263 SeqTwoByteString::cast(source)->GetChars() + from, 5264 to - from); 5265 return; 5266 } 5267 case kAsciiStringTag | kConsStringTag: 5268 case kTwoByteStringTag | kConsStringTag: { 5269 ConsString* cons_string = ConsString::cast(source); 5270 String* first = cons_string->first(); 5271 int boundary = first->length(); 5272 if (to - boundary >= boundary - from) { 5273 // Right hand side is longer. Recurse over left. 5274 if (from < boundary) { 5275 WriteToFlat(first, sink, from, boundary); 5276 sink += boundary - from; 5277 from = 0; 5278 } else { 5279 from -= boundary; 5280 } 5281 to -= boundary; 5282 source = cons_string->second(); 5283 } else { 5284 // Left hand side is longer. Recurse over right. 5285 if (to > boundary) { 5286 String* second = cons_string->second(); 5287 WriteToFlat(second, 5288 sink + boundary - from, 5289 0, 5290 to - boundary); 5291 to = boundary; 5292 } 5293 source = first; 5294 } 5295 break; 5296 } 5297 } 5298 } 5299 } 5300 5301 5302 template <typename IteratorA, typename IteratorB> 5303 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) { 5304 // General slow case check. We know that the ia and ib iterators 5305 // have the same length. 5306 while (ia->has_more()) { 5307 uc32 ca = ia->GetNext(); 5308 uc32 cb = ib->GetNext(); 5309 if (ca != cb) 5310 return false; 5311 } 5312 return true; 5313 } 5314 5315 5316 // Compares the contents of two strings by reading and comparing 5317 // int-sized blocks of characters. 5318 template <typename Char> 5319 static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) { 5320 int length = a.length(); 5321 ASSERT_EQ(length, b.length()); 5322 const Char* pa = a.start(); 5323 const Char* pb = b.start(); 5324 int i = 0; 5325 #ifndef V8_HOST_CAN_READ_UNALIGNED 5326 // If this architecture isn't comfortable reading unaligned ints 5327 // then we have to check that the strings are aligned before 5328 // comparing them blockwise. 5329 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT 5330 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa); 5331 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb); 5332 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) { 5333 #endif 5334 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT 5335 int endpoint = length - kStepSize; 5336 // Compare blocks until we reach near the end of the string. 5337 for (; i <= endpoint; i += kStepSize) { 5338 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i); 5339 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i); 5340 if (wa != wb) { 5341 return false; 5342 } 5343 } 5344 #ifndef V8_HOST_CAN_READ_UNALIGNED 5345 } 5346 #endif 5347 // Compare the remaining characters that didn't fit into a block. 5348 for (; i < length; i++) { 5349 if (a[i] != b[i]) { 5350 return false; 5351 } 5352 } 5353 return true; 5354 } 5355 5356 5357 template <typename IteratorA> 5358 static inline bool CompareStringContentsPartial(Isolate* isolate, 5359 IteratorA* ia, 5360 String* b) { 5361 if (b->IsFlat()) { 5362 if (b->IsAsciiRepresentation()) { 5363 VectorIterator<char> ib(b->ToAsciiVector()); 5364 return CompareStringContents(ia, &ib); 5365 } else { 5366 VectorIterator<uc16> ib(b->ToUC16Vector()); 5367 return CompareStringContents(ia, &ib); 5368 } 5369 } else { 5370 isolate->objects_string_compare_buffer_b()->Reset(0, b); 5371 return CompareStringContents(ia, 5372 isolate->objects_string_compare_buffer_b()); 5373 } 5374 } 5375 5376 5377 bool String::SlowEquals(String* other) { 5378 // Fast check: negative check with lengths. 5379 int len = length(); 5380 if (len != other->length()) return false; 5381 if (len == 0) return true; 5382 5383 // Fast check: if hash code is computed for both strings 5384 // a fast negative check can be performed. 5385 if (HasHashCode() && other->HasHashCode()) { 5386 if (Hash() != other->Hash()) return false; 5387 } 5388 5389 // We know the strings are both non-empty. Compare the first chars 5390 // before we try to flatten the strings. 5391 if (this->Get(0) != other->Get(0)) return false; 5392 5393 String* lhs = this->TryFlattenGetString(); 5394 String* rhs = other->TryFlattenGetString(); 5395 5396 if (StringShape(lhs).IsSequentialAscii() && 5397 StringShape(rhs).IsSequentialAscii()) { 5398 const char* str1 = SeqAsciiString::cast(lhs)->GetChars(); 5399 const char* str2 = SeqAsciiString::cast(rhs)->GetChars(); 5400 return CompareRawStringContents(Vector<const char>(str1, len), 5401 Vector<const char>(str2, len)); 5402 } 5403 5404 Isolate* isolate = GetIsolate(); 5405 if (lhs->IsFlat()) { 5406 if (lhs->IsAsciiRepresentation()) { 5407 Vector<const char> vec1 = lhs->ToAsciiVector(); 5408 if (rhs->IsFlat()) { 5409 if (rhs->IsAsciiRepresentation()) { 5410 Vector<const char> vec2 = rhs->ToAsciiVector(); 5411 return CompareRawStringContents(vec1, vec2); 5412 } else { 5413 VectorIterator<char> buf1(vec1); 5414 VectorIterator<uc16> ib(rhs->ToUC16Vector()); 5415 return CompareStringContents(&buf1, &ib); 5416 } 5417 } else { 5418 VectorIterator<char> buf1(vec1); 5419 isolate->objects_string_compare_buffer_b()->Reset(0, rhs); 5420 return CompareStringContents(&buf1, 5421 isolate->objects_string_compare_buffer_b()); 5422 } 5423 } else { 5424 Vector<const uc16> vec1 = lhs->ToUC16Vector(); 5425 if (rhs->IsFlat()) { 5426 if (rhs->IsAsciiRepresentation()) { 5427 VectorIterator<uc16> buf1(vec1); 5428 VectorIterator<char> ib(rhs->ToAsciiVector()); 5429 return CompareStringContents(&buf1, &ib); 5430 } else { 5431 Vector<const uc16> vec2(rhs->ToUC16Vector()); 5432 return CompareRawStringContents(vec1, vec2); 5433 } 5434 } else { 5435 VectorIterator<uc16> buf1(vec1); 5436 isolate->objects_string_compare_buffer_b()->Reset(0, rhs); 5437 return CompareStringContents(&buf1, 5438 isolate->objects_string_compare_buffer_b()); 5439 } 5440 } 5441 } else { 5442 isolate->objects_string_compare_buffer_a()->Reset(0, lhs); 5443 return CompareStringContentsPartial(isolate, 5444 isolate->objects_string_compare_buffer_a(), rhs); 5445 } 5446 } 5447 5448 5449 bool String::MarkAsUndetectable() { 5450 if (StringShape(this).IsSymbol()) return false; 5451 5452 Map* map = this->map(); 5453 Heap* heap = map->heap(); 5454 if (map == heap->string_map()) { 5455 this->set_map(heap->undetectable_string_map()); 5456 return true; 5457 } else if (map == heap->ascii_string_map()) { 5458 this->set_map(heap->undetectable_ascii_string_map()); 5459 return true; 5460 } 5461 // Rest cannot be marked as undetectable 5462 return false; 5463 } 5464 5465 5466 bool String::IsEqualTo(Vector<const char> str) { 5467 Isolate* isolate = GetIsolate(); 5468 int slen = length(); 5469 Access<UnicodeCache::Utf8Decoder> 5470 decoder(isolate->unicode_cache()->utf8_decoder()); 5471 decoder->Reset(str.start(), str.length()); 5472 int i; 5473 for (i = 0; i < slen && decoder->has_more(); i++) { 5474 uc32 r = decoder->GetNext(); 5475 if (Get(i) != r) return false; 5476 } 5477 return i == slen && !decoder->has_more(); 5478 } 5479 5480 5481 bool String::IsAsciiEqualTo(Vector<const char> str) { 5482 int slen = length(); 5483 if (str.length() != slen) return false; 5484 for (int i = 0; i < slen; i++) { 5485 if (Get(i) != static_cast<uint16_t>(str[i])) return false; 5486 } 5487 return true; 5488 } 5489 5490 5491 bool String::IsTwoByteEqualTo(Vector<const uc16> str) { 5492 int slen = length(); 5493 if (str.length() != slen) return false; 5494 for (int i = 0; i < slen; i++) { 5495 if (Get(i) != str[i]) return false; 5496 } 5497 return true; 5498 } 5499 5500 5501 uint32_t String::ComputeAndSetHash() { 5502 // Should only be called if hash code has not yet been computed. 5503 ASSERT(!HasHashCode()); 5504 5505 const int len = length(); 5506 5507 // Compute the hash code. 5508 uint32_t field = 0; 5509 if (StringShape(this).IsSequentialAscii()) { 5510 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len); 5511 } else if (StringShape(this).IsSequentialTwoByte()) { 5512 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len); 5513 } else { 5514 StringInputBuffer buffer(this); 5515 field = ComputeHashField(&buffer, len); 5516 } 5517 5518 // Store the hash code in the object. 5519 set_hash_field(field); 5520 5521 // Check the hash code is there. 5522 ASSERT(HasHashCode()); 5523 uint32_t result = field >> kHashShift; 5524 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed. 5525 return result; 5526 } 5527 5528 5529 bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer, 5530 uint32_t* index, 5531 int length) { 5532 if (length == 0 || length > kMaxArrayIndexSize) return false; 5533 uc32 ch = buffer->GetNext(); 5534 5535 // If the string begins with a '0' character, it must only consist 5536 // of it to be a legal array index. 5537 if (ch == '0') { 5538 *index = 0; 5539 return length == 1; 5540 } 5541 5542 // Convert string to uint32 array index; character by character. 5543 int d = ch - '0'; 5544 if (d < 0 || d > 9) return false; 5545 uint32_t result = d; 5546 while (buffer->has_more()) { 5547 d = buffer->GetNext() - '0'; 5548 if (d < 0 || d > 9) return false; 5549 // Check that the new result is below the 32 bit limit. 5550 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; 5551 result = (result * 10) + d; 5552 } 5553 5554 *index = result; 5555 return true; 5556 } 5557 5558 5559 bool String::SlowAsArrayIndex(uint32_t* index) { 5560 if (length() <= kMaxCachedArrayIndexLength) { 5561 Hash(); // force computation of hash code 5562 uint32_t field = hash_field(); 5563 if ((field & kIsNotArrayIndexMask) != 0) return false; 5564 // Isolate the array index form the full hash field. 5565 *index = (kArrayIndexHashMask & field) >> kHashShift; 5566 return true; 5567 } else { 5568 StringInputBuffer buffer(this); 5569 return ComputeArrayIndex(&buffer, index, length()); 5570 } 5571 } 5572 5573 5574 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) { 5575 // For array indexes mix the length into the hash as an array index could 5576 // be zero. 5577 ASSERT(length > 0); 5578 ASSERT(length <= String::kMaxArrayIndexSize); 5579 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < 5580 (1 << String::kArrayIndexValueBits)); 5581 5582 value <<= String::kHashShift; 5583 value |= length << String::kArrayIndexHashLengthShift; 5584 5585 ASSERT((value & String::kIsNotArrayIndexMask) == 0); 5586 ASSERT((length > String::kMaxCachedArrayIndexLength) || 5587 (value & String::kContainsCachedArrayIndexMask) == 0); 5588 return value; 5589 } 5590 5591 5592 uint32_t StringHasher::GetHashField() { 5593 ASSERT(is_valid()); 5594 if (length_ <= String::kMaxHashCalcLength) { 5595 if (is_array_index()) { 5596 return MakeArrayIndexHash(array_index(), length_); 5597 } 5598 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask; 5599 } else { 5600 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask; 5601 } 5602 } 5603 5604 5605 uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer, 5606 int length) { 5607 StringHasher hasher(length); 5608 5609 // Very long strings have a trivial hash that doesn't inspect the 5610 // string contents. 5611 if (hasher.has_trivial_hash()) { 5612 return hasher.GetHashField(); 5613 } 5614 5615 // Do the iterative array index computation as long as there is a 5616 // chance this is an array index. 5617 while (buffer->has_more() && hasher.is_array_index()) { 5618 hasher.AddCharacter(buffer->GetNext()); 5619 } 5620 5621 // Process the remaining characters without updating the array 5622 // index. 5623 while (buffer->has_more()) { 5624 hasher.AddCharacterNoIndex(buffer->GetNext()); 5625 } 5626 5627 return hasher.GetHashField(); 5628 } 5629 5630 5631 MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) { 5632 Heap* heap = GetHeap(); 5633 if (start == 0 && end == length()) return this; 5634 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure); 5635 return result; 5636 } 5637 5638 5639 void String::PrintOn(FILE* file) { 5640 int length = this->length(); 5641 for (int i = 0; i < length; i++) { 5642 fprintf(file, "%c", Get(i)); 5643 } 5644 } 5645 5646 5647 void Map::CreateBackPointers() { 5648 DescriptorArray* descriptors = instance_descriptors(); 5649 for (int i = 0; i < descriptors->number_of_descriptors(); i++) { 5650 if (descriptors->GetType(i) == MAP_TRANSITION || 5651 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION || 5652 descriptors->GetType(i) == CONSTANT_TRANSITION) { 5653 // Get target. 5654 Map* target = Map::cast(descriptors->GetValue(i)); 5655 #ifdef DEBUG 5656 // Verify target. 5657 Object* source_prototype = prototype(); 5658 Object* target_prototype = target->prototype(); 5659 ASSERT(source_prototype->IsJSObject() || 5660 source_prototype->IsMap() || 5661 source_prototype->IsNull()); 5662 ASSERT(target_prototype->IsJSObject() || 5663 target_prototype->IsNull()); 5664 ASSERT(source_prototype->IsMap() || 5665 source_prototype == target_prototype); 5666 #endif 5667 // Point target back to source. set_prototype() will not let us set 5668 // the prototype to a map, as we do here. 5669 *RawField(target, kPrototypeOffset) = this; 5670 } 5671 } 5672 } 5673 5674 5675 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { 5676 // Live DescriptorArray objects will be marked, so we must use 5677 // low-level accessors to get and modify their data. 5678 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( 5679 *RawField(this, Map::kInstanceDescriptorsOffset)); 5680 if (d == heap->raw_unchecked_empty_descriptor_array()) return; 5681 Smi* NullDescriptorDetails = 5682 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); 5683 FixedArray* contents = reinterpret_cast<FixedArray*>( 5684 d->get(DescriptorArray::kContentArrayIndex)); 5685 ASSERT(contents->length() >= 2); 5686 for (int i = 0; i < contents->length(); i += 2) { 5687 // If the pair (value, details) is a map transition, 5688 // check if the target is live. If not, null the descriptor. 5689 // Also drop the back pointer for that map transition, so that this 5690 // map is not reached again by following a back pointer from a 5691 // non-live object. 5692 PropertyDetails details(Smi::cast(contents->get(i + 1))); 5693 if (details.type() == MAP_TRANSITION || 5694 details.type() == EXTERNAL_ARRAY_TRANSITION || 5695 details.type() == CONSTANT_TRANSITION) { 5696 Map* target = reinterpret_cast<Map*>(contents->get(i)); 5697 ASSERT(target->IsHeapObject()); 5698 if (!target->IsMarked()) { 5699 ASSERT(target->IsMap()); 5700 contents->set_unchecked(i + 1, NullDescriptorDetails); 5701 contents->set_null_unchecked(heap, i); 5702 ASSERT(target->prototype() == this || 5703 target->prototype() == real_prototype); 5704 // Getter prototype() is read-only, set_prototype() has side effects. 5705 *RawField(target, Map::kPrototypeOffset) = real_prototype; 5706 } 5707 } 5708 } 5709 } 5710 5711 5712 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { 5713 // Iterate over all fields in the body but take care in dealing with 5714 // the code entry. 5715 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); 5716 v->VisitCodeEntry(this->address() + kCodeEntryOffset); 5717 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); 5718 } 5719 5720 5721 void JSFunction::MarkForLazyRecompilation() { 5722 ASSERT(is_compiled() && !IsOptimized()); 5723 ASSERT(shared()->allows_lazy_compilation() || 5724 code()->optimizable()); 5725 Builtins* builtins = GetIsolate()->builtins(); 5726 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile)); 5727 } 5728 5729 5730 uint32_t JSFunction::SourceHash() { 5731 uint32_t hash = 0; 5732 Object* script = shared()->script(); 5733 if (!script->IsUndefined()) { 5734 Object* source = Script::cast(script)->source(); 5735 if (source->IsUndefined()) hash = String::cast(source)->Hash(); 5736 } 5737 hash ^= ComputeIntegerHash(shared()->start_position_and_type()); 5738 hash += ComputeIntegerHash(shared()->end_position()); 5739 return hash; 5740 } 5741 5742 5743 bool JSFunction::IsInlineable() { 5744 if (IsBuiltin()) return false; 5745 SharedFunctionInfo* shared_info = shared(); 5746 // Check that the function has a script associated with it. 5747 if (!shared_info->script()->IsScript()) return false; 5748 if (shared_info->optimization_disabled()) return false; 5749 Code* code = shared_info->code(); 5750 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true; 5751 // If we never ran this (unlikely) then lets try to optimize it. 5752 if (code->kind() != Code::FUNCTION) return true; 5753 return code->optimizable(); 5754 } 5755 5756 5757 Object* JSFunction::SetInstancePrototype(Object* value) { 5758 ASSERT(value->IsJSObject()); 5759 Heap* heap = GetHeap(); 5760 if (has_initial_map()) { 5761 initial_map()->set_prototype(value); 5762 } else { 5763 // Put the value in the initial map field until an initial map is 5764 // needed. At that point, a new initial map is created and the 5765 // prototype is put into the initial map where it belongs. 5766 set_prototype_or_initial_map(value); 5767 } 5768 heap->ClearInstanceofCache(); 5769 return value; 5770 } 5771 5772 5773 MaybeObject* JSFunction::SetPrototype(Object* value) { 5774 ASSERT(should_have_prototype()); 5775 Object* construct_prototype = value; 5776 5777 // If the value is not a JSObject, store the value in the map's 5778 // constructor field so it can be accessed. Also, set the prototype 5779 // used for constructing objects to the original object prototype. 5780 // See ECMA-262 13.2.2. 5781 if (!value->IsJSObject()) { 5782 // Copy the map so this does not affect unrelated functions. 5783 // Remove map transitions because they point to maps with a 5784 // different prototype. 5785 Object* new_object; 5786 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); 5787 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map; 5788 } 5789 Map* new_map = Map::cast(new_object); 5790 Heap* heap = new_map->heap(); 5791 set_map(new_map); 5792 new_map->set_constructor(value); 5793 new_map->set_non_instance_prototype(true); 5794 construct_prototype = 5795 heap->isolate()->context()->global_context()-> 5796 initial_object_prototype(); 5797 } else { 5798 map()->set_non_instance_prototype(false); 5799 } 5800 5801 return SetInstancePrototype(construct_prototype); 5802 } 5803 5804 5805 Object* JSFunction::RemovePrototype() { 5806 Context* global_context = context()->global_context(); 5807 Map* no_prototype_map = shared()->strict_mode() 5808 ? global_context->strict_mode_function_without_prototype_map() 5809 : global_context->function_without_prototype_map(); 5810 5811 if (map() == no_prototype_map) { 5812 // Be idempotent. 5813 return this; 5814 } 5815 5816 ASSERT(!shared()->strict_mode() || 5817 map() == global_context->strict_mode_function_map()); 5818 ASSERT(shared()->strict_mode() || map() == global_context->function_map()); 5819 5820 set_map(no_prototype_map); 5821 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value()); 5822 return this; 5823 } 5824 5825 5826 Object* JSFunction::SetInstanceClassName(String* name) { 5827 shared()->set_instance_class_name(name); 5828 return this; 5829 } 5830 5831 5832 void JSFunction::PrintName(FILE* out) { 5833 SmartPointer<char> name = shared()->DebugName()->ToCString(); 5834 PrintF(out, "%s", *name); 5835 } 5836 5837 5838 Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) { 5839 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex)); 5840 } 5841 5842 5843 MaybeObject* Oddball::Initialize(const char* to_string, 5844 Object* to_number, 5845 byte kind) { 5846 Object* symbol; 5847 { MaybeObject* maybe_symbol = 5848 Isolate::Current()->heap()->LookupAsciiSymbol(to_string); 5849 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol; 5850 } 5851 set_to_string(String::cast(symbol)); 5852 set_to_number(to_number); 5853 set_kind(kind); 5854 return this; 5855 } 5856 5857 5858 String* SharedFunctionInfo::DebugName() { 5859 Object* n = name(); 5860 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name(); 5861 return String::cast(n); 5862 } 5863 5864 5865 bool SharedFunctionInfo::HasSourceCode() { 5866 return !script()->IsUndefined() && 5867 !reinterpret_cast<Script*>(script())->source()->IsUndefined(); 5868 } 5869 5870 5871 Object* SharedFunctionInfo::GetSourceCode() { 5872 Isolate* isolate = GetIsolate(); 5873 if (!HasSourceCode()) return isolate->heap()->undefined_value(); 5874 HandleScope scope(isolate); 5875 Object* source = Script::cast(script())->source(); 5876 return *SubString(Handle<String>(String::cast(source), isolate), 5877 start_position(), end_position()); 5878 } 5879 5880 5881 int SharedFunctionInfo::SourceSize() { 5882 return end_position() - start_position(); 5883 } 5884 5885 5886 int SharedFunctionInfo::CalculateInstanceSize() { 5887 int instance_size = 5888 JSObject::kHeaderSize + 5889 expected_nof_properties() * kPointerSize; 5890 if (instance_size > JSObject::kMaxInstanceSize) { 5891 instance_size = JSObject::kMaxInstanceSize; 5892 } 5893 return instance_size; 5894 } 5895 5896 5897 int SharedFunctionInfo::CalculateInObjectProperties() { 5898 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize; 5899 } 5900 5901 5902 bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) { 5903 // Check the basic conditions for generating inline constructor code. 5904 if (!FLAG_inline_new 5905 || !has_only_simple_this_property_assignments() 5906 || this_property_assignments_count() == 0) { 5907 return false; 5908 } 5909 5910 // If the prototype is null inline constructors cause no problems. 5911 if (!prototype->IsJSObject()) { 5912 ASSERT(prototype->IsNull()); 5913 return true; 5914 } 5915 5916 Heap* heap = GetHeap(); 5917 5918 // Traverse the proposed prototype chain looking for setters for properties of 5919 // the same names as are set by the inline constructor. 5920 for (Object* obj = prototype; 5921 obj != heap->null_value(); 5922 obj = obj->GetPrototype()) { 5923 JSObject* js_object = JSObject::cast(obj); 5924 for (int i = 0; i < this_property_assignments_count(); i++) { 5925 LookupResult result; 5926 String* name = GetThisPropertyAssignmentName(i); 5927 js_object->LocalLookupRealNamedProperty(name, &result); 5928 if (result.IsProperty() && result.type() == CALLBACKS) { 5929 return false; 5930 } 5931 } 5932 } 5933 5934 return true; 5935 } 5936 5937 5938 void SharedFunctionInfo::ForbidInlineConstructor() { 5939 set_compiler_hints(BooleanBit::set(compiler_hints(), 5940 kHasOnlySimpleThisPropertyAssignments, 5941 false)); 5942 } 5943 5944 5945 void SharedFunctionInfo::SetThisPropertyAssignmentsInfo( 5946 bool only_simple_this_property_assignments, 5947 FixedArray* assignments) { 5948 set_compiler_hints(BooleanBit::set(compiler_hints(), 5949 kHasOnlySimpleThisPropertyAssignments, 5950 only_simple_this_property_assignments)); 5951 set_this_property_assignments(assignments); 5952 set_this_property_assignments_count(assignments->length() / 3); 5953 } 5954 5955 5956 void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() { 5957 Heap* heap = GetHeap(); 5958 set_compiler_hints(BooleanBit::set(compiler_hints(), 5959 kHasOnlySimpleThisPropertyAssignments, 5960 false)); 5961 set_this_property_assignments(heap->undefined_value()); 5962 set_this_property_assignments_count(0); 5963 } 5964 5965 5966 String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) { 5967 Object* obj = this_property_assignments(); 5968 ASSERT(obj->IsFixedArray()); 5969 ASSERT(index < this_property_assignments_count()); 5970 obj = FixedArray::cast(obj)->get(index * 3); 5971 ASSERT(obj->IsString()); 5972 return String::cast(obj); 5973 } 5974 5975 5976 bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) { 5977 Object* obj = this_property_assignments(); 5978 ASSERT(obj->IsFixedArray()); 5979 ASSERT(index < this_property_assignments_count()); 5980 obj = FixedArray::cast(obj)->get(index * 3 + 1); 5981 return Smi::cast(obj)->value() != -1; 5982 } 5983 5984 5985 int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) { 5986 ASSERT(IsThisPropertyAssignmentArgument(index)); 5987 Object* obj = 5988 FixedArray::cast(this_property_assignments())->get(index * 3 + 1); 5989 return Smi::cast(obj)->value(); 5990 } 5991 5992 5993 Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) { 5994 ASSERT(!IsThisPropertyAssignmentArgument(index)); 5995 Object* obj = 5996 FixedArray::cast(this_property_assignments())->get(index * 3 + 2); 5997 return obj; 5998 } 5999 6000 6001 // Support function for printing the source code to a StringStream 6002 // without any allocation in the heap. 6003 void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator, 6004 int max_length) { 6005 // For some native functions there is no source. 6006 if (!HasSourceCode()) { 6007 accumulator->Add("<No Source>"); 6008 return; 6009 } 6010 6011 // Get the source for the script which this function came from. 6012 // Don't use String::cast because we don't want more assertion errors while 6013 // we are already creating a stack dump. 6014 String* script_source = 6015 reinterpret_cast<String*>(Script::cast(script())->source()); 6016 6017 if (!script_source->LooksValid()) { 6018 accumulator->Add("<Invalid Source>"); 6019 return; 6020 } 6021 6022 if (!is_toplevel()) { 6023 accumulator->Add("function "); 6024 Object* name = this->name(); 6025 if (name->IsString() && String::cast(name)->length() > 0) { 6026 accumulator->PrintName(name); 6027 } 6028 } 6029 6030 int len = end_position() - start_position(); 6031 if (len <= max_length || max_length < 0) { 6032 accumulator->Put(script_source, start_position(), end_position()); 6033 } else { 6034 accumulator->Put(script_source, 6035 start_position(), 6036 start_position() + max_length); 6037 accumulator->Add("...\n"); 6038 } 6039 } 6040 6041 6042 static bool IsCodeEquivalent(Code* code, Code* recompiled) { 6043 if (code->instruction_size() != recompiled->instruction_size()) return false; 6044 ByteArray* code_relocation = code->relocation_info(); 6045 ByteArray* recompiled_relocation = recompiled->relocation_info(); 6046 int length = code_relocation->length(); 6047 if (length != recompiled_relocation->length()) return false; 6048 int compare = memcmp(code_relocation->GetDataStartAddress(), 6049 recompiled_relocation->GetDataStartAddress(), 6050 length); 6051 return compare == 0; 6052 } 6053 6054 6055 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) { 6056 ASSERT(!has_deoptimization_support()); 6057 AssertNoAllocation no_allocation; 6058 Code* code = this->code(); 6059 if (IsCodeEquivalent(code, recompiled)) { 6060 // Copy the deoptimization data from the recompiled code. 6061 code->set_deoptimization_data(recompiled->deoptimization_data()); 6062 code->set_has_deoptimization_support(true); 6063 } else { 6064 // TODO(3025757): In case the recompiled isn't equivalent to the 6065 // old code, we have to replace it. We should try to avoid this 6066 // altogether because it flushes valuable type feedback by 6067 // effectively resetting all IC state. 6068 set_code(recompiled); 6069 } 6070 ASSERT(has_deoptimization_support()); 6071 } 6072 6073 6074 bool SharedFunctionInfo::VerifyBailoutId(int id) { 6075 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while 6076 // we are always bailing out on ARM. 6077 6078 ASSERT(id != AstNode::kNoNumber); 6079 Code* unoptimized = code(); 6080 DeoptimizationOutputData* data = 6081 DeoptimizationOutputData::cast(unoptimized->deoptimization_data()); 6082 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this); 6083 USE(ignore); 6084 return true; // Return true if there was no ASSERT. 6085 } 6086 6087 6088 void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) { 6089 ASSERT(!IsInobjectSlackTrackingInProgress()); 6090 6091 // Only initiate the tracking the first time. 6092 if (live_objects_may_exist()) return; 6093 set_live_objects_may_exist(true); 6094 6095 // No tracking during the snapshot construction phase. 6096 if (Serializer::enabled()) return; 6097 6098 if (map->unused_property_fields() == 0) return; 6099 6100 // Nonzero counter is a leftover from the previous attempt interrupted 6101 // by GC, keep it. 6102 if (construction_count() == 0) { 6103 set_construction_count(kGenerousAllocationCount); 6104 } 6105 set_initial_map(map); 6106 Builtins* builtins = map->heap()->isolate()->builtins(); 6107 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric), 6108 construct_stub()); 6109 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown)); 6110 } 6111 6112 6113 // Called from GC, hence reinterpret_cast and unchecked accessors. 6114 void SharedFunctionInfo::DetachInitialMap() { 6115 Map* map = reinterpret_cast<Map*>(initial_map()); 6116 6117 // Make the map remember to restore the link if it survives the GC. 6118 map->set_bit_field2( 6119 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo)); 6120 6121 // Undo state changes made by StartInobjectTracking (except the 6122 // construction_count). This way if the initial map does not survive the GC 6123 // then StartInobjectTracking will be called again the next time the 6124 // constructor is called. The countdown will continue and (possibly after 6125 // several more GCs) CompleteInobjectSlackTracking will eventually be called. 6126 set_initial_map(map->heap()->raw_unchecked_undefined_value()); 6127 Builtins* builtins = map->heap()->isolate()->builtins(); 6128 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), 6129 *RawField(this, kConstructStubOffset)); 6130 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); 6131 // It is safe to clear the flag: it will be set again if the map is live. 6132 set_live_objects_may_exist(false); 6133 } 6134 6135 6136 // Called from GC, hence reinterpret_cast and unchecked accessors. 6137 void SharedFunctionInfo::AttachInitialMap(Map* map) { 6138 map->set_bit_field2( 6139 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo)); 6140 6141 // Resume inobject slack tracking. 6142 set_initial_map(map); 6143 Builtins* builtins = map->heap()->isolate()->builtins(); 6144 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric), 6145 *RawField(this, kConstructStubOffset)); 6146 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown)); 6147 // The map survived the gc, so there may be objects referencing it. 6148 set_live_objects_may_exist(true); 6149 } 6150 6151 6152 static void GetMinInobjectSlack(Map* map, void* data) { 6153 int slack = map->unused_property_fields(); 6154 if (*reinterpret_cast<int*>(data) > slack) { 6155 *reinterpret_cast<int*>(data) = slack; 6156 } 6157 } 6158 6159 6160 static void ShrinkInstanceSize(Map* map, void* data) { 6161 int slack = *reinterpret_cast<int*>(data); 6162 map->set_inobject_properties(map->inobject_properties() - slack); 6163 map->set_unused_property_fields(map->unused_property_fields() - slack); 6164 map->set_instance_size(map->instance_size() - slack * kPointerSize); 6165 6166 // Visitor id might depend on the instance size, recalculate it. 6167 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map)); 6168 } 6169 6170 6171 void SharedFunctionInfo::CompleteInobjectSlackTracking() { 6172 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress()); 6173 Map* map = Map::cast(initial_map()); 6174 6175 Heap* heap = map->heap(); 6176 set_initial_map(heap->undefined_value()); 6177 Builtins* builtins = heap->isolate()->builtins(); 6178 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), 6179 construct_stub()); 6180 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); 6181 6182 int slack = map->unused_property_fields(); 6183 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack); 6184 if (slack != 0) { 6185 // Resize the initial map and all maps in its transition tree. 6186 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack); 6187 // Give the correct expected_nof_properties to initial maps created later. 6188 ASSERT(expected_nof_properties() >= slack); 6189 set_expected_nof_properties(expected_nof_properties() - slack); 6190 } 6191 } 6192 6193 6194 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { 6195 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); 6196 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 6197 Object* old_target = target; 6198 VisitPointer(&target); 6199 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target. 6200 } 6201 6202 6203 void ObjectVisitor::VisitCodeEntry(Address entry_address) { 6204 Object* code = Code::GetObjectFromEntryAddress(entry_address); 6205 Object* old_code = code; 6206 VisitPointer(&code); 6207 if (code != old_code) { 6208 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry(); 6209 } 6210 } 6211 6212 6213 void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) { 6214 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL); 6215 Object* cell = rinfo->target_cell(); 6216 Object* old_cell = cell; 6217 VisitPointer(&cell); 6218 if (cell != old_cell) { 6219 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell)); 6220 } 6221 } 6222 6223 6224 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) { 6225 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && 6226 rinfo->IsPatchedReturnSequence()) || 6227 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 6228 rinfo->IsPatchedDebugBreakSlotSequence())); 6229 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); 6230 Object* old_target = target; 6231 VisitPointer(&target); 6232 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target. 6233 } 6234 6235 6236 void Code::InvalidateRelocation() { 6237 set_relocation_info(heap()->empty_byte_array()); 6238 } 6239 6240 6241 void Code::Relocate(intptr_t delta) { 6242 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) { 6243 it.rinfo()->apply(delta); 6244 } 6245 CPU::FlushICache(instruction_start(), instruction_size()); 6246 } 6247 6248 6249 void Code::CopyFrom(const CodeDesc& desc) { 6250 // copy code 6251 memmove(instruction_start(), desc.buffer, desc.instr_size); 6252 6253 // copy reloc info 6254 memmove(relocation_start(), 6255 desc.buffer + desc.buffer_size - desc.reloc_size, 6256 desc.reloc_size); 6257 6258 // unbox handles and relocate 6259 intptr_t delta = instruction_start() - desc.buffer; 6260 int mode_mask = RelocInfo::kCodeTargetMask | 6261 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 6262 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) | 6263 RelocInfo::kApplyMask; 6264 Assembler* origin = desc.origin; // Needed to find target_object on X64. 6265 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 6266 RelocInfo::Mode mode = it.rinfo()->rmode(); 6267 if (mode == RelocInfo::EMBEDDED_OBJECT) { 6268 Handle<Object> p = it.rinfo()->target_object_handle(origin); 6269 it.rinfo()->set_target_object(*p); 6270 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) { 6271 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle(); 6272 it.rinfo()->set_target_cell(*cell); 6273 } else if (RelocInfo::IsCodeTarget(mode)) { 6274 // rewrite code handles in inline cache targets to direct 6275 // pointers to the first instruction in the code object 6276 Handle<Object> p = it.rinfo()->target_object_handle(origin); 6277 Code* code = Code::cast(*p); 6278 it.rinfo()->set_target_address(code->instruction_start()); 6279 } else { 6280 it.rinfo()->apply(delta); 6281 } 6282 } 6283 CPU::FlushICache(instruction_start(), instruction_size()); 6284 } 6285 6286 6287 // Locate the source position which is closest to the address in the code. This 6288 // is using the source position information embedded in the relocation info. 6289 // The position returned is relative to the beginning of the script where the 6290 // source for this function is found. 6291 int Code::SourcePosition(Address pc) { 6292 int distance = kMaxInt; 6293 int position = RelocInfo::kNoPosition; // Initially no position found. 6294 // Run through all the relocation info to find the best matching source 6295 // position. All the code needs to be considered as the sequence of the 6296 // instructions in the code does not necessarily follow the same order as the 6297 // source. 6298 RelocIterator it(this, RelocInfo::kPositionMask); 6299 while (!it.done()) { 6300 // Only look at positions after the current pc. 6301 if (it.rinfo()->pc() < pc) { 6302 // Get position and distance. 6303 6304 int dist = static_cast<int>(pc - it.rinfo()->pc()); 6305 int pos = static_cast<int>(it.rinfo()->data()); 6306 // If this position is closer than the current candidate or if it has the 6307 // same distance as the current candidate and the position is higher then 6308 // this position is the new candidate. 6309 if ((dist < distance) || 6310 (dist == distance && pos > position)) { 6311 position = pos; 6312 distance = dist; 6313 } 6314 } 6315 it.next(); 6316 } 6317 return position; 6318 } 6319 6320 6321 // Same as Code::SourcePosition above except it only looks for statement 6322 // positions. 6323 int Code::SourceStatementPosition(Address pc) { 6324 // First find the position as close as possible using all position 6325 // information. 6326 int position = SourcePosition(pc); 6327 // Now find the closest statement position before the position. 6328 int statement_position = 0; 6329 RelocIterator it(this, RelocInfo::kPositionMask); 6330 while (!it.done()) { 6331 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) { 6332 int p = static_cast<int>(it.rinfo()->data()); 6333 if (statement_position < p && p <= position) { 6334 statement_position = p; 6335 } 6336 } 6337 it.next(); 6338 } 6339 return statement_position; 6340 } 6341 6342 6343 SafepointEntry Code::GetSafepointEntry(Address pc) { 6344 SafepointTable table(this); 6345 return table.FindEntry(pc); 6346 } 6347 6348 6349 void Code::SetNoStackCheckTable() { 6350 // Indicate the absence of a stack-check table by a table start after the 6351 // end of the instructions. Table start must be aligned, so round up. 6352 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize)); 6353 } 6354 6355 6356 Map* Code::FindFirstMap() { 6357 ASSERT(is_inline_cache_stub()); 6358 AssertNoAllocation no_allocation; 6359 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 6360 for (RelocIterator it(this, mask); !it.done(); it.next()) { 6361 RelocInfo* info = it.rinfo(); 6362 Object* object = info->target_object(); 6363 if (object->IsMap()) return Map::cast(object); 6364 } 6365 return NULL; 6366 } 6367 6368 6369 #ifdef ENABLE_DISASSEMBLER 6370 6371 #ifdef OBJECT_PRINT 6372 6373 void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { 6374 disasm::NameConverter converter; 6375 int deopt_count = DeoptCount(); 6376 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count); 6377 if (0 == deopt_count) return; 6378 6379 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands"); 6380 for (int i = 0; i < deopt_count; i++) { 6381 int command_count = 0; 6382 PrintF(out, "%6d %6d %6d", 6383 i, AstId(i)->value(), ArgumentsStackHeight(i)->value()); 6384 int translation_index = TranslationIndex(i)->value(); 6385 TranslationIterator iterator(TranslationByteArray(), translation_index); 6386 Translation::Opcode opcode = 6387 static_cast<Translation::Opcode>(iterator.Next()); 6388 ASSERT(Translation::BEGIN == opcode); 6389 int frame_count = iterator.Next(); 6390 if (FLAG_print_code_verbose) { 6391 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode), 6392 frame_count); 6393 } 6394 6395 for (int i = 0; i < frame_count; ++i) { 6396 opcode = static_cast<Translation::Opcode>(iterator.Next()); 6397 ASSERT(Translation::FRAME == opcode); 6398 int ast_id = iterator.Next(); 6399 int function_id = iterator.Next(); 6400 JSFunction* function = 6401 JSFunction::cast(LiteralArray()->get(function_id)); 6402 unsigned height = iterator.Next(); 6403 if (FLAG_print_code_verbose) { 6404 PrintF(out, "%24s %s {ast_id=%d, function=", 6405 "", Translation::StringFor(opcode), ast_id); 6406 function->PrintName(out); 6407 PrintF(out, ", height=%u}\n", height); 6408 } 6409 6410 // Size of translation is height plus all incoming arguments including 6411 // receiver. 6412 int size = height + function->shared()->formal_parameter_count() + 1; 6413 command_count += size; 6414 for (int j = 0; j < size; ++j) { 6415 opcode = static_cast<Translation::Opcode>(iterator.Next()); 6416 if (FLAG_print_code_verbose) { 6417 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode)); 6418 } 6419 6420 if (opcode == Translation::DUPLICATE) { 6421 opcode = static_cast<Translation::Opcode>(iterator.Next()); 6422 if (FLAG_print_code_verbose) { 6423 PrintF(out, "%s ", Translation::StringFor(opcode)); 6424 } 6425 --j; // Two commands share the same frame index. 6426 } 6427 6428 switch (opcode) { 6429 case Translation::BEGIN: 6430 case Translation::FRAME: 6431 case Translation::DUPLICATE: 6432 UNREACHABLE(); 6433 break; 6434 6435 case Translation::REGISTER: { 6436 int reg_code = iterator.Next(); 6437 if (FLAG_print_code_verbose) { 6438 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code)); 6439 } 6440 break; 6441 } 6442 6443 case Translation::INT32_REGISTER: { 6444 int reg_code = iterator.Next(); 6445 if (FLAG_print_code_verbose) { 6446 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code)); 6447 } 6448 break; 6449 } 6450 6451 case Translation::DOUBLE_REGISTER: { 6452 int reg_code = iterator.Next(); 6453 if (FLAG_print_code_verbose) { 6454 PrintF(out, "{input=%s}", 6455 DoubleRegister::AllocationIndexToString(reg_code)); 6456 } 6457 break; 6458 } 6459 6460 case Translation::STACK_SLOT: { 6461 int input_slot_index = iterator.Next(); 6462 if (FLAG_print_code_verbose) { 6463 PrintF(out, "{input=%d}", input_slot_index); 6464 } 6465 break; 6466 } 6467 6468 case Translation::INT32_STACK_SLOT: { 6469 int input_slot_index = iterator.Next(); 6470 if (FLAG_print_code_verbose) { 6471 PrintF(out, "{input=%d}", input_slot_index); 6472 } 6473 break; 6474 } 6475 6476 case Translation::DOUBLE_STACK_SLOT: { 6477 int input_slot_index = iterator.Next(); 6478 if (FLAG_print_code_verbose) { 6479 PrintF(out, "{input=%d}", input_slot_index); 6480 } 6481 break; 6482 } 6483 6484 case Translation::LITERAL: { 6485 unsigned literal_index = iterator.Next(); 6486 if (FLAG_print_code_verbose) { 6487 PrintF(out, "{literal_id=%u}", literal_index); 6488 } 6489 break; 6490 } 6491 6492 case Translation::ARGUMENTS_OBJECT: 6493 break; 6494 } 6495 if (FLAG_print_code_verbose) PrintF(out, "\n"); 6496 } 6497 } 6498 if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count); 6499 } 6500 } 6501 6502 6503 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) { 6504 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n", 6505 this->DeoptPoints()); 6506 if (this->DeoptPoints() == 0) return; 6507 6508 PrintF("%6s %8s %s\n", "ast id", "pc", "state"); 6509 for (int i = 0; i < this->DeoptPoints(); i++) { 6510 int pc_and_state = this->PcAndState(i)->value(); 6511 PrintF("%6d %8d %s\n", 6512 this->AstId(i)->value(), 6513 FullCodeGenerator::PcField::decode(pc_and_state), 6514 FullCodeGenerator::State2String( 6515 FullCodeGenerator::StateField::decode(pc_and_state))); 6516 } 6517 } 6518 6519 #endif 6520 6521 6522 // Identify kind of code. 6523 const char* Code::Kind2String(Kind kind) { 6524 switch (kind) { 6525 case FUNCTION: return "FUNCTION"; 6526 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION"; 6527 case STUB: return "STUB"; 6528 case BUILTIN: return "BUILTIN"; 6529 case LOAD_IC: return "LOAD_IC"; 6530 case KEYED_LOAD_IC: return "KEYED_LOAD_IC"; 6531 case KEYED_EXTERNAL_ARRAY_LOAD_IC: return "KEYED_EXTERNAL_ARRAY_LOAD_IC"; 6532 case STORE_IC: return "STORE_IC"; 6533 case KEYED_STORE_IC: return "KEYED_STORE_IC"; 6534 case KEYED_EXTERNAL_ARRAY_STORE_IC: return "KEYED_EXTERNAL_ARRAY_STORE_IC"; 6535 case CALL_IC: return "CALL_IC"; 6536 case KEYED_CALL_IC: return "KEYED_CALL_IC"; 6537 case TYPE_RECORDING_BINARY_OP_IC: return "TYPE_RECORDING_BINARY_OP_IC"; 6538 case COMPARE_IC: return "COMPARE_IC"; 6539 } 6540 UNREACHABLE(); 6541 return NULL; 6542 } 6543 6544 6545 const char* Code::ICState2String(InlineCacheState state) { 6546 switch (state) { 6547 case UNINITIALIZED: return "UNINITIALIZED"; 6548 case PREMONOMORPHIC: return "PREMONOMORPHIC"; 6549 case MONOMORPHIC: return "MONOMORPHIC"; 6550 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE"; 6551 case MEGAMORPHIC: return "MEGAMORPHIC"; 6552 case DEBUG_BREAK: return "DEBUG_BREAK"; 6553 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN"; 6554 } 6555 UNREACHABLE(); 6556 return NULL; 6557 } 6558 6559 6560 const char* Code::PropertyType2String(PropertyType type) { 6561 switch (type) { 6562 case NORMAL: return "NORMAL"; 6563 case FIELD: return "FIELD"; 6564 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION"; 6565 case CALLBACKS: return "CALLBACKS"; 6566 case INTERCEPTOR: return "INTERCEPTOR"; 6567 case MAP_TRANSITION: return "MAP_TRANSITION"; 6568 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION"; 6569 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION"; 6570 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR"; 6571 } 6572 UNREACHABLE(); 6573 return NULL; 6574 } 6575 6576 6577 void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) { 6578 const char* name = NULL; 6579 switch (kind) { 6580 case CALL_IC: 6581 if (extra == STRING_INDEX_OUT_OF_BOUNDS) { 6582 name = "STRING_INDEX_OUT_OF_BOUNDS"; 6583 } 6584 break; 6585 case STORE_IC: 6586 case KEYED_STORE_IC: 6587 if (extra == kStrictMode) { 6588 name = "STRICT"; 6589 } 6590 break; 6591 default: 6592 break; 6593 } 6594 if (name != NULL) { 6595 PrintF(out, "extra_ic_state = %s\n", name); 6596 } else { 6597 PrintF(out, "etra_ic_state = %d\n", extra); 6598 } 6599 } 6600 6601 6602 void Code::Disassemble(const char* name, FILE* out) { 6603 PrintF(out, "kind = %s\n", Kind2String(kind())); 6604 if (is_inline_cache_stub()) { 6605 PrintF(out, "ic_state = %s\n", ICState2String(ic_state())); 6606 PrintExtraICState(out, kind(), extra_ic_state()); 6607 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP); 6608 if (ic_state() == MONOMORPHIC) { 6609 PrintF(out, "type = %s\n", PropertyType2String(type())); 6610 } 6611 } 6612 if ((name != NULL) && (name[0] != '\0')) { 6613 PrintF(out, "name = %s\n", name); 6614 } 6615 if (kind() == OPTIMIZED_FUNCTION) { 6616 PrintF(out, "stack_slots = %d\n", stack_slots()); 6617 } 6618 6619 PrintF(out, "Instructions (size = %d)\n", instruction_size()); 6620 Disassembler::Decode(out, this); 6621 PrintF(out, "\n"); 6622 6623 #ifdef DEBUG 6624 if (kind() == FUNCTION) { 6625 DeoptimizationOutputData* data = 6626 DeoptimizationOutputData::cast(this->deoptimization_data()); 6627 data->DeoptimizationOutputDataPrint(out); 6628 } else if (kind() == OPTIMIZED_FUNCTION) { 6629 DeoptimizationInputData* data = 6630 DeoptimizationInputData::cast(this->deoptimization_data()); 6631 data->DeoptimizationInputDataPrint(out); 6632 } 6633 PrintF("\n"); 6634 #endif 6635 6636 if (kind() == OPTIMIZED_FUNCTION) { 6637 SafepointTable table(this); 6638 PrintF(out, "Safepoints (size = %u)\n", table.size()); 6639 for (unsigned i = 0; i < table.length(); i++) { 6640 unsigned pc_offset = table.GetPcOffset(i); 6641 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset); 6642 table.PrintEntry(i); 6643 PrintF(out, " (sp -> fp)"); 6644 SafepointEntry entry = table.GetEntry(i); 6645 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) { 6646 PrintF(out, " %6d", entry.deoptimization_index()); 6647 } else { 6648 PrintF(out, " <none>"); 6649 } 6650 if (entry.argument_count() > 0) { 6651 PrintF(out, " argc: %d", entry.argument_count()); 6652 } 6653 PrintF(out, "\n"); 6654 } 6655 PrintF(out, "\n"); 6656 } else if (kind() == FUNCTION) { 6657 unsigned offset = stack_check_table_offset(); 6658 // If there is no stack check table, the "table start" will at or after 6659 // (due to alignment) the end of the instruction stream. 6660 if (static_cast<int>(offset) < instruction_size()) { 6661 unsigned* address = 6662 reinterpret_cast<unsigned*>(instruction_start() + offset); 6663 unsigned length = address[0]; 6664 PrintF(out, "Stack checks (size = %u)\n", length); 6665 PrintF(out, "ast_id pc_offset\n"); 6666 for (unsigned i = 0; i < length; ++i) { 6667 unsigned index = (2 * i) + 1; 6668 PrintF(out, "%6u %9u\n", address[index], address[index + 1]); 6669 } 6670 PrintF(out, "\n"); 6671 } 6672 } 6673 6674 PrintF("RelocInfo (size = %d)\n", relocation_size()); 6675 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out); 6676 PrintF(out, "\n"); 6677 } 6678 #endif // ENABLE_DISASSEMBLER 6679 6680 6681 MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, 6682 int length) { 6683 Heap* heap = GetHeap(); 6684 // We should never end in here with a pixel or external array. 6685 ASSERT(!HasExternalArrayElements()); 6686 6687 Object* obj; 6688 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity); 6689 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6690 } 6691 FixedArray* elems = FixedArray::cast(obj); 6692 6693 { MaybeObject* maybe_obj = map()->GetFastElementsMap(); 6694 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6695 } 6696 Map* new_map = Map::cast(obj); 6697 6698 AssertNoAllocation no_gc; 6699 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); 6700 switch (GetElementsKind()) { 6701 case FAST_ELEMENTS: { 6702 FixedArray* old_elements = FixedArray::cast(elements()); 6703 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); 6704 // Fill out the new array with this content and array holes. 6705 for (uint32_t i = 0; i < old_length; i++) { 6706 elems->set(i, old_elements->get(i), mode); 6707 } 6708 break; 6709 } 6710 case DICTIONARY_ELEMENTS: { 6711 NumberDictionary* dictionary = NumberDictionary::cast(elements()); 6712 for (int i = 0; i < dictionary->Capacity(); i++) { 6713 Object* key = dictionary->KeyAt(i); 6714 if (key->IsNumber()) { 6715 uint32_t entry = static_cast<uint32_t>(key->Number()); 6716 elems->set(entry, dictionary->ValueAt(i), mode); 6717 } 6718 } 6719 break; 6720 } 6721 default: 6722 UNREACHABLE(); 6723 break; 6724 } 6725 6726 set_map(new_map); 6727 set_elements(elems); 6728 6729 if (IsJSArray()) { 6730 JSArray::cast(this)->set_length(Smi::FromInt(length)); 6731 } 6732 6733 return this; 6734 } 6735 6736 6737 MaybeObject* JSObject::SetSlowElements(Object* len) { 6738 // We should never end in here with a pixel or external array. 6739 ASSERT(!HasExternalArrayElements()); 6740 6741 uint32_t new_length = static_cast<uint32_t>(len->Number()); 6742 6743 switch (GetElementsKind()) { 6744 case FAST_ELEMENTS: { 6745 // Make sure we never try to shrink dense arrays into sparse arrays. 6746 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= 6747 new_length); 6748 Object* obj; 6749 { MaybeObject* maybe_obj = NormalizeElements(); 6750 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6751 } 6752 6753 // Update length for JSArrays. 6754 if (IsJSArray()) JSArray::cast(this)->set_length(len); 6755 break; 6756 } 6757 case DICTIONARY_ELEMENTS: { 6758 if (IsJSArray()) { 6759 uint32_t old_length = 6760 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); 6761 element_dictionary()->RemoveNumberEntries(new_length, old_length), 6762 JSArray::cast(this)->set_length(len); 6763 } 6764 break; 6765 } 6766 default: 6767 UNREACHABLE(); 6768 break; 6769 } 6770 return this; 6771 } 6772 6773 6774 MaybeObject* JSArray::Initialize(int capacity) { 6775 Heap* heap = GetHeap(); 6776 ASSERT(capacity >= 0); 6777 set_length(Smi::FromInt(0)); 6778 FixedArray* new_elements; 6779 if (capacity == 0) { 6780 new_elements = heap->empty_fixed_array(); 6781 } else { 6782 Object* obj; 6783 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity); 6784 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6785 } 6786 new_elements = FixedArray::cast(obj); 6787 } 6788 set_elements(new_elements); 6789 return this; 6790 } 6791 6792 6793 void JSArray::Expand(int required_size) { 6794 Handle<JSArray> self(this); 6795 Handle<FixedArray> old_backing(FixedArray::cast(elements())); 6796 int old_size = old_backing->length(); 6797 int new_size = required_size > old_size ? required_size : old_size; 6798 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size); 6799 // Can't use this any more now because we may have had a GC! 6800 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); 6801 self->SetContent(*new_backing); 6802 } 6803 6804 6805 static Failure* ArrayLengthRangeError(Heap* heap) { 6806 HandleScope scope; 6807 return heap->isolate()->Throw( 6808 *FACTORY->NewRangeError("invalid_array_length", 6809 HandleVector<Object>(NULL, 0))); 6810 } 6811 6812 6813 MaybeObject* JSObject::SetElementsLength(Object* len) { 6814 // We should never end in here with a pixel or external array. 6815 ASSERT(AllowsSetElementsLength()); 6816 6817 MaybeObject* maybe_smi_length = len->ToSmi(); 6818 Object* smi_length = Smi::FromInt(0); 6819 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) { 6820 const int value = Smi::cast(smi_length)->value(); 6821 if (value < 0) return ArrayLengthRangeError(GetHeap()); 6822 switch (GetElementsKind()) { 6823 case FAST_ELEMENTS: { 6824 int old_capacity = FixedArray::cast(elements())->length(); 6825 if (value <= old_capacity) { 6826 if (IsJSArray()) { 6827 Object* obj; 6828 { MaybeObject* maybe_obj = EnsureWritableFastElements(); 6829 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6830 } 6831 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); 6832 // NOTE: We may be able to optimize this by removing the 6833 // last part of the elements backing storage array and 6834 // setting the capacity to the new size. 6835 for (int i = value; i < old_length; i++) { 6836 FixedArray::cast(elements())->set_the_hole(i); 6837 } 6838 JSArray::cast(this)->set_length(Smi::cast(smi_length)); 6839 } 6840 return this; 6841 } 6842 int min = NewElementsCapacity(old_capacity); 6843 int new_capacity = value > min ? value : min; 6844 if (new_capacity <= kMaxFastElementsLength || 6845 !ShouldConvertToSlowElements(new_capacity)) { 6846 Object* obj; 6847 { MaybeObject* maybe_obj = 6848 SetFastElementsCapacityAndLength(new_capacity, value); 6849 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6850 } 6851 return this; 6852 } 6853 break; 6854 } 6855 case DICTIONARY_ELEMENTS: { 6856 if (IsJSArray()) { 6857 if (value == 0) { 6858 // If the length of a slow array is reset to zero, we clear 6859 // the array and flush backing storage. This has the added 6860 // benefit that the array returns to fast mode. 6861 Object* obj; 6862 { MaybeObject* maybe_obj = ResetElements(); 6863 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6864 } 6865 } else { 6866 // Remove deleted elements. 6867 uint32_t old_length = 6868 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); 6869 element_dictionary()->RemoveNumberEntries(value, old_length); 6870 } 6871 JSArray::cast(this)->set_length(Smi::cast(smi_length)); 6872 } 6873 return this; 6874 } 6875 default: 6876 UNREACHABLE(); 6877 break; 6878 } 6879 } 6880 6881 // General slow case. 6882 if (len->IsNumber()) { 6883 uint32_t length; 6884 if (len->ToArrayIndex(&length)) { 6885 return SetSlowElements(len); 6886 } else { 6887 return ArrayLengthRangeError(GetHeap()); 6888 } 6889 } 6890 6891 // len is not a number so make the array size one and 6892 // set only element to len. 6893 Object* obj; 6894 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1); 6895 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6896 } 6897 FixedArray::cast(obj)->set(0, len); 6898 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); 6899 set_elements(FixedArray::cast(obj)); 6900 return this; 6901 } 6902 6903 6904 Object* Map::GetPrototypeTransition(Object* prototype) { 6905 FixedArray* cache = prototype_transitions(); 6906 int capacity = cache->length(); 6907 if (capacity == 0) return NULL; 6908 int finger = Smi::cast(cache->get(0))->value(); 6909 for (int i = 1; i < finger; i += 2) { 6910 if (cache->get(i) == prototype) return cache->get(i + 1); 6911 } 6912 return NULL; 6913 } 6914 6915 6916 MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { 6917 // Don't cache prototype transition if this map is shared. 6918 if (is_shared() || !FLAG_cache_prototype_transitions) return this; 6919 6920 FixedArray* cache = prototype_transitions(); 6921 6922 int capacity = cache->length(); 6923 6924 int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value(); 6925 6926 if (finger >= capacity) { 6927 if (capacity > kMaxCachedPrototypeTransitions) return this; 6928 6929 FixedArray* new_cache; 6930 { MaybeObject* maybe_cache = heap()->AllocateFixedArray(finger * 2 + 1); 6931 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache; 6932 } 6933 6934 for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i)); 6935 cache = new_cache; 6936 set_prototype_transitions(cache); 6937 } 6938 6939 cache->set(finger, prototype); 6940 cache->set(finger + 1, map); 6941 cache->set(0, Smi::FromInt(finger + 2)); 6942 6943 return cache; 6944 } 6945 6946 6947 MaybeObject* JSObject::SetPrototype(Object* value, 6948 bool skip_hidden_prototypes) { 6949 Heap* heap = GetHeap(); 6950 // Silently ignore the change if value is not a JSObject or null. 6951 // SpiderMonkey behaves this way. 6952 if (!value->IsJSObject() && !value->IsNull()) return value; 6953 6954 // From 8.6.2 Object Internal Methods 6955 // ... 6956 // In addition, if [[Extensible]] is false the value of the [[Class]] and 6957 // [[Prototype]] internal properties of the object may not be modified. 6958 // ... 6959 // Implementation specific extensions that modify [[Class]], [[Prototype]] 6960 // or [[Extensible]] must not violate the invariants defined in the preceding 6961 // paragraph. 6962 if (!this->map()->is_extensible()) { 6963 HandleScope scope; 6964 Handle<Object> handle(this, heap->isolate()); 6965 return heap->isolate()->Throw( 6966 *FACTORY->NewTypeError("non_extensible_proto", 6967 HandleVector<Object>(&handle, 1))); 6968 } 6969 6970 // Before we can set the prototype we need to be sure 6971 // prototype cycles are prevented. 6972 // It is sufficient to validate that the receiver is not in the new prototype 6973 // chain. 6974 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) { 6975 if (JSObject::cast(pt) == this) { 6976 // Cycle detected. 6977 HandleScope scope; 6978 return heap->isolate()->Throw( 6979 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0))); 6980 } 6981 } 6982 6983 JSObject* real_receiver = this; 6984 6985 if (skip_hidden_prototypes) { 6986 // Find the first object in the chain whose prototype object is not 6987 // hidden and set the new prototype on that object. 6988 Object* current_proto = real_receiver->GetPrototype(); 6989 while (current_proto->IsJSObject() && 6990 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { 6991 real_receiver = JSObject::cast(current_proto); 6992 current_proto = current_proto->GetPrototype(); 6993 } 6994 } 6995 6996 // Set the new prototype of the object. 6997 Map* map = real_receiver->map(); 6998 6999 // Nothing to do if prototype is already set. 7000 if (map->prototype() == value) return value; 7001 7002 Object* new_map = map->GetPrototypeTransition(value); 7003 if (new_map == NULL) { 7004 { MaybeObject* maybe_new_map = map->CopyDropTransitions(); 7005 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 7006 } 7007 7008 { MaybeObject* maybe_new_cache = 7009 map->PutPrototypeTransition(value, Map::cast(new_map)); 7010 if (maybe_new_cache->IsFailure()) return maybe_new_cache; 7011 } 7012 7013 Map::cast(new_map)->set_prototype(value); 7014 } 7015 ASSERT(Map::cast(new_map)->prototype() == value); 7016 real_receiver->set_map(Map::cast(new_map)); 7017 7018 heap->ClearInstanceofCache(); 7019 7020 return value; 7021 } 7022 7023 7024 bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) { 7025 switch (GetElementsKind()) { 7026 case FAST_ELEMENTS: { 7027 uint32_t length = IsJSArray() ? 7028 static_cast<uint32_t> 7029 (Smi::cast(JSArray::cast(this)->length())->value()) : 7030 static_cast<uint32_t>(FixedArray::cast(elements())->length()); 7031 if ((index < length) && 7032 !FixedArray::cast(elements())->get(index)->IsTheHole()) { 7033 return true; 7034 } 7035 break; 7036 } 7037 case EXTERNAL_PIXEL_ELEMENTS: { 7038 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); 7039 if (index < static_cast<uint32_t>(pixels->length())) { 7040 return true; 7041 } 7042 break; 7043 } 7044 case EXTERNAL_BYTE_ELEMENTS: 7045 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 7046 case EXTERNAL_SHORT_ELEMENTS: 7047 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 7048 case EXTERNAL_INT_ELEMENTS: 7049 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 7050 case EXTERNAL_FLOAT_ELEMENTS: { 7051 ExternalArray* array = ExternalArray::cast(elements()); 7052 if (index < static_cast<uint32_t>(array->length())) { 7053 return true; 7054 } 7055 break; 7056 } 7057 case DICTIONARY_ELEMENTS: { 7058 if (element_dictionary()->FindEntry(index) 7059 != NumberDictionary::kNotFound) { 7060 return true; 7061 } 7062 break; 7063 } 7064 default: 7065 UNREACHABLE(); 7066 break; 7067 } 7068 7069 // Handle [] on String objects. 7070 if (this->IsStringObjectWithCharacterAt(index)) return true; 7071 7072 Object* pt = GetPrototype(); 7073 if (pt->IsNull()) return false; 7074 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); 7075 } 7076 7077 7078 bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) { 7079 Isolate* isolate = GetIsolate(); 7080 // Make sure that the top context does not change when doing 7081 // callbacks or interceptor calls. 7082 AssertNoContextChange ncc; 7083 HandleScope scope(isolate); 7084 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); 7085 Handle<JSObject> receiver_handle(receiver); 7086 Handle<JSObject> holder_handle(this); 7087 CustomArguments args(isolate, interceptor->data(), receiver, this); 7088 v8::AccessorInfo info(args.end()); 7089 if (!interceptor->query()->IsUndefined()) { 7090 v8::IndexedPropertyQuery query = 7091 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query()); 7092 LOG(isolate, 7093 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); 7094 v8::Handle<v8::Integer> result; 7095 { 7096 // Leaving JavaScript. 7097 VMState state(isolate, EXTERNAL); 7098 result = query(index, info); 7099 } 7100 if (!result.IsEmpty()) { 7101 ASSERT(result->IsInt32()); 7102 return true; // absence of property is signaled by empty handle. 7103 } 7104 } else if (!interceptor->getter()->IsUndefined()) { 7105 v8::IndexedPropertyGetter getter = 7106 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); 7107 LOG(isolate, 7108 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index)); 7109 v8::Handle<v8::Value> result; 7110 { 7111 // Leaving JavaScript. 7112 VMState state(isolate, EXTERNAL); 7113 result = getter(index, info); 7114 } 7115 if (!result.IsEmpty()) return true; 7116 } 7117 return holder_handle->HasElementPostInterceptor(*receiver_handle, index); 7118 } 7119 7120 7121 JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) { 7122 // Check access rights if needed. 7123 if (IsAccessCheckNeeded()) { 7124 Heap* heap = GetHeap(); 7125 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { 7126 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); 7127 return UNDEFINED_ELEMENT; 7128 } 7129 } 7130 7131 if (IsJSGlobalProxy()) { 7132 Object* proto = GetPrototype(); 7133 if (proto->IsNull()) return UNDEFINED_ELEMENT; 7134 ASSERT(proto->IsJSGlobalObject()); 7135 return JSObject::cast(proto)->HasLocalElement(index); 7136 } 7137 7138 // Check for lookup interceptor 7139 if (HasIndexedInterceptor()) { 7140 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT 7141 : UNDEFINED_ELEMENT; 7142 } 7143 7144 // Handle [] on String objects. 7145 if (this->IsStringObjectWithCharacterAt(index)) { 7146 return STRING_CHARACTER_ELEMENT; 7147 } 7148 7149 switch (GetElementsKind()) { 7150 case FAST_ELEMENTS: { 7151 uint32_t length = IsJSArray() ? 7152 static_cast<uint32_t> 7153 (Smi::cast(JSArray::cast(this)->length())->value()) : 7154 static_cast<uint32_t>(FixedArray::cast(elements())->length()); 7155 if ((index < length) && 7156 !FixedArray::cast(elements())->get(index)->IsTheHole()) { 7157 return FAST_ELEMENT; 7158 } 7159 break; 7160 } 7161 case EXTERNAL_PIXEL_ELEMENTS: { 7162 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); 7163 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT; 7164 break; 7165 } 7166 case EXTERNAL_BYTE_ELEMENTS: 7167 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 7168 case EXTERNAL_SHORT_ELEMENTS: 7169 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 7170 case EXTERNAL_INT_ELEMENTS: 7171 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 7172 case EXTERNAL_FLOAT_ELEMENTS: { 7173 ExternalArray* array = ExternalArray::cast(elements()); 7174 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT; 7175 break; 7176 } 7177 case DICTIONARY_ELEMENTS: { 7178 if (element_dictionary()->FindEntry(index) != 7179 NumberDictionary::kNotFound) { 7180 return DICTIONARY_ELEMENT; 7181 } 7182 break; 7183 } 7184 default: 7185 UNREACHABLE(); 7186 break; 7187 } 7188 7189 return UNDEFINED_ELEMENT; 7190 } 7191 7192 7193 bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) { 7194 // Check access rights if needed. 7195 if (IsAccessCheckNeeded()) { 7196 Heap* heap = GetHeap(); 7197 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { 7198 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); 7199 return false; 7200 } 7201 } 7202 7203 // Check for lookup interceptor 7204 if (HasIndexedInterceptor()) { 7205 return HasElementWithInterceptor(receiver, index); 7206 } 7207 7208 switch (GetElementsKind()) { 7209 case FAST_ELEMENTS: { 7210 uint32_t length = IsJSArray() ? 7211 static_cast<uint32_t> 7212 (Smi::cast(JSArray::cast(this)->length())->value()) : 7213 static_cast<uint32_t>(FixedArray::cast(elements())->length()); 7214 if ((index < length) && 7215 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; 7216 break; 7217 } 7218 case EXTERNAL_PIXEL_ELEMENTS: { 7219 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); 7220 if (index < static_cast<uint32_t>(pixels->length())) { 7221 return true; 7222 } 7223 break; 7224 } 7225 case EXTERNAL_BYTE_ELEMENTS: 7226 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 7227 case EXTERNAL_SHORT_ELEMENTS: 7228 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 7229 case EXTERNAL_INT_ELEMENTS: 7230 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 7231 case EXTERNAL_FLOAT_ELEMENTS: { 7232 ExternalArray* array = ExternalArray::cast(elements()); 7233 if (index < static_cast<uint32_t>(array->length())) { 7234 return true; 7235 } 7236 break; 7237 } 7238 case DICTIONARY_ELEMENTS: { 7239 if (element_dictionary()->FindEntry(index) 7240 != NumberDictionary::kNotFound) { 7241 return true; 7242 } 7243 break; 7244 } 7245 default: 7246 UNREACHABLE(); 7247 break; 7248 } 7249 7250 // Handle [] on String objects. 7251 if (this->IsStringObjectWithCharacterAt(index)) return true; 7252 7253 Object* pt = GetPrototype(); 7254 if (pt->IsNull()) return false; 7255 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); 7256 } 7257 7258 7259 MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index, 7260 Object* value, 7261 StrictModeFlag strict_mode, 7262 bool check_prototype) { 7263 Isolate* isolate = GetIsolate(); 7264 // Make sure that the top context does not change when doing 7265 // callbacks or interceptor calls. 7266 AssertNoContextChange ncc; 7267 HandleScope scope(isolate); 7268 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); 7269 Handle<JSObject> this_handle(this); 7270 Handle<Object> value_handle(value, isolate); 7271 if (!interceptor->setter()->IsUndefined()) { 7272 v8::IndexedPropertySetter setter = 7273 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter()); 7274 LOG(isolate, 7275 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index)); 7276 CustomArguments args(isolate, interceptor->data(), this, this); 7277 v8::AccessorInfo info(args.end()); 7278 v8::Handle<v8::Value> result; 7279 { 7280 // Leaving JavaScript. 7281 VMState state(isolate, EXTERNAL); 7282 result = setter(index, v8::Utils::ToLocal(value_handle), info); 7283 } 7284 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 7285 if (!result.IsEmpty()) return *value_handle; 7286 } 7287 MaybeObject* raw_result = 7288 this_handle->SetElementWithoutInterceptor(index, 7289 *value_handle, 7290 strict_mode, 7291 check_prototype); 7292 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 7293 return raw_result; 7294 } 7295 7296 7297 MaybeObject* JSObject::GetElementWithCallback(Object* receiver, 7298 Object* structure, 7299 uint32_t index, 7300 Object* holder) { 7301 Isolate* isolate = GetIsolate(); 7302 ASSERT(!structure->IsProxy()); 7303 7304 // api style callbacks. 7305 if (structure->IsAccessorInfo()) { 7306 AccessorInfo* data = AccessorInfo::cast(structure); 7307 Object* fun_obj = data->getter(); 7308 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); 7309 HandleScope scope(isolate); 7310 Handle<JSObject> self(JSObject::cast(receiver)); 7311 Handle<JSObject> holder_handle(JSObject::cast(holder)); 7312 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); 7313 Handle<String> key(isolate->factory()->NumberToString(number)); 7314 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key)); 7315 CustomArguments args(isolate, data->data(), *self, *holder_handle); 7316 v8::AccessorInfo info(args.end()); 7317 v8::Handle<v8::Value> result; 7318 { 7319 // Leaving JavaScript. 7320 VMState state(isolate, EXTERNAL); 7321 result = call_fun(v8::Utils::ToLocal(key), info); 7322 } 7323 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 7324 if (result.IsEmpty()) return isolate->heap()->undefined_value(); 7325 return *v8::Utils::OpenHandle(*result); 7326 } 7327 7328 // __defineGetter__ callback 7329 if (structure->IsFixedArray()) { 7330 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); 7331 if (getter->IsJSFunction()) { 7332 return Object::GetPropertyWithDefinedGetter(receiver, 7333 JSFunction::cast(getter)); 7334 } 7335 // Getter is not a function. 7336 return isolate->heap()->undefined_value(); 7337 } 7338 7339 UNREACHABLE(); 7340 return NULL; 7341 } 7342 7343 7344 MaybeObject* JSObject::SetElementWithCallback(Object* structure, 7345 uint32_t index, 7346 Object* value, 7347 JSObject* holder) { 7348 Isolate* isolate = GetIsolate(); 7349 HandleScope scope(isolate); 7350 7351 // We should never get here to initialize a const with the hole 7352 // value since a const declaration would conflict with the setter. 7353 ASSERT(!value->IsTheHole()); 7354 Handle<Object> value_handle(value, isolate); 7355 7356 // To accommodate both the old and the new api we switch on the 7357 // data structure used to store the callbacks. Eventually proxy 7358 // callbacks should be phased out. 7359 ASSERT(!structure->IsProxy()); 7360 7361 if (structure->IsAccessorInfo()) { 7362 // api style callbacks 7363 AccessorInfo* data = AccessorInfo::cast(structure); 7364 Object* call_obj = data->setter(); 7365 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj); 7366 if (call_fun == NULL) return value; 7367 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); 7368 Handle<String> key(isolate->factory()->NumberToString(number)); 7369 LOG(isolate, ApiNamedPropertyAccess("store", this, *key)); 7370 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder)); 7371 v8::AccessorInfo info(args.end()); 7372 { 7373 // Leaving JavaScript. 7374 VMState state(isolate, EXTERNAL); 7375 call_fun(v8::Utils::ToLocal(key), 7376 v8::Utils::ToLocal(value_handle), 7377 info); 7378 } 7379 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 7380 return *value_handle; 7381 } 7382 7383 if (structure->IsFixedArray()) { 7384 Object* setter = FixedArray::cast(structure)->get(kSetterIndex); 7385 if (setter->IsJSFunction()) { 7386 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); 7387 } else { 7388 Handle<Object> holder_handle(holder, isolate); 7389 Handle<Object> key(isolate->factory()->NewNumberFromUint(index)); 7390 Handle<Object> args[2] = { key, holder_handle }; 7391 return isolate->Throw( 7392 *isolate->factory()->NewTypeError("no_setter_in_callback", 7393 HandleVector(args, 2))); 7394 } 7395 } 7396 7397 UNREACHABLE(); 7398 return NULL; 7399 } 7400 7401 7402 // Adding n elements in fast case is O(n*n). 7403 // Note: revisit design to have dual undefined values to capture absent 7404 // elements. 7405 MaybeObject* JSObject::SetFastElement(uint32_t index, 7406 Object* value, 7407 StrictModeFlag strict_mode, 7408 bool check_prototype) { 7409 ASSERT(HasFastElements()); 7410 7411 Object* elms_obj; 7412 { MaybeObject* maybe_elms_obj = EnsureWritableFastElements(); 7413 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; 7414 } 7415 FixedArray* elms = FixedArray::cast(elms_obj); 7416 uint32_t elms_length = static_cast<uint32_t>(elms->length()); 7417 7418 if (check_prototype && 7419 (index >= elms_length || elms->get(index)->IsTheHole())) { 7420 bool found; 7421 MaybeObject* result = 7422 SetElementWithCallbackSetterInPrototypes(index, value, &found); 7423 if (found) return result; 7424 } 7425 7426 7427 // Check whether there is extra space in fixed array.. 7428 if (index < elms_length) { 7429 elms->set(index, value); 7430 if (IsJSArray()) { 7431 // Update the length of the array if needed. 7432 uint32_t array_length = 0; 7433 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); 7434 if (index >= array_length) { 7435 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); 7436 } 7437 } 7438 return value; 7439 } 7440 7441 // Allow gap in fast case. 7442 if ((index - elms_length) < kMaxGap) { 7443 // Try allocating extra space. 7444 int new_capacity = NewElementsCapacity(index+1); 7445 if (new_capacity <= kMaxFastElementsLength || 7446 !ShouldConvertToSlowElements(new_capacity)) { 7447 ASSERT(static_cast<uint32_t>(new_capacity) > index); 7448 Object* obj; 7449 { MaybeObject* maybe_obj = 7450 SetFastElementsCapacityAndLength(new_capacity, index + 1); 7451 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7452 } 7453 FixedArray::cast(elements())->set(index, value); 7454 return value; 7455 } 7456 } 7457 7458 // Otherwise default to slow case. 7459 Object* obj; 7460 { MaybeObject* maybe_obj = NormalizeElements(); 7461 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7462 } 7463 ASSERT(HasDictionaryElements()); 7464 return SetElement(index, value, strict_mode, check_prototype); 7465 } 7466 7467 7468 MaybeObject* JSObject::SetElement(uint32_t index, 7469 Object* value, 7470 StrictModeFlag strict_mode, 7471 bool check_prototype) { 7472 // Check access rights if needed. 7473 if (IsAccessCheckNeeded()) { 7474 Heap* heap = GetHeap(); 7475 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { 7476 HandleScope scope; 7477 Handle<Object> value_handle(value); 7478 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); 7479 return *value_handle; 7480 } 7481 } 7482 7483 if (IsJSGlobalProxy()) { 7484 Object* proto = GetPrototype(); 7485 if (proto->IsNull()) return value; 7486 ASSERT(proto->IsJSGlobalObject()); 7487 return JSObject::cast(proto)->SetElement(index, 7488 value, 7489 strict_mode, 7490 check_prototype); 7491 } 7492 7493 // Check for lookup interceptor 7494 if (HasIndexedInterceptor()) { 7495 return SetElementWithInterceptor(index, 7496 value, 7497 strict_mode, 7498 check_prototype); 7499 } 7500 7501 return SetElementWithoutInterceptor(index, 7502 value, 7503 strict_mode, 7504 check_prototype); 7505 } 7506 7507 7508 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, 7509 Object* value, 7510 StrictModeFlag strict_mode, 7511 bool check_prototype) { 7512 Isolate* isolate = GetIsolate(); 7513 switch (GetElementsKind()) { 7514 case FAST_ELEMENTS: 7515 // Fast case. 7516 return SetFastElement(index, value, strict_mode, check_prototype); 7517 case EXTERNAL_PIXEL_ELEMENTS: { 7518 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); 7519 return pixels->SetValue(index, value); 7520 } 7521 case EXTERNAL_BYTE_ELEMENTS: { 7522 ExternalByteArray* array = ExternalByteArray::cast(elements()); 7523 return array->SetValue(index, value); 7524 } 7525 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 7526 ExternalUnsignedByteArray* array = 7527 ExternalUnsignedByteArray::cast(elements()); 7528 return array->SetValue(index, value); 7529 } 7530 case EXTERNAL_SHORT_ELEMENTS: { 7531 ExternalShortArray* array = ExternalShortArray::cast(elements()); 7532 return array->SetValue(index, value); 7533 } 7534 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 7535 ExternalUnsignedShortArray* array = 7536 ExternalUnsignedShortArray::cast(elements()); 7537 return array->SetValue(index, value); 7538 } 7539 case EXTERNAL_INT_ELEMENTS: { 7540 ExternalIntArray* array = ExternalIntArray::cast(elements()); 7541 return array->SetValue(index, value); 7542 } 7543 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { 7544 ExternalUnsignedIntArray* array = 7545 ExternalUnsignedIntArray::cast(elements()); 7546 return array->SetValue(index, value); 7547 } 7548 case EXTERNAL_FLOAT_ELEMENTS: { 7549 ExternalFloatArray* array = ExternalFloatArray::cast(elements()); 7550 return array->SetValue(index, value); 7551 } 7552 case DICTIONARY_ELEMENTS: { 7553 // Insert element in the dictionary. 7554 FixedArray* elms = FixedArray::cast(elements()); 7555 NumberDictionary* dictionary = NumberDictionary::cast(elms); 7556 7557 int entry = dictionary->FindEntry(index); 7558 if (entry != NumberDictionary::kNotFound) { 7559 Object* element = dictionary->ValueAt(entry); 7560 PropertyDetails details = dictionary->DetailsAt(entry); 7561 if (details.type() == CALLBACKS) { 7562 return SetElementWithCallback(element, index, value, this); 7563 } else { 7564 dictionary->UpdateMaxNumberKey(index); 7565 // If put fails instrict mode, throw exception. 7566 if (!dictionary->ValueAtPut(entry, value) && 7567 strict_mode == kStrictMode) { 7568 Handle<Object> number(isolate->factory()->NewNumberFromUint(index)); 7569 Handle<Object> holder(this); 7570 Handle<Object> args[2] = { number, holder }; 7571 return isolate->Throw( 7572 *isolate->factory()->NewTypeError("strict_read_only_property", 7573 HandleVector(args, 2))); 7574 } 7575 } 7576 } else { 7577 // Index not already used. Look for an accessor in the prototype chain. 7578 if (check_prototype) { 7579 bool found; 7580 MaybeObject* result = 7581 // Strict mode not needed. No-setter case already handled. 7582 SetElementWithCallbackSetterInPrototypes(index, value, &found); 7583 if (found) return result; 7584 } 7585 // When we set the is_extensible flag to false we always force 7586 // the element into dictionary mode (and force them to stay there). 7587 if (!map()->is_extensible()) { 7588 if (strict_mode == kNonStrictMode) { 7589 return isolate->heap()->undefined_value(); 7590 } else { 7591 Handle<Object> number(isolate->factory()->NewNumberFromUint(index)); 7592 Handle<String> index_string( 7593 isolate->factory()->NumberToString(number)); 7594 Handle<Object> args[1] = { index_string }; 7595 return isolate->Throw( 7596 *isolate->factory()->NewTypeError("object_not_extensible", 7597 HandleVector(args, 1))); 7598 } 7599 } 7600 Object* result; 7601 { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value); 7602 if (!maybe_result->ToObject(&result)) return maybe_result; 7603 } 7604 if (elms != FixedArray::cast(result)) { 7605 set_elements(FixedArray::cast(result)); 7606 } 7607 } 7608 7609 // Update the array length if this JSObject is an array. 7610 if (IsJSArray()) { 7611 JSArray* array = JSArray::cast(this); 7612 Object* return_value; 7613 { MaybeObject* maybe_return_value = 7614 array->JSArrayUpdateLengthFromIndex(index, value); 7615 if (!maybe_return_value->ToObject(&return_value)) { 7616 return maybe_return_value; 7617 } 7618 } 7619 } 7620 7621 // Attempt to put this object back in fast case. 7622 if (ShouldConvertToFastElements()) { 7623 uint32_t new_length = 0; 7624 if (IsJSArray()) { 7625 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); 7626 } else { 7627 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; 7628 } 7629 Object* obj; 7630 { MaybeObject* maybe_obj = 7631 SetFastElementsCapacityAndLength(new_length, new_length); 7632 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7633 } 7634 #ifdef DEBUG 7635 if (FLAG_trace_normalization) { 7636 PrintF("Object elements are fast case again:\n"); 7637 Print(); 7638 } 7639 #endif 7640 } 7641 7642 return value; 7643 } 7644 default: 7645 UNREACHABLE(); 7646 break; 7647 } 7648 // All possible cases have been handled above. Add a return to avoid the 7649 // complaints from the compiler. 7650 UNREACHABLE(); 7651 return isolate->heap()->null_value(); 7652 } 7653 7654 7655 MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, 7656 Object* value) { 7657 uint32_t old_len = 0; 7658 CHECK(length()->ToArrayIndex(&old_len)); 7659 // Check to see if we need to update the length. For now, we make 7660 // sure that the length stays within 32-bits (unsigned). 7661 if (index >= old_len && index != 0xffffffff) { 7662 Object* len; 7663 { MaybeObject* maybe_len = 7664 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1); 7665 if (!maybe_len->ToObject(&len)) return maybe_len; 7666 } 7667 set_length(len); 7668 } 7669 return value; 7670 } 7671 7672 7673 MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver, 7674 uint32_t index) { 7675 // Get element works for both JSObject and JSArray since 7676 // JSArray::length cannot change. 7677 switch (GetElementsKind()) { 7678 case FAST_ELEMENTS: { 7679 FixedArray* elms = FixedArray::cast(elements()); 7680 if (index < static_cast<uint32_t>(elms->length())) { 7681 Object* value = elms->get(index); 7682 if (!value->IsTheHole()) return value; 7683 } 7684 break; 7685 } 7686 case EXTERNAL_PIXEL_ELEMENTS: 7687 case EXTERNAL_BYTE_ELEMENTS: 7688 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 7689 case EXTERNAL_SHORT_ELEMENTS: 7690 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 7691 case EXTERNAL_INT_ELEMENTS: 7692 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 7693 case EXTERNAL_FLOAT_ELEMENTS: { 7694 MaybeObject* maybe_value = GetExternalElement(index); 7695 Object* value; 7696 if (!maybe_value->ToObject(&value)) return maybe_value; 7697 if (!value->IsUndefined()) return value; 7698 break; 7699 } 7700 case DICTIONARY_ELEMENTS: { 7701 NumberDictionary* dictionary = element_dictionary(); 7702 int entry = dictionary->FindEntry(index); 7703 if (entry != NumberDictionary::kNotFound) { 7704 Object* element = dictionary->ValueAt(entry); 7705 PropertyDetails details = dictionary->DetailsAt(entry); 7706 if (details.type() == CALLBACKS) { 7707 return GetElementWithCallback(receiver, 7708 element, 7709 index, 7710 this); 7711 } 7712 return element; 7713 } 7714 break; 7715 } 7716 default: 7717 UNREACHABLE(); 7718 break; 7719 } 7720 7721 // Continue searching via the prototype chain. 7722 Object* pt = GetPrototype(); 7723 if (pt->IsNull()) return GetHeap()->undefined_value(); 7724 return pt->GetElementWithReceiver(receiver, index); 7725 } 7726 7727 7728 MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver, 7729 uint32_t index) { 7730 Isolate* isolate = GetIsolate(); 7731 // Make sure that the top context does not change when doing 7732 // callbacks or interceptor calls. 7733 AssertNoContextChange ncc; 7734 HandleScope scope(isolate); 7735 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate); 7736 Handle<Object> this_handle(receiver, isolate); 7737 Handle<JSObject> holder_handle(this, isolate); 7738 if (!interceptor->getter()->IsUndefined()) { 7739 v8::IndexedPropertyGetter getter = 7740 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); 7741 LOG(isolate, 7742 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index)); 7743 CustomArguments args(isolate, interceptor->data(), receiver, this); 7744 v8::AccessorInfo info(args.end()); 7745 v8::Handle<v8::Value> result; 7746 { 7747 // Leaving JavaScript. 7748 VMState state(isolate, EXTERNAL); 7749 result = getter(index, info); 7750 } 7751 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 7752 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 7753 } 7754 7755 MaybeObject* raw_result = 7756 holder_handle->GetElementPostInterceptor(*this_handle, index); 7757 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 7758 return raw_result; 7759 } 7760 7761 7762 MaybeObject* JSObject::GetElementWithReceiver(Object* receiver, 7763 uint32_t index) { 7764 // Check access rights if needed. 7765 if (IsAccessCheckNeeded()) { 7766 Heap* heap = GetHeap(); 7767 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) { 7768 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET); 7769 return heap->undefined_value(); 7770 } 7771 } 7772 7773 if (HasIndexedInterceptor()) { 7774 return GetElementWithInterceptor(receiver, index); 7775 } 7776 7777 // Get element works for both JSObject and JSArray since 7778 // JSArray::length cannot change. 7779 switch (GetElementsKind()) { 7780 case FAST_ELEMENTS: { 7781 FixedArray* elms = FixedArray::cast(elements()); 7782 if (index < static_cast<uint32_t>(elms->length())) { 7783 Object* value = elms->get(index); 7784 if (!value->IsTheHole()) return value; 7785 } 7786 break; 7787 } 7788 case EXTERNAL_PIXEL_ELEMENTS: 7789 case EXTERNAL_BYTE_ELEMENTS: 7790 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 7791 case EXTERNAL_SHORT_ELEMENTS: 7792 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 7793 case EXTERNAL_INT_ELEMENTS: 7794 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 7795 case EXTERNAL_FLOAT_ELEMENTS: { 7796 MaybeObject* maybe_value = GetExternalElement(index); 7797 Object* value; 7798 if (!maybe_value->ToObject(&value)) return maybe_value; 7799 if (!value->IsUndefined()) return value; 7800 break; 7801 } 7802 case DICTIONARY_ELEMENTS: { 7803 NumberDictionary* dictionary = element_dictionary(); 7804 int entry = dictionary->FindEntry(index); 7805 if (entry != NumberDictionary::kNotFound) { 7806 Object* element = dictionary->ValueAt(entry); 7807 PropertyDetails details = dictionary->DetailsAt(entry); 7808 if (details.type() == CALLBACKS) { 7809 return GetElementWithCallback(receiver, 7810 element, 7811 index, 7812 this); 7813 } 7814 return element; 7815 } 7816 break; 7817 } 7818 } 7819 7820 Object* pt = GetPrototype(); 7821 Heap* heap = GetHeap(); 7822 if (pt == heap->null_value()) return heap->undefined_value(); 7823 return pt->GetElementWithReceiver(receiver, index); 7824 } 7825 7826 7827 MaybeObject* JSObject::GetExternalElement(uint32_t index) { 7828 // Get element works for both JSObject and JSArray since 7829 // JSArray::length cannot change. 7830 switch (GetElementsKind()) { 7831 case EXTERNAL_PIXEL_ELEMENTS: { 7832 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); 7833 if (index < static_cast<uint32_t>(pixels->length())) { 7834 uint8_t value = pixels->get(index); 7835 return Smi::FromInt(value); 7836 } 7837 break; 7838 } 7839 case EXTERNAL_BYTE_ELEMENTS: { 7840 ExternalByteArray* array = ExternalByteArray::cast(elements()); 7841 if (index < static_cast<uint32_t>(array->length())) { 7842 int8_t value = array->get(index); 7843 return Smi::FromInt(value); 7844 } 7845 break; 7846 } 7847 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 7848 ExternalUnsignedByteArray* array = 7849 ExternalUnsignedByteArray::cast(elements()); 7850 if (index < static_cast<uint32_t>(array->length())) { 7851 uint8_t value = array->get(index); 7852 return Smi::FromInt(value); 7853 } 7854 break; 7855 } 7856 case EXTERNAL_SHORT_ELEMENTS: { 7857 ExternalShortArray* array = ExternalShortArray::cast(elements()); 7858 if (index < static_cast<uint32_t>(array->length())) { 7859 int16_t value = array->get(index); 7860 return Smi::FromInt(value); 7861 } 7862 break; 7863 } 7864 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 7865 ExternalUnsignedShortArray* array = 7866 ExternalUnsignedShortArray::cast(elements()); 7867 if (index < static_cast<uint32_t>(array->length())) { 7868 uint16_t value = array->get(index); 7869 return Smi::FromInt(value); 7870 } 7871 break; 7872 } 7873 case EXTERNAL_INT_ELEMENTS: { 7874 ExternalIntArray* array = ExternalIntArray::cast(elements()); 7875 if (index < static_cast<uint32_t>(array->length())) { 7876 int32_t value = array->get(index); 7877 return GetHeap()->NumberFromInt32(value); 7878 } 7879 break; 7880 } 7881 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { 7882 ExternalUnsignedIntArray* array = 7883 ExternalUnsignedIntArray::cast(elements()); 7884 if (index < static_cast<uint32_t>(array->length())) { 7885 uint32_t value = array->get(index); 7886 return GetHeap()->NumberFromUint32(value); 7887 } 7888 break; 7889 } 7890 case EXTERNAL_FLOAT_ELEMENTS: { 7891 ExternalFloatArray* array = ExternalFloatArray::cast(elements()); 7892 if (index < static_cast<uint32_t>(array->length())) { 7893 float value = array->get(index); 7894 return GetHeap()->AllocateHeapNumber(value); 7895 } 7896 break; 7897 } 7898 case FAST_ELEMENTS: 7899 case DICTIONARY_ELEMENTS: 7900 UNREACHABLE(); 7901 break; 7902 } 7903 return GetHeap()->undefined_value(); 7904 } 7905 7906 7907 bool JSObject::HasDenseElements() { 7908 int capacity = 0; 7909 int number_of_elements = 0; 7910 7911 switch (GetElementsKind()) { 7912 case FAST_ELEMENTS: { 7913 FixedArray* elms = FixedArray::cast(elements()); 7914 capacity = elms->length(); 7915 for (int i = 0; i < capacity; i++) { 7916 if (!elms->get(i)->IsTheHole()) number_of_elements++; 7917 } 7918 break; 7919 } 7920 case EXTERNAL_PIXEL_ELEMENTS: 7921 case EXTERNAL_BYTE_ELEMENTS: 7922 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 7923 case EXTERNAL_SHORT_ELEMENTS: 7924 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 7925 case EXTERNAL_INT_ELEMENTS: 7926 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 7927 case EXTERNAL_FLOAT_ELEMENTS: { 7928 return true; 7929 } 7930 case DICTIONARY_ELEMENTS: { 7931 NumberDictionary* dictionary = NumberDictionary::cast(elements()); 7932 capacity = dictionary->Capacity(); 7933 number_of_elements = dictionary->NumberOfElements(); 7934 break; 7935 } 7936 default: 7937 UNREACHABLE(); 7938 break; 7939 } 7940 7941 if (capacity == 0) return true; 7942 return (number_of_elements > (capacity / 2)); 7943 } 7944 7945 7946 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { 7947 ASSERT(HasFastElements()); 7948 // Keep the array in fast case if the current backing storage is 7949 // almost filled and if the new capacity is no more than twice the 7950 // old capacity. 7951 int elements_length = FixedArray::cast(elements())->length(); 7952 return !HasDenseElements() || ((new_capacity / 2) > elements_length); 7953 } 7954 7955 7956 bool JSObject::ShouldConvertToFastElements() { 7957 ASSERT(HasDictionaryElements()); 7958 NumberDictionary* dictionary = NumberDictionary::cast(elements()); 7959 // If the elements are sparse, we should not go back to fast case. 7960 if (!HasDenseElements()) return false; 7961 // If an element has been added at a very high index in the elements 7962 // dictionary, we cannot go back to fast case. 7963 if (dictionary->requires_slow_elements()) return false; 7964 // An object requiring access checks is never allowed to have fast 7965 // elements. If it had fast elements we would skip security checks. 7966 if (IsAccessCheckNeeded()) return false; 7967 // If the dictionary backing storage takes up roughly half as much 7968 // space as a fast-case backing storage would the array should have 7969 // fast elements. 7970 uint32_t length = 0; 7971 if (IsJSArray()) { 7972 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); 7973 } else { 7974 length = dictionary->max_number_key(); 7975 } 7976 return static_cast<uint32_t>(dictionary->Capacity()) >= 7977 (length / (2 * NumberDictionary::kEntrySize)); 7978 } 7979 7980 7981 // Certain compilers request function template instantiation when they 7982 // see the definition of the other template functions in the 7983 // class. This requires us to have the template functions put 7984 // together, so even though this function belongs in objects-debug.cc, 7985 // we keep it here instead to satisfy certain compilers. 7986 #ifdef OBJECT_PRINT 7987 template<typename Shape, typename Key> 7988 void Dictionary<Shape, Key>::Print(FILE* out) { 7989 int capacity = HashTable<Shape, Key>::Capacity(); 7990 for (int i = 0; i < capacity; i++) { 7991 Object* k = HashTable<Shape, Key>::KeyAt(i); 7992 if (HashTable<Shape, Key>::IsKey(k)) { 7993 PrintF(out, " "); 7994 if (k->IsString()) { 7995 String::cast(k)->StringPrint(out); 7996 } else { 7997 k->ShortPrint(out); 7998 } 7999 PrintF(out, ": "); 8000 ValueAt(i)->ShortPrint(out); 8001 PrintF(out, "\n"); 8002 } 8003 } 8004 } 8005 #endif 8006 8007 8008 template<typename Shape, typename Key> 8009 void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) { 8010 int pos = 0; 8011 int capacity = HashTable<Shape, Key>::Capacity(); 8012 AssertNoAllocation no_gc; 8013 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 8014 for (int i = 0; i < capacity; i++) { 8015 Object* k = Dictionary<Shape, Key>::KeyAt(i); 8016 if (Dictionary<Shape, Key>::IsKey(k)) { 8017 elements->set(pos++, ValueAt(i), mode); 8018 } 8019 } 8020 ASSERT(pos == elements->length()); 8021 } 8022 8023 8024 InterceptorInfo* JSObject::GetNamedInterceptor() { 8025 ASSERT(map()->has_named_interceptor()); 8026 JSFunction* constructor = JSFunction::cast(map()->constructor()); 8027 ASSERT(constructor->shared()->IsApiFunction()); 8028 Object* result = 8029 constructor->shared()->get_api_func_data()->named_property_handler(); 8030 return InterceptorInfo::cast(result); 8031 } 8032 8033 8034 InterceptorInfo* JSObject::GetIndexedInterceptor() { 8035 ASSERT(map()->has_indexed_interceptor()); 8036 JSFunction* constructor = JSFunction::cast(map()->constructor()); 8037 ASSERT(constructor->shared()->IsApiFunction()); 8038 Object* result = 8039 constructor->shared()->get_api_func_data()->indexed_property_handler(); 8040 return InterceptorInfo::cast(result); 8041 } 8042 8043 8044 MaybeObject* JSObject::GetPropertyPostInterceptor( 8045 JSObject* receiver, 8046 String* name, 8047 PropertyAttributes* attributes) { 8048 // Check local property in holder, ignore interceptor. 8049 LookupResult result; 8050 LocalLookupRealNamedProperty(name, &result); 8051 if (result.IsProperty()) { 8052 return GetProperty(receiver, &result, name, attributes); 8053 } 8054 // Continue searching via the prototype chain. 8055 Object* pt = GetPrototype(); 8056 *attributes = ABSENT; 8057 if (pt->IsNull()) return GetHeap()->undefined_value(); 8058 return pt->GetPropertyWithReceiver(receiver, name, attributes); 8059 } 8060 8061 8062 MaybeObject* JSObject::GetLocalPropertyPostInterceptor( 8063 JSObject* receiver, 8064 String* name, 8065 PropertyAttributes* attributes) { 8066 // Check local property in holder, ignore interceptor. 8067 LookupResult result; 8068 LocalLookupRealNamedProperty(name, &result); 8069 if (result.IsProperty()) { 8070 return GetProperty(receiver, &result, name, attributes); 8071 } 8072 return GetHeap()->undefined_value(); 8073 } 8074 8075 8076 MaybeObject* JSObject::GetPropertyWithInterceptor( 8077 JSObject* receiver, 8078 String* name, 8079 PropertyAttributes* attributes) { 8080 Isolate* isolate = GetIsolate(); 8081 InterceptorInfo* interceptor = GetNamedInterceptor(); 8082 HandleScope scope(isolate); 8083 Handle<JSObject> receiver_handle(receiver); 8084 Handle<JSObject> holder_handle(this); 8085 Handle<String> name_handle(name); 8086 8087 if (!interceptor->getter()->IsUndefined()) { 8088 v8::NamedPropertyGetter getter = 8089 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); 8090 LOG(isolate, 8091 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name)); 8092 CustomArguments args(isolate, interceptor->data(), receiver, this); 8093 v8::AccessorInfo info(args.end()); 8094 v8::Handle<v8::Value> result; 8095 { 8096 // Leaving JavaScript. 8097 VMState state(isolate, EXTERNAL); 8098 result = getter(v8::Utils::ToLocal(name_handle), info); 8099 } 8100 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 8101 if (!result.IsEmpty()) { 8102 *attributes = NONE; 8103 return *v8::Utils::OpenHandle(*result); 8104 } 8105 } 8106 8107 MaybeObject* result = holder_handle->GetPropertyPostInterceptor( 8108 *receiver_handle, 8109 *name_handle, 8110 attributes); 8111 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 8112 return result; 8113 } 8114 8115 8116 bool JSObject::HasRealNamedProperty(String* key) { 8117 // Check access rights if needed. 8118 if (IsAccessCheckNeeded()) { 8119 Heap* heap = GetHeap(); 8120 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) { 8121 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); 8122 return false; 8123 } 8124 } 8125 8126 LookupResult result; 8127 LocalLookupRealNamedProperty(key, &result); 8128 return result.IsProperty() && (result.type() != INTERCEPTOR); 8129 } 8130 8131 8132 bool JSObject::HasRealElementProperty(uint32_t index) { 8133 // Check access rights if needed. 8134 if (IsAccessCheckNeeded()) { 8135 Heap* heap = GetHeap(); 8136 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { 8137 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); 8138 return false; 8139 } 8140 } 8141 8142 // Handle [] on String objects. 8143 if (this->IsStringObjectWithCharacterAt(index)) return true; 8144 8145 switch (GetElementsKind()) { 8146 case FAST_ELEMENTS: { 8147 uint32_t length = IsJSArray() ? 8148 static_cast<uint32_t>( 8149 Smi::cast(JSArray::cast(this)->length())->value()) : 8150 static_cast<uint32_t>(FixedArray::cast(elements())->length()); 8151 return (index < length) && 8152 !FixedArray::cast(elements())->get(index)->IsTheHole(); 8153 } 8154 case EXTERNAL_PIXEL_ELEMENTS: { 8155 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); 8156 return index < static_cast<uint32_t>(pixels->length()); 8157 } 8158 case EXTERNAL_BYTE_ELEMENTS: 8159 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 8160 case EXTERNAL_SHORT_ELEMENTS: 8161 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 8162 case EXTERNAL_INT_ELEMENTS: 8163 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 8164 case EXTERNAL_FLOAT_ELEMENTS: { 8165 ExternalArray* array = ExternalArray::cast(elements()); 8166 return index < static_cast<uint32_t>(array->length()); 8167 } 8168 case DICTIONARY_ELEMENTS: { 8169 return element_dictionary()->FindEntry(index) 8170 != NumberDictionary::kNotFound; 8171 } 8172 default: 8173 UNREACHABLE(); 8174 break; 8175 } 8176 // All possibilities have been handled above already. 8177 UNREACHABLE(); 8178 return GetHeap()->null_value(); 8179 } 8180 8181 8182 bool JSObject::HasRealNamedCallbackProperty(String* key) { 8183 // Check access rights if needed. 8184 if (IsAccessCheckNeeded()) { 8185 Heap* heap = GetHeap(); 8186 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) { 8187 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); 8188 return false; 8189 } 8190 } 8191 8192 LookupResult result; 8193 LocalLookupRealNamedProperty(key, &result); 8194 return result.IsProperty() && (result.type() == CALLBACKS); 8195 } 8196 8197 8198 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { 8199 if (HasFastProperties()) { 8200 DescriptorArray* descs = map()->instance_descriptors(); 8201 int result = 0; 8202 for (int i = 0; i < descs->number_of_descriptors(); i++) { 8203 PropertyDetails details(descs->GetDetails(i)); 8204 if (details.IsProperty() && (details.attributes() & filter) == 0) { 8205 result++; 8206 } 8207 } 8208 return result; 8209 } else { 8210 return property_dictionary()->NumberOfElementsFilterAttributes(filter); 8211 } 8212 } 8213 8214 8215 int JSObject::NumberOfEnumProperties() { 8216 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM)); 8217 } 8218 8219 8220 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) { 8221 Object* temp = get(i); 8222 set(i, get(j)); 8223 set(j, temp); 8224 if (this != numbers) { 8225 temp = numbers->get(i); 8226 numbers->set(i, numbers->get(j)); 8227 numbers->set(j, temp); 8228 } 8229 } 8230 8231 8232 static void InsertionSortPairs(FixedArray* content, 8233 FixedArray* numbers, 8234 int len) { 8235 for (int i = 1; i < len; i++) { 8236 int j = i; 8237 while (j > 0 && 8238 (NumberToUint32(numbers->get(j - 1)) > 8239 NumberToUint32(numbers->get(j)))) { 8240 content->SwapPairs(numbers, j - 1, j); 8241 j--; 8242 } 8243 } 8244 } 8245 8246 8247 void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) { 8248 // In-place heap sort. 8249 ASSERT(content->length() == numbers->length()); 8250 8251 // Bottom-up max-heap construction. 8252 for (int i = 1; i < len; ++i) { 8253 int child_index = i; 8254 while (child_index > 0) { 8255 int parent_index = ((child_index + 1) >> 1) - 1; 8256 uint32_t parent_value = NumberToUint32(numbers->get(parent_index)); 8257 uint32_t child_value = NumberToUint32(numbers->get(child_index)); 8258 if (parent_value < child_value) { 8259 content->SwapPairs(numbers, parent_index, child_index); 8260 } else { 8261 break; 8262 } 8263 child_index = parent_index; 8264 } 8265 } 8266 8267 // Extract elements and create sorted array. 8268 for (int i = len - 1; i > 0; --i) { 8269 // Put max element at the back of the array. 8270 content->SwapPairs(numbers, 0, i); 8271 // Sift down the new top element. 8272 int parent_index = 0; 8273 while (true) { 8274 int child_index = ((parent_index + 1) << 1) - 1; 8275 if (child_index >= i) break; 8276 uint32_t child1_value = NumberToUint32(numbers->get(child_index)); 8277 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1)); 8278 uint32_t parent_value = NumberToUint32(numbers->get(parent_index)); 8279 if (child_index + 1 >= i || child1_value > child2_value) { 8280 if (parent_value > child1_value) break; 8281 content->SwapPairs(numbers, parent_index, child_index); 8282 parent_index = child_index; 8283 } else { 8284 if (parent_value > child2_value) break; 8285 content->SwapPairs(numbers, parent_index, child_index + 1); 8286 parent_index = child_index + 1; 8287 } 8288 } 8289 } 8290 } 8291 8292 8293 // Sort this array and the numbers as pairs wrt. the (distinct) numbers. 8294 void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) { 8295 ASSERT(this->length() == numbers->length()); 8296 // For small arrays, simply use insertion sort. 8297 if (len <= 10) { 8298 InsertionSortPairs(this, numbers, len); 8299 return; 8300 } 8301 // Check the range of indices. 8302 uint32_t min_index = NumberToUint32(numbers->get(0)); 8303 uint32_t max_index = min_index; 8304 uint32_t i; 8305 for (i = 1; i < len; i++) { 8306 if (NumberToUint32(numbers->get(i)) < min_index) { 8307 min_index = NumberToUint32(numbers->get(i)); 8308 } else if (NumberToUint32(numbers->get(i)) > max_index) { 8309 max_index = NumberToUint32(numbers->get(i)); 8310 } 8311 } 8312 if (max_index - min_index + 1 == len) { 8313 // Indices form a contiguous range, unless there are duplicates. 8314 // Do an in-place linear time sort assuming distinct numbers, but 8315 // avoid hanging in case they are not. 8316 for (i = 0; i < len; i++) { 8317 uint32_t p; 8318 uint32_t j = 0; 8319 // While the current element at i is not at its correct position p, 8320 // swap the elements at these two positions. 8321 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i && 8322 j++ < len) { 8323 SwapPairs(numbers, i, p); 8324 } 8325 } 8326 } else { 8327 HeapSortPairs(this, numbers, len); 8328 return; 8329 } 8330 } 8331 8332 8333 // Fill in the names of local properties into the supplied storage. The main 8334 // purpose of this function is to provide reflection information for the object 8335 // mirrors. 8336 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { 8337 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index)); 8338 if (HasFastProperties()) { 8339 DescriptorArray* descs = map()->instance_descriptors(); 8340 for (int i = 0; i < descs->number_of_descriptors(); i++) { 8341 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i)); 8342 } 8343 ASSERT(storage->length() >= index); 8344 } else { 8345 property_dictionary()->CopyKeysTo(storage, 8346 index); 8347 } 8348 } 8349 8350 8351 int JSObject::NumberOfLocalElements(PropertyAttributes filter) { 8352 return GetLocalElementKeys(NULL, filter); 8353 } 8354 8355 8356 int JSObject::NumberOfEnumElements() { 8357 // Fast case for objects with no elements. 8358 if (!IsJSValue() && HasFastElements()) { 8359 uint32_t length = IsJSArray() ? 8360 static_cast<uint32_t>( 8361 Smi::cast(JSArray::cast(this)->length())->value()) : 8362 static_cast<uint32_t>(FixedArray::cast(elements())->length()); 8363 if (length == 0) return 0; 8364 } 8365 // Compute the number of enumerable elements. 8366 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM)); 8367 } 8368 8369 8370 int JSObject::GetLocalElementKeys(FixedArray* storage, 8371 PropertyAttributes filter) { 8372 int counter = 0; 8373 switch (GetElementsKind()) { 8374 case FAST_ELEMENTS: { 8375 int length = IsJSArray() ? 8376 Smi::cast(JSArray::cast(this)->length())->value() : 8377 FixedArray::cast(elements())->length(); 8378 for (int i = 0; i < length; i++) { 8379 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) { 8380 if (storage != NULL) { 8381 storage->set(counter, Smi::FromInt(i)); 8382 } 8383 counter++; 8384 } 8385 } 8386 ASSERT(!storage || storage->length() >= counter); 8387 break; 8388 } 8389 case EXTERNAL_PIXEL_ELEMENTS: { 8390 int length = ExternalPixelArray::cast(elements())->length(); 8391 while (counter < length) { 8392 if (storage != NULL) { 8393 storage->set(counter, Smi::FromInt(counter)); 8394 } 8395 counter++; 8396 } 8397 ASSERT(!storage || storage->length() >= counter); 8398 break; 8399 } 8400 case EXTERNAL_BYTE_ELEMENTS: 8401 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 8402 case EXTERNAL_SHORT_ELEMENTS: 8403 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 8404 case EXTERNAL_INT_ELEMENTS: 8405 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 8406 case EXTERNAL_FLOAT_ELEMENTS: { 8407 int length = ExternalArray::cast(elements())->length(); 8408 while (counter < length) { 8409 if (storage != NULL) { 8410 storage->set(counter, Smi::FromInt(counter)); 8411 } 8412 counter++; 8413 } 8414 ASSERT(!storage || storage->length() >= counter); 8415 break; 8416 } 8417 case DICTIONARY_ELEMENTS: { 8418 if (storage != NULL) { 8419 element_dictionary()->CopyKeysTo(storage, filter); 8420 } 8421 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); 8422 break; 8423 } 8424 default: 8425 UNREACHABLE(); 8426 break; 8427 } 8428 8429 if (this->IsJSValue()) { 8430 Object* val = JSValue::cast(this)->value(); 8431 if (val->IsString()) { 8432 String* str = String::cast(val); 8433 if (storage) { 8434 for (int i = 0; i < str->length(); i++) { 8435 storage->set(counter + i, Smi::FromInt(i)); 8436 } 8437 } 8438 counter += str->length(); 8439 } 8440 } 8441 ASSERT(!storage || storage->length() == counter); 8442 return counter; 8443 } 8444 8445 8446 int JSObject::GetEnumElementKeys(FixedArray* storage) { 8447 return GetLocalElementKeys(storage, 8448 static_cast<PropertyAttributes>(DONT_ENUM)); 8449 } 8450 8451 8452 // StringKey simply carries a string object as key. 8453 class StringKey : public HashTableKey { 8454 public: 8455 explicit StringKey(String* string) : 8456 string_(string), 8457 hash_(HashForObject(string)) { } 8458 8459 bool IsMatch(Object* string) { 8460 // We know that all entries in a hash table had their hash keys created. 8461 // Use that knowledge to have fast failure. 8462 if (hash_ != HashForObject(string)) { 8463 return false; 8464 } 8465 return string_->Equals(String::cast(string)); 8466 } 8467 8468 uint32_t Hash() { return hash_; } 8469 8470 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); } 8471 8472 Object* AsObject() { return string_; } 8473 8474 String* string_; 8475 uint32_t hash_; 8476 }; 8477 8478 8479 // StringSharedKeys are used as keys in the eval cache. 8480 class StringSharedKey : public HashTableKey { 8481 public: 8482 StringSharedKey(String* source, 8483 SharedFunctionInfo* shared, 8484 StrictModeFlag strict_mode) 8485 : source_(source), 8486 shared_(shared), 8487 strict_mode_(strict_mode) { } 8488 8489 bool IsMatch(Object* other) { 8490 if (!other->IsFixedArray()) return false; 8491 FixedArray* pair = FixedArray::cast(other); 8492 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0)); 8493 if (shared != shared_) return false; 8494 StrictModeFlag strict_mode = static_cast<StrictModeFlag>( 8495 Smi::cast(pair->get(2))->value()); 8496 if (strict_mode != strict_mode_) return false; 8497 String* source = String::cast(pair->get(1)); 8498 return source->Equals(source_); 8499 } 8500 8501 static uint32_t StringSharedHashHelper(String* source, 8502 SharedFunctionInfo* shared, 8503 StrictModeFlag strict_mode) { 8504 uint32_t hash = source->Hash(); 8505 if (shared->HasSourceCode()) { 8506 // Instead of using the SharedFunctionInfo pointer in the hash 8507 // code computation, we use a combination of the hash of the 8508 // script source code and the start and end positions. We do 8509 // this to ensure that the cache entries can survive garbage 8510 // collection. 8511 Script* script = Script::cast(shared->script()); 8512 hash ^= String::cast(script->source())->Hash(); 8513 if (strict_mode == kStrictMode) hash ^= 0x8000; 8514 hash += shared->start_position(); 8515 } 8516 return hash; 8517 } 8518 8519 uint32_t Hash() { 8520 return StringSharedHashHelper(source_, shared_, strict_mode_); 8521 } 8522 8523 uint32_t HashForObject(Object* obj) { 8524 FixedArray* pair = FixedArray::cast(obj); 8525 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0)); 8526 String* source = String::cast(pair->get(1)); 8527 StrictModeFlag strict_mode = static_cast<StrictModeFlag>( 8528 Smi::cast(pair->get(2))->value()); 8529 return StringSharedHashHelper(source, shared, strict_mode); 8530 } 8531 8532 MUST_USE_RESULT MaybeObject* AsObject() { 8533 Object* obj; 8534 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3); 8535 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 8536 } 8537 FixedArray* pair = FixedArray::cast(obj); 8538 pair->set(0, shared_); 8539 pair->set(1, source_); 8540 pair->set(2, Smi::FromInt(strict_mode_)); 8541 return pair; 8542 } 8543 8544 private: 8545 String* source_; 8546 SharedFunctionInfo* shared_; 8547 StrictModeFlag strict_mode_; 8548 }; 8549 8550 8551 // RegExpKey carries the source and flags of a regular expression as key. 8552 class RegExpKey : public HashTableKey { 8553 public: 8554 RegExpKey(String* string, JSRegExp::Flags flags) 8555 : string_(string), 8556 flags_(Smi::FromInt(flags.value())) { } 8557 8558 // Rather than storing the key in the hash table, a pointer to the 8559 // stored value is stored where the key should be. IsMatch then 8560 // compares the search key to the found object, rather than comparing 8561 // a key to a key. 8562 bool IsMatch(Object* obj) { 8563 FixedArray* val = FixedArray::cast(obj); 8564 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex))) 8565 && (flags_ == val->get(JSRegExp::kFlagsIndex)); 8566 } 8567 8568 uint32_t Hash() { return RegExpHash(string_, flags_); } 8569 8570 Object* AsObject() { 8571 // Plain hash maps, which is where regexp keys are used, don't 8572 // use this function. 8573 UNREACHABLE(); 8574 return NULL; 8575 } 8576 8577 uint32_t HashForObject(Object* obj) { 8578 FixedArray* val = FixedArray::cast(obj); 8579 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)), 8580 Smi::cast(val->get(JSRegExp::kFlagsIndex))); 8581 } 8582 8583 static uint32_t RegExpHash(String* string, Smi* flags) { 8584 return string->Hash() + flags->value(); 8585 } 8586 8587 String* string_; 8588 Smi* flags_; 8589 }; 8590 8591 // Utf8SymbolKey carries a vector of chars as key. 8592 class Utf8SymbolKey : public HashTableKey { 8593 public: 8594 explicit Utf8SymbolKey(Vector<const char> string) 8595 : string_(string), hash_field_(0) { } 8596 8597 bool IsMatch(Object* string) { 8598 return String::cast(string)->IsEqualTo(string_); 8599 } 8600 8601 uint32_t Hash() { 8602 if (hash_field_ != 0) return hash_field_ >> String::kHashShift; 8603 unibrow::Utf8InputBuffer<> buffer(string_.start(), 8604 static_cast<unsigned>(string_.length())); 8605 chars_ = buffer.Length(); 8606 hash_field_ = String::ComputeHashField(&buffer, chars_); 8607 uint32_t result = hash_field_ >> String::kHashShift; 8608 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed. 8609 return result; 8610 } 8611 8612 uint32_t HashForObject(Object* other) { 8613 return String::cast(other)->Hash(); 8614 } 8615 8616 MaybeObject* AsObject() { 8617 if (hash_field_ == 0) Hash(); 8618 return Isolate::Current()->heap()->AllocateSymbol( 8619 string_, chars_, hash_field_); 8620 } 8621 8622 Vector<const char> string_; 8623 uint32_t hash_field_; 8624 int chars_; // Caches the number of characters when computing the hash code. 8625 }; 8626 8627 8628 template <typename Char> 8629 class SequentialSymbolKey : public HashTableKey { 8630 public: 8631 explicit SequentialSymbolKey(Vector<const Char> string) 8632 : string_(string), hash_field_(0) { } 8633 8634 uint32_t Hash() { 8635 StringHasher hasher(string_.length()); 8636 8637 // Very long strings have a trivial hash that doesn't inspect the 8638 // string contents. 8639 if (hasher.has_trivial_hash()) { 8640 hash_field_ = hasher.GetHashField(); 8641 } else { 8642 int i = 0; 8643 // Do the iterative array index computation as long as there is a 8644 // chance this is an array index. 8645 while (i < string_.length() && hasher.is_array_index()) { 8646 hasher.AddCharacter(static_cast<uc32>(string_[i])); 8647 i++; 8648 } 8649 8650 // Process the remaining characters without updating the array 8651 // index. 8652 while (i < string_.length()) { 8653 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i])); 8654 i++; 8655 } 8656 hash_field_ = hasher.GetHashField(); 8657 } 8658 8659 uint32_t result = hash_field_ >> String::kHashShift; 8660 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed. 8661 return result; 8662 } 8663 8664 8665 uint32_t HashForObject(Object* other) { 8666 return String::cast(other)->Hash(); 8667 } 8668 8669 Vector<const Char> string_; 8670 uint32_t hash_field_; 8671 }; 8672 8673 8674 8675 class AsciiSymbolKey : public SequentialSymbolKey<char> { 8676 public: 8677 explicit AsciiSymbolKey(Vector<const char> str) 8678 : SequentialSymbolKey<char>(str) { } 8679 8680 bool IsMatch(Object* string) { 8681 return String::cast(string)->IsAsciiEqualTo(string_); 8682 } 8683 8684 MaybeObject* AsObject() { 8685 if (hash_field_ == 0) Hash(); 8686 return HEAP->AllocateAsciiSymbol(string_, hash_field_); 8687 } 8688 }; 8689 8690 8691 class TwoByteSymbolKey : public SequentialSymbolKey<uc16> { 8692 public: 8693 explicit TwoByteSymbolKey(Vector<const uc16> str) 8694 : SequentialSymbolKey<uc16>(str) { } 8695 8696 bool IsMatch(Object* string) { 8697 return String::cast(string)->IsTwoByteEqualTo(string_); 8698 } 8699 8700 MaybeObject* AsObject() { 8701 if (hash_field_ == 0) Hash(); 8702 return HEAP->AllocateTwoByteSymbol(string_, hash_field_); 8703 } 8704 }; 8705 8706 8707 // SymbolKey carries a string/symbol object as key. 8708 class SymbolKey : public HashTableKey { 8709 public: 8710 explicit SymbolKey(String* string) 8711 : string_(string) { } 8712 8713 bool IsMatch(Object* string) { 8714 return String::cast(string)->Equals(string_); 8715 } 8716 8717 uint32_t Hash() { return string_->Hash(); } 8718 8719 uint32_t HashForObject(Object* other) { 8720 return String::cast(other)->Hash(); 8721 } 8722 8723 MaybeObject* AsObject() { 8724 // Attempt to flatten the string, so that symbols will most often 8725 // be flat strings. 8726 string_ = string_->TryFlattenGetString(); 8727 Heap* heap = string_->GetHeap(); 8728 // Transform string to symbol if possible. 8729 Map* map = heap->SymbolMapForString(string_); 8730 if (map != NULL) { 8731 string_->set_map(map); 8732 ASSERT(string_->IsSymbol()); 8733 return string_; 8734 } 8735 // Otherwise allocate a new symbol. 8736 StringInputBuffer buffer(string_); 8737 return heap->AllocateInternalSymbol(&buffer, 8738 string_->length(), 8739 string_->hash_field()); 8740 } 8741 8742 static uint32_t StringHash(Object* obj) { 8743 return String::cast(obj)->Hash(); 8744 } 8745 8746 String* string_; 8747 }; 8748 8749 8750 template<typename Shape, typename Key> 8751 void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) { 8752 IteratePointers(v, 0, kElementsStartOffset); 8753 } 8754 8755 8756 template<typename Shape, typename Key> 8757 void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) { 8758 IteratePointers(v, 8759 kElementsStartOffset, 8760 kHeaderSize + length() * kPointerSize); 8761 } 8762 8763 8764 template<typename Shape, typename Key> 8765 MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for, 8766 PretenureFlag pretenure) { 8767 const int kMinCapacity = 32; 8768 int capacity = RoundUpToPowerOf2(at_least_space_for * 2); 8769 if (capacity < kMinCapacity) { 8770 capacity = kMinCapacity; // Guarantee min capacity. 8771 } else if (capacity > HashTable::kMaxCapacity) { 8772 return Failure::OutOfMemoryException(); 8773 } 8774 8775 Object* obj; 8776 { MaybeObject* maybe_obj = Isolate::Current()->heap()-> 8777 AllocateHashTable(EntryToIndex(capacity), pretenure); 8778 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 8779 } 8780 HashTable::cast(obj)->SetNumberOfElements(0); 8781 HashTable::cast(obj)->SetNumberOfDeletedElements(0); 8782 HashTable::cast(obj)->SetCapacity(capacity); 8783 return obj; 8784 } 8785 8786 8787 // Find entry for key otherwise return kNotFound. 8788 int StringDictionary::FindEntry(String* key) { 8789 if (!key->IsSymbol()) { 8790 return HashTable<StringDictionaryShape, String*>::FindEntry(key); 8791 } 8792 8793 // Optimized for symbol key. Knowledge of the key type allows: 8794 // 1. Move the check if the key is a symbol out of the loop. 8795 // 2. Avoid comparing hash codes in symbol to symbol comparision. 8796 // 3. Detect a case when a dictionary key is not a symbol but the key is. 8797 // In case of positive result the dictionary key may be replaced by 8798 // the symbol with minimal performance penalty. It gives a chance to 8799 // perform further lookups in code stubs (and significant performance boost 8800 // a certain style of code). 8801 8802 // EnsureCapacity will guarantee the hash table is never full. 8803 uint32_t capacity = Capacity(); 8804 uint32_t entry = FirstProbe(key->Hash(), capacity); 8805 uint32_t count = 1; 8806 8807 while (true) { 8808 int index = EntryToIndex(entry); 8809 Object* element = get(index); 8810 if (element->IsUndefined()) break; // Empty entry. 8811 if (key == element) return entry; 8812 if (!element->IsSymbol() && 8813 !element->IsNull() && 8814 String::cast(element)->Equals(key)) { 8815 // Replace a non-symbol key by the equivalent symbol for faster further 8816 // lookups. 8817 set(index, key); 8818 return entry; 8819 } 8820 ASSERT(element->IsNull() || !String::cast(element)->Equals(key)); 8821 entry = NextProbe(entry, count++, capacity); 8822 } 8823 return kNotFound; 8824 } 8825 8826 8827 template<typename Shape, typename Key> 8828 MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) { 8829 int capacity = Capacity(); 8830 int nof = NumberOfElements() + n; 8831 int nod = NumberOfDeletedElements(); 8832 // Return if: 8833 // 50% is still free after adding n elements and 8834 // at most 50% of the free elements are deleted elements. 8835 if (nod <= (capacity - nof) >> 1) { 8836 int needed_free = nof >> 1; 8837 if (nof + needed_free <= capacity) return this; 8838 } 8839 8840 const int kMinCapacityForPretenure = 256; 8841 bool pretenure = 8842 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this); 8843 Object* obj; 8844 { MaybeObject* maybe_obj = 8845 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED); 8846 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 8847 } 8848 8849 AssertNoAllocation no_gc; 8850 HashTable* table = HashTable::cast(obj); 8851 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc); 8852 8853 // Copy prefix to new array. 8854 for (int i = kPrefixStartIndex; 8855 i < kPrefixStartIndex + Shape::kPrefixSize; 8856 i++) { 8857 table->set(i, get(i), mode); 8858 } 8859 // Rehash the elements. 8860 for (int i = 0; i < capacity; i++) { 8861 uint32_t from_index = EntryToIndex(i); 8862 Object* k = get(from_index); 8863 if (IsKey(k)) { 8864 uint32_t hash = Shape::HashForObject(key, k); 8865 uint32_t insertion_index = 8866 EntryToIndex(table->FindInsertionEntry(hash)); 8867 for (int j = 0; j < Shape::kEntrySize; j++) { 8868 table->set(insertion_index + j, get(from_index + j), mode); 8869 } 8870 } 8871 } 8872 table->SetNumberOfElements(NumberOfElements()); 8873 table->SetNumberOfDeletedElements(0); 8874 return table; 8875 } 8876 8877 8878 template<typename Shape, typename Key> 8879 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) { 8880 uint32_t capacity = Capacity(); 8881 uint32_t entry = FirstProbe(hash, capacity); 8882 uint32_t count = 1; 8883 // EnsureCapacity will guarantee the hash table is never full. 8884 while (true) { 8885 Object* element = KeyAt(entry); 8886 if (element->IsUndefined() || element->IsNull()) break; 8887 entry = NextProbe(entry, count++, capacity); 8888 } 8889 return entry; 8890 } 8891 8892 // Force instantiation of template instances class. 8893 // Please note this list is compiler dependent. 8894 8895 template class HashTable<SymbolTableShape, HashTableKey*>; 8896 8897 template class HashTable<CompilationCacheShape, HashTableKey*>; 8898 8899 template class HashTable<MapCacheShape, HashTableKey*>; 8900 8901 template class Dictionary<StringDictionaryShape, String*>; 8902 8903 template class Dictionary<NumberDictionaryShape, uint32_t>; 8904 8905 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate( 8906 int); 8907 8908 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate( 8909 int); 8910 8911 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut( 8912 uint32_t, Object*); 8913 8914 template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup( 8915 Object*); 8916 8917 template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup( 8918 Object*); 8919 8920 template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo( 8921 FixedArray*, PropertyAttributes); 8922 8923 template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty( 8924 int, JSObject::DeleteMode); 8925 8926 template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty( 8927 int, JSObject::DeleteMode); 8928 8929 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo( 8930 FixedArray*, int); 8931 8932 template int 8933 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes( 8934 PropertyAttributes); 8935 8936 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add( 8937 String*, Object*, PropertyDetails); 8938 8939 template MaybeObject* 8940 Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices(); 8941 8942 template int 8943 Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes( 8944 PropertyAttributes); 8945 8946 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add( 8947 uint32_t, Object*, PropertyDetails); 8948 8949 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>:: 8950 EnsureCapacity(int, uint32_t); 8951 8952 template MaybeObject* Dictionary<StringDictionaryShape, String*>:: 8953 EnsureCapacity(int, String*); 8954 8955 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry( 8956 uint32_t, Object*, PropertyDetails, uint32_t); 8957 8958 template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry( 8959 String*, Object*, PropertyDetails, uint32_t); 8960 8961 template 8962 int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements(); 8963 8964 template 8965 int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements(); 8966 8967 template 8968 int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t); 8969 8970 8971 // Collates undefined and unexisting elements below limit from position 8972 // zero of the elements. The object stays in Dictionary mode. 8973 MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) { 8974 ASSERT(HasDictionaryElements()); 8975 // Must stay in dictionary mode, either because of requires_slow_elements, 8976 // or because we are not going to sort (and therefore compact) all of the 8977 // elements. 8978 NumberDictionary* dict = element_dictionary(); 8979 HeapNumber* result_double = NULL; 8980 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { 8981 // Allocate space for result before we start mutating the object. 8982 Object* new_double; 8983 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0); 8984 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double; 8985 } 8986 result_double = HeapNumber::cast(new_double); 8987 } 8988 8989 Object* obj; 8990 { MaybeObject* maybe_obj = 8991 NumberDictionary::Allocate(dict->NumberOfElements()); 8992 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 8993 } 8994 NumberDictionary* new_dict = NumberDictionary::cast(obj); 8995 8996 AssertNoAllocation no_alloc; 8997 8998 uint32_t pos = 0; 8999 uint32_t undefs = 0; 9000 int capacity = dict->Capacity(); 9001 for (int i = 0; i < capacity; i++) { 9002 Object* k = dict->KeyAt(i); 9003 if (dict->IsKey(k)) { 9004 ASSERT(k->IsNumber()); 9005 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0); 9006 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0); 9007 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32); 9008 Object* value = dict->ValueAt(i); 9009 PropertyDetails details = dict->DetailsAt(i); 9010 if (details.type() == CALLBACKS) { 9011 // Bail out and do the sorting of undefineds and array holes in JS. 9012 return Smi::FromInt(-1); 9013 } 9014 uint32_t key = NumberToUint32(k); 9015 // In the following we assert that adding the entry to the new dictionary 9016 // does not cause GC. This is the case because we made sure to allocate 9017 // the dictionary big enough above, so it need not grow. 9018 if (key < limit) { 9019 if (value->IsUndefined()) { 9020 undefs++; 9021 } else { 9022 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { 9023 // Adding an entry with the key beyond smi-range requires 9024 // allocation. Bailout. 9025 return Smi::FromInt(-1); 9026 } 9027 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked(); 9028 pos++; 9029 } 9030 } else { 9031 if (key > static_cast<uint32_t>(Smi::kMaxValue)) { 9032 // Adding an entry with the key beyond smi-range requires 9033 // allocation. Bailout. 9034 return Smi::FromInt(-1); 9035 } 9036 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked(); 9037 } 9038 } 9039 } 9040 9041 uint32_t result = pos; 9042 PropertyDetails no_details = PropertyDetails(NONE, NORMAL); 9043 Heap* heap = GetHeap(); 9044 while (undefs > 0) { 9045 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { 9046 // Adding an entry with the key beyond smi-range requires 9047 // allocation. Bailout. 9048 return Smi::FromInt(-1); 9049 } 9050 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)-> 9051 ToObjectUnchecked(); 9052 pos++; 9053 undefs--; 9054 } 9055 9056 set_elements(new_dict); 9057 9058 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { 9059 return Smi::FromInt(static_cast<int>(result)); 9060 } 9061 9062 ASSERT_NE(NULL, result_double); 9063 result_double->set_value(static_cast<double>(result)); 9064 return result_double; 9065 } 9066 9067 9068 // Collects all defined (non-hole) and non-undefined (array) elements at 9069 // the start of the elements array. 9070 // If the object is in dictionary mode, it is converted to fast elements 9071 // mode. 9072 MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { 9073 ASSERT(!HasExternalArrayElements()); 9074 9075 Heap* heap = GetHeap(); 9076 9077 if (HasDictionaryElements()) { 9078 // Convert to fast elements containing only the existing properties. 9079 // Ordering is irrelevant, since we are going to sort anyway. 9080 NumberDictionary* dict = element_dictionary(); 9081 if (IsJSArray() || dict->requires_slow_elements() || 9082 dict->max_number_key() >= limit) { 9083 return PrepareSlowElementsForSort(limit); 9084 } 9085 // Convert to fast elements. 9086 9087 Object* obj; 9088 { MaybeObject* maybe_obj = map()->GetFastElementsMap(); 9089 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9090 } 9091 Map* new_map = Map::cast(obj); 9092 9093 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED; 9094 Object* new_array; 9095 { MaybeObject* maybe_new_array = 9096 heap->AllocateFixedArray(dict->NumberOfElements(), tenure); 9097 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array; 9098 } 9099 FixedArray* fast_elements = FixedArray::cast(new_array); 9100 dict->CopyValuesTo(fast_elements); 9101 9102 set_map(new_map); 9103 set_elements(fast_elements); 9104 } else { 9105 Object* obj; 9106 { MaybeObject* maybe_obj = EnsureWritableFastElements(); 9107 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9108 } 9109 } 9110 ASSERT(HasFastElements()); 9111 9112 // Collect holes at the end, undefined before that and the rest at the 9113 // start, and return the number of non-hole, non-undefined values. 9114 9115 FixedArray* elements = FixedArray::cast(this->elements()); 9116 uint32_t elements_length = static_cast<uint32_t>(elements->length()); 9117 if (limit > elements_length) { 9118 limit = elements_length ; 9119 } 9120 if (limit == 0) { 9121 return Smi::FromInt(0); 9122 } 9123 9124 HeapNumber* result_double = NULL; 9125 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { 9126 // Pessimistically allocate space for return value before 9127 // we start mutating the array. 9128 Object* new_double; 9129 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0); 9130 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double; 9131 } 9132 result_double = HeapNumber::cast(new_double); 9133 } 9134 9135 AssertNoAllocation no_alloc; 9136 9137 // Split elements into defined, undefined and the_hole, in that order. 9138 // Only count locations for undefined and the hole, and fill them afterwards. 9139 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc); 9140 unsigned int undefs = limit; 9141 unsigned int holes = limit; 9142 // Assume most arrays contain no holes and undefined values, so minimize the 9143 // number of stores of non-undefined, non-the-hole values. 9144 for (unsigned int i = 0; i < undefs; i++) { 9145 Object* current = elements->get(i); 9146 if (current->IsTheHole()) { 9147 holes--; 9148 undefs--; 9149 } else if (current->IsUndefined()) { 9150 undefs--; 9151 } else { 9152 continue; 9153 } 9154 // Position i needs to be filled. 9155 while (undefs > i) { 9156 current = elements->get(undefs); 9157 if (current->IsTheHole()) { 9158 holes--; 9159 undefs--; 9160 } else if (current->IsUndefined()) { 9161 undefs--; 9162 } else { 9163 elements->set(i, current, write_barrier); 9164 break; 9165 } 9166 } 9167 } 9168 uint32_t result = undefs; 9169 while (undefs < holes) { 9170 elements->set_undefined(undefs); 9171 undefs++; 9172 } 9173 while (holes < limit) { 9174 elements->set_the_hole(holes); 9175 holes++; 9176 } 9177 9178 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { 9179 return Smi::FromInt(static_cast<int>(result)); 9180 } 9181 ASSERT_NE(NULL, result_double); 9182 result_double->set_value(static_cast<double>(result)); 9183 return result_double; 9184 } 9185 9186 9187 Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) { 9188 uint8_t clamped_value = 0; 9189 if (index < static_cast<uint32_t>(length())) { 9190 if (value->IsSmi()) { 9191 int int_value = Smi::cast(value)->value(); 9192 if (int_value < 0) { 9193 clamped_value = 0; 9194 } else if (int_value > 255) { 9195 clamped_value = 255; 9196 } else { 9197 clamped_value = static_cast<uint8_t>(int_value); 9198 } 9199 } else if (value->IsHeapNumber()) { 9200 double double_value = HeapNumber::cast(value)->value(); 9201 if (!(double_value > 0)) { 9202 // NaN and less than zero clamp to zero. 9203 clamped_value = 0; 9204 } else if (double_value > 255) { 9205 // Greater than 255 clamp to 255. 9206 clamped_value = 255; 9207 } else { 9208 // Other doubles are rounded to the nearest integer. 9209 clamped_value = static_cast<uint8_t>(double_value + 0.5); 9210 } 9211 } else { 9212 // Clamp undefined to zero (default). All other types have been 9213 // converted to a number type further up in the call chain. 9214 ASSERT(value->IsUndefined()); 9215 } 9216 set(index, clamped_value); 9217 } 9218 return Smi::FromInt(clamped_value); 9219 } 9220 9221 9222 template<typename ExternalArrayClass, typename ValueType> 9223 static MaybeObject* ExternalArrayIntSetter(Heap* heap, 9224 ExternalArrayClass* receiver, 9225 uint32_t index, 9226 Object* value) { 9227 ValueType cast_value = 0; 9228 if (index < static_cast<uint32_t>(receiver->length())) { 9229 if (value->IsSmi()) { 9230 int int_value = Smi::cast(value)->value(); 9231 cast_value = static_cast<ValueType>(int_value); 9232 } else if (value->IsHeapNumber()) { 9233 double double_value = HeapNumber::cast(value)->value(); 9234 cast_value = static_cast<ValueType>(DoubleToInt32(double_value)); 9235 } else { 9236 // Clamp undefined to zero (default). All other types have been 9237 // converted to a number type further up in the call chain. 9238 ASSERT(value->IsUndefined()); 9239 } 9240 receiver->set(index, cast_value); 9241 } 9242 return heap->NumberFromInt32(cast_value); 9243 } 9244 9245 9246 MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) { 9247 return ExternalArrayIntSetter<ExternalByteArray, int8_t> 9248 (GetHeap(), this, index, value); 9249 } 9250 9251 9252 MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index, 9253 Object* value) { 9254 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t> 9255 (GetHeap(), this, index, value); 9256 } 9257 9258 9259 MaybeObject* ExternalShortArray::SetValue(uint32_t index, 9260 Object* value) { 9261 return ExternalArrayIntSetter<ExternalShortArray, int16_t> 9262 (GetHeap(), this, index, value); 9263 } 9264 9265 9266 MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index, 9267 Object* value) { 9268 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t> 9269 (GetHeap(), this, index, value); 9270 } 9271 9272 9273 MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) { 9274 return ExternalArrayIntSetter<ExternalIntArray, int32_t> 9275 (GetHeap(), this, index, value); 9276 } 9277 9278 9279 MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) { 9280 uint32_t cast_value = 0; 9281 Heap* heap = GetHeap(); 9282 if (index < static_cast<uint32_t>(length())) { 9283 if (value->IsSmi()) { 9284 int int_value = Smi::cast(value)->value(); 9285 cast_value = static_cast<uint32_t>(int_value); 9286 } else if (value->IsHeapNumber()) { 9287 double double_value = HeapNumber::cast(value)->value(); 9288 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value)); 9289 } else { 9290 // Clamp undefined to zero (default). All other types have been 9291 // converted to a number type further up in the call chain. 9292 ASSERT(value->IsUndefined()); 9293 } 9294 set(index, cast_value); 9295 } 9296 return heap->NumberFromUint32(cast_value); 9297 } 9298 9299 9300 MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) { 9301 float cast_value = 0; 9302 Heap* heap = GetHeap(); 9303 if (index < static_cast<uint32_t>(length())) { 9304 if (value->IsSmi()) { 9305 int int_value = Smi::cast(value)->value(); 9306 cast_value = static_cast<float>(int_value); 9307 } else if (value->IsHeapNumber()) { 9308 double double_value = HeapNumber::cast(value)->value(); 9309 cast_value = static_cast<float>(double_value); 9310 } else { 9311 // Clamp undefined to zero (default). All other types have been 9312 // converted to a number type further up in the call chain. 9313 ASSERT(value->IsUndefined()); 9314 } 9315 set(index, cast_value); 9316 } 9317 return heap->AllocateHeapNumber(cast_value); 9318 } 9319 9320 9321 JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) { 9322 ASSERT(!HasFastProperties()); 9323 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); 9324 return JSGlobalPropertyCell::cast(value); 9325 } 9326 9327 9328 MaybeObject* GlobalObject::EnsurePropertyCell(String* name) { 9329 ASSERT(!HasFastProperties()); 9330 int entry = property_dictionary()->FindEntry(name); 9331 if (entry == StringDictionary::kNotFound) { 9332 Heap* heap = GetHeap(); 9333 Object* cell; 9334 { MaybeObject* maybe_cell = 9335 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value()); 9336 if (!maybe_cell->ToObject(&cell)) return maybe_cell; 9337 } 9338 PropertyDetails details(NONE, NORMAL); 9339 details = details.AsDeleted(); 9340 Object* dictionary; 9341 { MaybeObject* maybe_dictionary = 9342 property_dictionary()->Add(name, cell, details); 9343 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary; 9344 } 9345 set_properties(StringDictionary::cast(dictionary)); 9346 return cell; 9347 } else { 9348 Object* value = property_dictionary()->ValueAt(entry); 9349 ASSERT(value->IsJSGlobalPropertyCell()); 9350 return value; 9351 } 9352 } 9353 9354 9355 MaybeObject* SymbolTable::LookupString(String* string, Object** s) { 9356 SymbolKey key(string); 9357 return LookupKey(&key, s); 9358 } 9359 9360 9361 // This class is used for looking up two character strings in the symbol table. 9362 // If we don't have a hit we don't want to waste much time so we unroll the 9363 // string hash calculation loop here for speed. Doesn't work if the two 9364 // characters form a decimal integer, since such strings have a different hash 9365 // algorithm. 9366 class TwoCharHashTableKey : public HashTableKey { 9367 public: 9368 TwoCharHashTableKey(uint32_t c1, uint32_t c2) 9369 : c1_(c1), c2_(c2) { 9370 // Char 1. 9371 uint32_t hash = c1 + (c1 << 10); 9372 hash ^= hash >> 6; 9373 // Char 2. 9374 hash += c2; 9375 hash += hash << 10; 9376 hash ^= hash >> 6; 9377 // GetHash. 9378 hash += hash << 3; 9379 hash ^= hash >> 11; 9380 hash += hash << 15; 9381 if (hash == 0) hash = 27; 9382 #ifdef DEBUG 9383 StringHasher hasher(2); 9384 hasher.AddCharacter(c1); 9385 hasher.AddCharacter(c2); 9386 // If this assert fails then we failed to reproduce the two-character 9387 // version of the string hashing algorithm above. One reason could be 9388 // that we were passed two digits as characters, since the hash 9389 // algorithm is different in that case. 9390 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash)); 9391 #endif 9392 hash_ = hash; 9393 } 9394 9395 bool IsMatch(Object* o) { 9396 if (!o->IsString()) return false; 9397 String* other = String::cast(o); 9398 if (other->length() != 2) return false; 9399 if (other->Get(0) != c1_) return false; 9400 return other->Get(1) == c2_; 9401 } 9402 9403 uint32_t Hash() { return hash_; } 9404 uint32_t HashForObject(Object* key) { 9405 if (!key->IsString()) return 0; 9406 return String::cast(key)->Hash(); 9407 } 9408 9409 Object* AsObject() { 9410 // The TwoCharHashTableKey is only used for looking in the symbol 9411 // table, not for adding to it. 9412 UNREACHABLE(); 9413 return NULL; 9414 } 9415 private: 9416 uint32_t c1_; 9417 uint32_t c2_; 9418 uint32_t hash_; 9419 }; 9420 9421 9422 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { 9423 SymbolKey key(string); 9424 int entry = FindEntry(&key); 9425 if (entry == kNotFound) { 9426 return false; 9427 } else { 9428 String* result = String::cast(KeyAt(entry)); 9429 ASSERT(StringShape(result).IsSymbol()); 9430 *symbol = result; 9431 return true; 9432 } 9433 } 9434 9435 9436 bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1, 9437 uint32_t c2, 9438 String** symbol) { 9439 TwoCharHashTableKey key(c1, c2); 9440 int entry = FindEntry(&key); 9441 if (entry == kNotFound) { 9442 return false; 9443 } else { 9444 String* result = String::cast(KeyAt(entry)); 9445 ASSERT(StringShape(result).IsSymbol()); 9446 *symbol = result; 9447 return true; 9448 } 9449 } 9450 9451 9452 MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { 9453 Utf8SymbolKey key(str); 9454 return LookupKey(&key, s); 9455 } 9456 9457 9458 MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str, 9459 Object** s) { 9460 AsciiSymbolKey key(str); 9461 return LookupKey(&key, s); 9462 } 9463 9464 9465 MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str, 9466 Object** s) { 9467 TwoByteSymbolKey key(str); 9468 return LookupKey(&key, s); 9469 } 9470 9471 MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) { 9472 int entry = FindEntry(key); 9473 9474 // Symbol already in table. 9475 if (entry != kNotFound) { 9476 *s = KeyAt(entry); 9477 return this; 9478 } 9479 9480 // Adding new symbol. Grow table if needed. 9481 Object* obj; 9482 { MaybeObject* maybe_obj = EnsureCapacity(1, key); 9483 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9484 } 9485 9486 // Create symbol object. 9487 Object* symbol; 9488 { MaybeObject* maybe_symbol = key->AsObject(); 9489 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol; 9490 } 9491 9492 // If the symbol table grew as part of EnsureCapacity, obj is not 9493 // the current symbol table and therefore we cannot use 9494 // SymbolTable::cast here. 9495 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj); 9496 9497 // Add the new symbol and return it along with the symbol table. 9498 entry = table->FindInsertionEntry(key->Hash()); 9499 table->set(EntryToIndex(entry), symbol); 9500 table->ElementAdded(); 9501 *s = symbol; 9502 return table; 9503 } 9504 9505 9506 Object* CompilationCacheTable::Lookup(String* src) { 9507 StringKey key(src); 9508 int entry = FindEntry(&key); 9509 if (entry == kNotFound) return GetHeap()->undefined_value(); 9510 return get(EntryToIndex(entry) + 1); 9511 } 9512 9513 9514 Object* CompilationCacheTable::LookupEval(String* src, 9515 Context* context, 9516 StrictModeFlag strict_mode) { 9517 StringSharedKey key(src, context->closure()->shared(), strict_mode); 9518 int entry = FindEntry(&key); 9519 if (entry == kNotFound) return GetHeap()->undefined_value(); 9520 return get(EntryToIndex(entry) + 1); 9521 } 9522 9523 9524 Object* CompilationCacheTable::LookupRegExp(String* src, 9525 JSRegExp::Flags flags) { 9526 RegExpKey key(src, flags); 9527 int entry = FindEntry(&key); 9528 if (entry == kNotFound) return GetHeap()->undefined_value(); 9529 return get(EntryToIndex(entry) + 1); 9530 } 9531 9532 9533 MaybeObject* CompilationCacheTable::Put(String* src, Object* value) { 9534 StringKey key(src); 9535 Object* obj; 9536 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); 9537 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9538 } 9539 9540 CompilationCacheTable* cache = 9541 reinterpret_cast<CompilationCacheTable*>(obj); 9542 int entry = cache->FindInsertionEntry(key.Hash()); 9543 cache->set(EntryToIndex(entry), src); 9544 cache->set(EntryToIndex(entry) + 1, value); 9545 cache->ElementAdded(); 9546 return cache; 9547 } 9548 9549 9550 MaybeObject* CompilationCacheTable::PutEval(String* src, 9551 Context* context, 9552 SharedFunctionInfo* value) { 9553 StringSharedKey key(src, 9554 context->closure()->shared(), 9555 value->strict_mode() ? kStrictMode : kNonStrictMode); 9556 Object* obj; 9557 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); 9558 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9559 } 9560 9561 CompilationCacheTable* cache = 9562 reinterpret_cast<CompilationCacheTable*>(obj); 9563 int entry = cache->FindInsertionEntry(key.Hash()); 9564 9565 Object* k; 9566 { MaybeObject* maybe_k = key.AsObject(); 9567 if (!maybe_k->ToObject(&k)) return maybe_k; 9568 } 9569 9570 cache->set(EntryToIndex(entry), k); 9571 cache->set(EntryToIndex(entry) + 1, value); 9572 cache->ElementAdded(); 9573 return cache; 9574 } 9575 9576 9577 MaybeObject* CompilationCacheTable::PutRegExp(String* src, 9578 JSRegExp::Flags flags, 9579 FixedArray* value) { 9580 RegExpKey key(src, flags); 9581 Object* obj; 9582 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); 9583 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9584 } 9585 9586 CompilationCacheTable* cache = 9587 reinterpret_cast<CompilationCacheTable*>(obj); 9588 int entry = cache->FindInsertionEntry(key.Hash()); 9589 // We store the value in the key slot, and compare the search key 9590 // to the stored value with a custon IsMatch function during lookups. 9591 cache->set(EntryToIndex(entry), value); 9592 cache->set(EntryToIndex(entry) + 1, value); 9593 cache->ElementAdded(); 9594 return cache; 9595 } 9596 9597 9598 void CompilationCacheTable::Remove(Object* value) { 9599 Object* null_value = GetHeap()->null_value(); 9600 for (int entry = 0, size = Capacity(); entry < size; entry++) { 9601 int entry_index = EntryToIndex(entry); 9602 int value_index = entry_index + 1; 9603 if (get(value_index) == value) { 9604 fast_set(this, entry_index, null_value); 9605 fast_set(this, value_index, null_value); 9606 ElementRemoved(); 9607 } 9608 } 9609 return; 9610 } 9611 9612 9613 // SymbolsKey used for HashTable where key is array of symbols. 9614 class SymbolsKey : public HashTableKey { 9615 public: 9616 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { } 9617 9618 bool IsMatch(Object* symbols) { 9619 FixedArray* o = FixedArray::cast(symbols); 9620 int len = symbols_->length(); 9621 if (o->length() != len) return false; 9622 for (int i = 0; i < len; i++) { 9623 if (o->get(i) != symbols_->get(i)) return false; 9624 } 9625 return true; 9626 } 9627 9628 uint32_t Hash() { return HashForObject(symbols_); } 9629 9630 uint32_t HashForObject(Object* obj) { 9631 FixedArray* symbols = FixedArray::cast(obj); 9632 int len = symbols->length(); 9633 uint32_t hash = 0; 9634 for (int i = 0; i < len; i++) { 9635 hash ^= String::cast(symbols->get(i))->Hash(); 9636 } 9637 return hash; 9638 } 9639 9640 Object* AsObject() { return symbols_; } 9641 9642 private: 9643 FixedArray* symbols_; 9644 }; 9645 9646 9647 Object* MapCache::Lookup(FixedArray* array) { 9648 SymbolsKey key(array); 9649 int entry = FindEntry(&key); 9650 if (entry == kNotFound) return GetHeap()->undefined_value(); 9651 return get(EntryToIndex(entry) + 1); 9652 } 9653 9654 9655 MaybeObject* MapCache::Put(FixedArray* array, Map* value) { 9656 SymbolsKey key(array); 9657 Object* obj; 9658 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); 9659 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9660 } 9661 9662 MapCache* cache = reinterpret_cast<MapCache*>(obj); 9663 int entry = cache->FindInsertionEntry(key.Hash()); 9664 cache->set(EntryToIndex(entry), array); 9665 cache->set(EntryToIndex(entry) + 1, value); 9666 cache->ElementAdded(); 9667 return cache; 9668 } 9669 9670 9671 template<typename Shape, typename Key> 9672 MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) { 9673 Object* obj; 9674 { MaybeObject* maybe_obj = 9675 HashTable<Shape, Key>::Allocate(at_least_space_for); 9676 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9677 } 9678 // Initialize the next enumeration index. 9679 Dictionary<Shape, Key>::cast(obj)-> 9680 SetNextEnumerationIndex(PropertyDetails::kInitialIndex); 9681 return obj; 9682 } 9683 9684 9685 template<typename Shape, typename Key> 9686 MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() { 9687 Heap* heap = Dictionary<Shape, Key>::GetHeap(); 9688 int length = HashTable<Shape, Key>::NumberOfElements(); 9689 9690 // Allocate and initialize iteration order array. 9691 Object* obj; 9692 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length); 9693 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9694 } 9695 FixedArray* iteration_order = FixedArray::cast(obj); 9696 for (int i = 0; i < length; i++) { 9697 iteration_order->set(i, Smi::FromInt(i)); 9698 } 9699 9700 // Allocate array with enumeration order. 9701 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length); 9702 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9703 } 9704 FixedArray* enumeration_order = FixedArray::cast(obj); 9705 9706 // Fill the enumeration order array with property details. 9707 int capacity = HashTable<Shape, Key>::Capacity(); 9708 int pos = 0; 9709 for (int i = 0; i < capacity; i++) { 9710 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { 9711 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index())); 9712 } 9713 } 9714 9715 // Sort the arrays wrt. enumeration order. 9716 iteration_order->SortPairs(enumeration_order, enumeration_order->length()); 9717 9718 // Overwrite the enumeration_order with the enumeration indices. 9719 for (int i = 0; i < length; i++) { 9720 int index = Smi::cast(iteration_order->get(i))->value(); 9721 int enum_index = PropertyDetails::kInitialIndex + i; 9722 enumeration_order->set(index, Smi::FromInt(enum_index)); 9723 } 9724 9725 // Update the dictionary with new indices. 9726 capacity = HashTable<Shape, Key>::Capacity(); 9727 pos = 0; 9728 for (int i = 0; i < capacity; i++) { 9729 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { 9730 int enum_index = Smi::cast(enumeration_order->get(pos++))->value(); 9731 PropertyDetails details = DetailsAt(i); 9732 PropertyDetails new_details = 9733 PropertyDetails(details.attributes(), details.type(), enum_index); 9734 DetailsAtPut(i, new_details); 9735 } 9736 } 9737 9738 // Set the next enumeration index. 9739 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length); 9740 return this; 9741 } 9742 9743 template<typename Shape, typename Key> 9744 MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) { 9745 // Check whether there are enough enumeration indices to add n elements. 9746 if (Shape::kIsEnumerable && 9747 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) { 9748 // If not, we generate new indices for the properties. 9749 Object* result; 9750 { MaybeObject* maybe_result = GenerateNewEnumerationIndices(); 9751 if (!maybe_result->ToObject(&result)) return maybe_result; 9752 } 9753 } 9754 return HashTable<Shape, Key>::EnsureCapacity(n, key); 9755 } 9756 9757 9758 void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) { 9759 // Do nothing if the interval [from, to) is empty. 9760 if (from >= to) return; 9761 9762 Heap* heap = GetHeap(); 9763 int removed_entries = 0; 9764 Object* sentinel = heap->null_value(); 9765 int capacity = Capacity(); 9766 for (int i = 0; i < capacity; i++) { 9767 Object* key = KeyAt(i); 9768 if (key->IsNumber()) { 9769 uint32_t number = static_cast<uint32_t>(key->Number()); 9770 if (from <= number && number < to) { 9771 SetEntry(i, sentinel, sentinel); 9772 removed_entries++; 9773 } 9774 } 9775 } 9776 9777 // Update the number of elements. 9778 ElementsRemoved(removed_entries); 9779 } 9780 9781 9782 template<typename Shape, typename Key> 9783 Object* Dictionary<Shape, Key>::DeleteProperty(int entry, 9784 JSObject::DeleteMode mode) { 9785 Heap* heap = Dictionary<Shape, Key>::GetHeap(); 9786 PropertyDetails details = DetailsAt(entry); 9787 // Ignore attributes if forcing a deletion. 9788 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) { 9789 return heap->false_value(); 9790 } 9791 SetEntry(entry, heap->null_value(), heap->null_value()); 9792 HashTable<Shape, Key>::ElementRemoved(); 9793 return heap->true_value(); 9794 } 9795 9796 9797 template<typename Shape, typename Key> 9798 MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) { 9799 int entry = this->FindEntry(key); 9800 9801 // If the entry is present set the value; 9802 if (entry != Dictionary<Shape, Key>::kNotFound) { 9803 ValueAtPut(entry, value); 9804 return this; 9805 } 9806 9807 // Check whether the dictionary should be extended. 9808 Object* obj; 9809 { MaybeObject* maybe_obj = EnsureCapacity(1, key); 9810 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9811 } 9812 9813 Object* k; 9814 { MaybeObject* maybe_k = Shape::AsObject(key); 9815 if (!maybe_k->ToObject(&k)) return maybe_k; 9816 } 9817 PropertyDetails details = PropertyDetails(NONE, NORMAL); 9818 return Dictionary<Shape, Key>::cast(obj)-> 9819 AddEntry(key, value, details, Shape::Hash(key)); 9820 } 9821 9822 9823 template<typename Shape, typename Key> 9824 MaybeObject* Dictionary<Shape, Key>::Add(Key key, 9825 Object* value, 9826 PropertyDetails details) { 9827 // Valdate key is absent. 9828 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound)); 9829 // Check whether the dictionary should be extended. 9830 Object* obj; 9831 { MaybeObject* maybe_obj = EnsureCapacity(1, key); 9832 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9833 } 9834 return Dictionary<Shape, Key>::cast(obj)-> 9835 AddEntry(key, value, details, Shape::Hash(key)); 9836 } 9837 9838 9839 // Add a key, value pair to the dictionary. 9840 template<typename Shape, typename Key> 9841 MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key, 9842 Object* value, 9843 PropertyDetails details, 9844 uint32_t hash) { 9845 // Compute the key object. 9846 Object* k; 9847 { MaybeObject* maybe_k = Shape::AsObject(key); 9848 if (!maybe_k->ToObject(&k)) return maybe_k; 9849 } 9850 9851 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash); 9852 // Insert element at empty or deleted entry 9853 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) { 9854 // Assign an enumeration index to the property and update 9855 // SetNextEnumerationIndex. 9856 int index = NextEnumerationIndex(); 9857 details = PropertyDetails(details.attributes(), details.type(), index); 9858 SetNextEnumerationIndex(index + 1); 9859 } 9860 SetEntry(entry, k, value, details); 9861 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber() 9862 || Dictionary<Shape, Key>::KeyAt(entry)->IsString())); 9863 HashTable<Shape, Key>::ElementAdded(); 9864 return this; 9865 } 9866 9867 9868 void NumberDictionary::UpdateMaxNumberKey(uint32_t key) { 9869 // If the dictionary requires slow elements an element has already 9870 // been added at a high index. 9871 if (requires_slow_elements()) return; 9872 // Check if this index is high enough that we should require slow 9873 // elements. 9874 if (key > kRequiresSlowElementsLimit) { 9875 set_requires_slow_elements(); 9876 return; 9877 } 9878 // Update max key value. 9879 Object* max_index_object = get(kMaxNumberKeyIndex); 9880 if (!max_index_object->IsSmi() || max_number_key() < key) { 9881 FixedArray::set(kMaxNumberKeyIndex, 9882 Smi::FromInt(key << kRequiresSlowElementsTagSize)); 9883 } 9884 } 9885 9886 9887 MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key, 9888 Object* value, 9889 PropertyDetails details) { 9890 UpdateMaxNumberKey(key); 9891 SLOW_ASSERT(this->FindEntry(key) == kNotFound); 9892 return Add(key, value, details); 9893 } 9894 9895 9896 MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) { 9897 UpdateMaxNumberKey(key); 9898 return AtPut(key, value); 9899 } 9900 9901 9902 MaybeObject* NumberDictionary::Set(uint32_t key, 9903 Object* value, 9904 PropertyDetails details) { 9905 int entry = FindEntry(key); 9906 if (entry == kNotFound) return AddNumberEntry(key, value, details); 9907 // Preserve enumeration index. 9908 details = PropertyDetails(details.attributes(), 9909 details.type(), 9910 DetailsAt(entry).index()); 9911 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key); 9912 Object* object_key; 9913 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key; 9914 SetEntry(entry, object_key, value, details); 9915 return this; 9916 } 9917 9918 9919 9920 template<typename Shape, typename Key> 9921 int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes( 9922 PropertyAttributes filter) { 9923 int capacity = HashTable<Shape, Key>::Capacity(); 9924 int result = 0; 9925 for (int i = 0; i < capacity; i++) { 9926 Object* k = HashTable<Shape, Key>::KeyAt(i); 9927 if (HashTable<Shape, Key>::IsKey(k)) { 9928 PropertyDetails details = DetailsAt(i); 9929 if (details.IsDeleted()) continue; 9930 PropertyAttributes attr = details.attributes(); 9931 if ((attr & filter) == 0) result++; 9932 } 9933 } 9934 return result; 9935 } 9936 9937 9938 template<typename Shape, typename Key> 9939 int Dictionary<Shape, Key>::NumberOfEnumElements() { 9940 return NumberOfElementsFilterAttributes( 9941 static_cast<PropertyAttributes>(DONT_ENUM)); 9942 } 9943 9944 9945 template<typename Shape, typename Key> 9946 void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage, 9947 PropertyAttributes filter) { 9948 ASSERT(storage->length() >= NumberOfEnumElements()); 9949 int capacity = HashTable<Shape, Key>::Capacity(); 9950 int index = 0; 9951 for (int i = 0; i < capacity; i++) { 9952 Object* k = HashTable<Shape, Key>::KeyAt(i); 9953 if (HashTable<Shape, Key>::IsKey(k)) { 9954 PropertyDetails details = DetailsAt(i); 9955 if (details.IsDeleted()) continue; 9956 PropertyAttributes attr = details.attributes(); 9957 if ((attr & filter) == 0) storage->set(index++, k); 9958 } 9959 } 9960 storage->SortPairs(storage, index); 9961 ASSERT(storage->length() >= index); 9962 } 9963 9964 9965 void StringDictionary::CopyEnumKeysTo(FixedArray* storage, 9966 FixedArray* sort_array) { 9967 ASSERT(storage->length() >= NumberOfEnumElements()); 9968 int capacity = Capacity(); 9969 int index = 0; 9970 for (int i = 0; i < capacity; i++) { 9971 Object* k = KeyAt(i); 9972 if (IsKey(k)) { 9973 PropertyDetails details = DetailsAt(i); 9974 if (details.IsDeleted() || details.IsDontEnum()) continue; 9975 storage->set(index, k); 9976 sort_array->set(index, Smi::FromInt(details.index())); 9977 index++; 9978 } 9979 } 9980 storage->SortPairs(sort_array, sort_array->length()); 9981 ASSERT(storage->length() >= index); 9982 } 9983 9984 9985 template<typename Shape, typename Key> 9986 void Dictionary<Shape, Key>::CopyKeysTo( 9987 FixedArray* storage, int index) { 9988 ASSERT(storage->length() >= NumberOfElementsFilterAttributes( 9989 static_cast<PropertyAttributes>(NONE))); 9990 int capacity = HashTable<Shape, Key>::Capacity(); 9991 for (int i = 0; i < capacity; i++) { 9992 Object* k = HashTable<Shape, Key>::KeyAt(i); 9993 if (HashTable<Shape, Key>::IsKey(k)) { 9994 PropertyDetails details = DetailsAt(i); 9995 if (details.IsDeleted()) continue; 9996 storage->set(index++, k); 9997 } 9998 } 9999 ASSERT(storage->length() >= index); 10000 } 10001 10002 10003 // Backwards lookup (slow). 10004 template<typename Shape, typename Key> 10005 Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) { 10006 int capacity = HashTable<Shape, Key>::Capacity(); 10007 for (int i = 0; i < capacity; i++) { 10008 Object* k = HashTable<Shape, Key>::KeyAt(i); 10009 if (Dictionary<Shape, Key>::IsKey(k)) { 10010 Object* e = ValueAt(i); 10011 if (e->IsJSGlobalPropertyCell()) { 10012 e = JSGlobalPropertyCell::cast(e)->value(); 10013 } 10014 if (e == value) return k; 10015 } 10016 } 10017 Heap* heap = Dictionary<Shape, Key>::GetHeap(); 10018 return heap->undefined_value(); 10019 } 10020 10021 10022 MaybeObject* StringDictionary::TransformPropertiesToFastFor( 10023 JSObject* obj, int unused_property_fields) { 10024 // Make sure we preserve dictionary representation if there are too many 10025 // descriptors. 10026 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj; 10027 10028 // Figure out if it is necessary to generate new enumeration indices. 10029 int max_enumeration_index = 10030 NextEnumerationIndex() + 10031 (DescriptorArray::kMaxNumberOfDescriptors - 10032 NumberOfElements()); 10033 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) { 10034 Object* result; 10035 { MaybeObject* maybe_result = GenerateNewEnumerationIndices(); 10036 if (!maybe_result->ToObject(&result)) return maybe_result; 10037 } 10038 } 10039 10040 int instance_descriptor_length = 0; 10041 int number_of_fields = 0; 10042 10043 Heap* heap = GetHeap(); 10044 10045 // Compute the length of the instance descriptor. 10046 int capacity = Capacity(); 10047 for (int i = 0; i < capacity; i++) { 10048 Object* k = KeyAt(i); 10049 if (IsKey(k)) { 10050 Object* value = ValueAt(i); 10051 PropertyType type = DetailsAt(i).type(); 10052 ASSERT(type != FIELD); 10053 instance_descriptor_length++; 10054 if (type == NORMAL && 10055 (!value->IsJSFunction() || heap->InNewSpace(value))) { 10056 number_of_fields += 1; 10057 } 10058 } 10059 } 10060 10061 // Allocate the instance descriptor. 10062 Object* descriptors_unchecked; 10063 { MaybeObject* maybe_descriptors_unchecked = 10064 DescriptorArray::Allocate(instance_descriptor_length); 10065 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) { 10066 return maybe_descriptors_unchecked; 10067 } 10068 } 10069 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked); 10070 10071 int inobject_props = obj->map()->inobject_properties(); 10072 int number_of_allocated_fields = 10073 number_of_fields + unused_property_fields - inobject_props; 10074 if (number_of_allocated_fields < 0) { 10075 // There is enough inobject space for all fields (including unused). 10076 number_of_allocated_fields = 0; 10077 unused_property_fields = inobject_props - number_of_fields; 10078 } 10079 10080 // Allocate the fixed array for the fields. 10081 Object* fields; 10082 { MaybeObject* maybe_fields = 10083 heap->AllocateFixedArray(number_of_allocated_fields); 10084 if (!maybe_fields->ToObject(&fields)) return maybe_fields; 10085 } 10086 10087 // Fill in the instance descriptor and the fields. 10088 int next_descriptor = 0; 10089 int current_offset = 0; 10090 for (int i = 0; i < capacity; i++) { 10091 Object* k = KeyAt(i); 10092 if (IsKey(k)) { 10093 Object* value = ValueAt(i); 10094 // Ensure the key is a symbol before writing into the instance descriptor. 10095 Object* key; 10096 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k)); 10097 if (!maybe_key->ToObject(&key)) return maybe_key; 10098 } 10099 PropertyDetails details = DetailsAt(i); 10100 PropertyType type = details.type(); 10101 10102 if (value->IsJSFunction() && !heap->InNewSpace(value)) { 10103 ConstantFunctionDescriptor d(String::cast(key), 10104 JSFunction::cast(value), 10105 details.attributes(), 10106 details.index()); 10107 descriptors->Set(next_descriptor++, &d); 10108 } else if (type == NORMAL) { 10109 if (current_offset < inobject_props) { 10110 obj->InObjectPropertyAtPut(current_offset, 10111 value, 10112 UPDATE_WRITE_BARRIER); 10113 } else { 10114 int offset = current_offset - inobject_props; 10115 FixedArray::cast(fields)->set(offset, value); 10116 } 10117 FieldDescriptor d(String::cast(key), 10118 current_offset++, 10119 details.attributes(), 10120 details.index()); 10121 descriptors->Set(next_descriptor++, &d); 10122 } else if (type == CALLBACKS) { 10123 CallbacksDescriptor d(String::cast(key), 10124 value, 10125 details.attributes(), 10126 details.index()); 10127 descriptors->Set(next_descriptor++, &d); 10128 } else { 10129 UNREACHABLE(); 10130 } 10131 } 10132 } 10133 ASSERT(current_offset == number_of_fields); 10134 10135 descriptors->Sort(); 10136 // Allocate new map. 10137 Object* new_map; 10138 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors(); 10139 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 10140 } 10141 10142 // Transform the object. 10143 obj->set_map(Map::cast(new_map)); 10144 obj->map()->set_instance_descriptors(descriptors); 10145 obj->map()->set_unused_property_fields(unused_property_fields); 10146 10147 obj->set_properties(FixedArray::cast(fields)); 10148 ASSERT(obj->IsJSObject()); 10149 10150 descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); 10151 // Check that it really works. 10152 ASSERT(obj->HasFastProperties()); 10153 10154 return obj; 10155 } 10156 10157 10158 #ifdef ENABLE_DEBUGGER_SUPPORT 10159 // Check if there is a break point at this code position. 10160 bool DebugInfo::HasBreakPoint(int code_position) { 10161 // Get the break point info object for this code position. 10162 Object* break_point_info = GetBreakPointInfo(code_position); 10163 10164 // If there is no break point info object or no break points in the break 10165 // point info object there is no break point at this code position. 10166 if (break_point_info->IsUndefined()) return false; 10167 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0; 10168 } 10169 10170 10171 // Get the break point info object for this code position. 10172 Object* DebugInfo::GetBreakPointInfo(int code_position) { 10173 // Find the index of the break point info object for this code position. 10174 int index = GetBreakPointInfoIndex(code_position); 10175 10176 // Return the break point info object if any. 10177 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value(); 10178 return BreakPointInfo::cast(break_points()->get(index)); 10179 } 10180 10181 10182 // Clear a break point at the specified code position. 10183 void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info, 10184 int code_position, 10185 Handle<Object> break_point_object) { 10186 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position)); 10187 if (break_point_info->IsUndefined()) return; 10188 BreakPointInfo::ClearBreakPoint( 10189 Handle<BreakPointInfo>::cast(break_point_info), 10190 break_point_object); 10191 } 10192 10193 10194 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, 10195 int code_position, 10196 int source_position, 10197 int statement_position, 10198 Handle<Object> break_point_object) { 10199 Isolate* isolate = Isolate::Current(); 10200 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position)); 10201 if (!break_point_info->IsUndefined()) { 10202 BreakPointInfo::SetBreakPoint( 10203 Handle<BreakPointInfo>::cast(break_point_info), 10204 break_point_object); 10205 return; 10206 } 10207 10208 // Adding a new break point for a code position which did not have any 10209 // break points before. Try to find a free slot. 10210 int index = kNoBreakPointInfo; 10211 for (int i = 0; i < debug_info->break_points()->length(); i++) { 10212 if (debug_info->break_points()->get(i)->IsUndefined()) { 10213 index = i; 10214 break; 10215 } 10216 } 10217 if (index == kNoBreakPointInfo) { 10218 // No free slot - extend break point info array. 10219 Handle<FixedArray> old_break_points = 10220 Handle<FixedArray>(FixedArray::cast(debug_info->break_points())); 10221 Handle<FixedArray> new_break_points = 10222 isolate->factory()->NewFixedArray( 10223 old_break_points->length() + 10224 Debug::kEstimatedNofBreakPointsInFunction); 10225 10226 debug_info->set_break_points(*new_break_points); 10227 for (int i = 0; i < old_break_points->length(); i++) { 10228 new_break_points->set(i, old_break_points->get(i)); 10229 } 10230 index = old_break_points->length(); 10231 } 10232 ASSERT(index != kNoBreakPointInfo); 10233 10234 // Allocate new BreakPointInfo object and set the break point. 10235 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast( 10236 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE)); 10237 new_break_point_info->set_code_position(Smi::FromInt(code_position)); 10238 new_break_point_info->set_source_position(Smi::FromInt(source_position)); 10239 new_break_point_info-> 10240 set_statement_position(Smi::FromInt(statement_position)); 10241 new_break_point_info->set_break_point_objects( 10242 isolate->heap()->undefined_value()); 10243 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object); 10244 debug_info->break_points()->set(index, *new_break_point_info); 10245 } 10246 10247 10248 // Get the break point objects for a code position. 10249 Object* DebugInfo::GetBreakPointObjects(int code_position) { 10250 Object* break_point_info = GetBreakPointInfo(code_position); 10251 if (break_point_info->IsUndefined()) { 10252 return GetHeap()->undefined_value(); 10253 } 10254 return BreakPointInfo::cast(break_point_info)->break_point_objects(); 10255 } 10256 10257 10258 // Get the total number of break points. 10259 int DebugInfo::GetBreakPointCount() { 10260 if (break_points()->IsUndefined()) return 0; 10261 int count = 0; 10262 for (int i = 0; i < break_points()->length(); i++) { 10263 if (!break_points()->get(i)->IsUndefined()) { 10264 BreakPointInfo* break_point_info = 10265 BreakPointInfo::cast(break_points()->get(i)); 10266 count += break_point_info->GetBreakPointCount(); 10267 } 10268 } 10269 return count; 10270 } 10271 10272 10273 Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info, 10274 Handle<Object> break_point_object) { 10275 Heap* heap = debug_info->GetHeap(); 10276 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value(); 10277 for (int i = 0; i < debug_info->break_points()->length(); i++) { 10278 if (!debug_info->break_points()->get(i)->IsUndefined()) { 10279 Handle<BreakPointInfo> break_point_info = 10280 Handle<BreakPointInfo>(BreakPointInfo::cast( 10281 debug_info->break_points()->get(i))); 10282 if (BreakPointInfo::HasBreakPointObject(break_point_info, 10283 break_point_object)) { 10284 return *break_point_info; 10285 } 10286 } 10287 } 10288 return heap->undefined_value(); 10289 } 10290 10291 10292 // Find the index of the break point info object for the specified code 10293 // position. 10294 int DebugInfo::GetBreakPointInfoIndex(int code_position) { 10295 if (break_points()->IsUndefined()) return kNoBreakPointInfo; 10296 for (int i = 0; i < break_points()->length(); i++) { 10297 if (!break_points()->get(i)->IsUndefined()) { 10298 BreakPointInfo* break_point_info = 10299 BreakPointInfo::cast(break_points()->get(i)); 10300 if (break_point_info->code_position()->value() == code_position) { 10301 return i; 10302 } 10303 } 10304 } 10305 return kNoBreakPointInfo; 10306 } 10307 10308 10309 // Remove the specified break point object. 10310 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info, 10311 Handle<Object> break_point_object) { 10312 Isolate* isolate = Isolate::Current(); 10313 // If there are no break points just ignore. 10314 if (break_point_info->break_point_objects()->IsUndefined()) return; 10315 // If there is a single break point clear it if it is the same. 10316 if (!break_point_info->break_point_objects()->IsFixedArray()) { 10317 if (break_point_info->break_point_objects() == *break_point_object) { 10318 break_point_info->set_break_point_objects( 10319 isolate->heap()->undefined_value()); 10320 } 10321 return; 10322 } 10323 // If there are multiple break points shrink the array 10324 ASSERT(break_point_info->break_point_objects()->IsFixedArray()); 10325 Handle<FixedArray> old_array = 10326 Handle<FixedArray>( 10327 FixedArray::cast(break_point_info->break_point_objects())); 10328 Handle<FixedArray> new_array = 10329 isolate->factory()->NewFixedArray(old_array->length() - 1); 10330 int found_count = 0; 10331 for (int i = 0; i < old_array->length(); i++) { 10332 if (old_array->get(i) == *break_point_object) { 10333 ASSERT(found_count == 0); 10334 found_count++; 10335 } else { 10336 new_array->set(i - found_count, old_array->get(i)); 10337 } 10338 } 10339 // If the break point was found in the list change it. 10340 if (found_count > 0) break_point_info->set_break_point_objects(*new_array); 10341 } 10342 10343 10344 // Add the specified break point object. 10345 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info, 10346 Handle<Object> break_point_object) { 10347 // If there was no break point objects before just set it. 10348 if (break_point_info->break_point_objects()->IsUndefined()) { 10349 break_point_info->set_break_point_objects(*break_point_object); 10350 return; 10351 } 10352 // If the break point object is the same as before just ignore. 10353 if (break_point_info->break_point_objects() == *break_point_object) return; 10354 // If there was one break point object before replace with array. 10355 if (!break_point_info->break_point_objects()->IsFixedArray()) { 10356 Handle<FixedArray> array = FACTORY->NewFixedArray(2); 10357 array->set(0, break_point_info->break_point_objects()); 10358 array->set(1, *break_point_object); 10359 break_point_info->set_break_point_objects(*array); 10360 return; 10361 } 10362 // If there was more than one break point before extend array. 10363 Handle<FixedArray> old_array = 10364 Handle<FixedArray>( 10365 FixedArray::cast(break_point_info->break_point_objects())); 10366 Handle<FixedArray> new_array = 10367 FACTORY->NewFixedArray(old_array->length() + 1); 10368 for (int i = 0; i < old_array->length(); i++) { 10369 // If the break point was there before just ignore. 10370 if (old_array->get(i) == *break_point_object) return; 10371 new_array->set(i, old_array->get(i)); 10372 } 10373 // Add the new break point. 10374 new_array->set(old_array->length(), *break_point_object); 10375 break_point_info->set_break_point_objects(*new_array); 10376 } 10377 10378 10379 bool BreakPointInfo::HasBreakPointObject( 10380 Handle<BreakPointInfo> break_point_info, 10381 Handle<Object> break_point_object) { 10382 // No break point. 10383 if (break_point_info->break_point_objects()->IsUndefined()) return false; 10384 // Single beak point. 10385 if (!break_point_info->break_point_objects()->IsFixedArray()) { 10386 return break_point_info->break_point_objects() == *break_point_object; 10387 } 10388 // Multiple break points. 10389 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects()); 10390 for (int i = 0; i < array->length(); i++) { 10391 if (array->get(i) == *break_point_object) { 10392 return true; 10393 } 10394 } 10395 return false; 10396 } 10397 10398 10399 // Get the number of break points. 10400 int BreakPointInfo::GetBreakPointCount() { 10401 // No break point. 10402 if (break_point_objects()->IsUndefined()) return 0; 10403 // Single beak point. 10404 if (!break_point_objects()->IsFixedArray()) return 1; 10405 // Multiple break points. 10406 return FixedArray::cast(break_point_objects())->length(); 10407 } 10408 #endif 10409 10410 10411 } } // namespace v8::internal 10412