Home | History | Annotate | Download | only in src
      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