Update V8 to r3431 as required by WebKit r51976.

Change-Id: I567392c3f8c0a0d5201a4249611ac4ccf468cd5b
diff --git a/src/objects.cc b/src/objects.cc
index af1a0e5..0f8dca3 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -37,6 +37,7 @@
 #include "scanner.h"
 #include "scopeinfo.h"
 #include "string-stream.h"
+#include "utils.h"
 
 #ifdef ENABLE_DISASSEMBLER
 #include "disassembler.h"
@@ -683,23 +684,6 @@
 #endif
 
   switch (StringShape(this).representation_tag()) {
-    case kSlicedStringTag: {
-      SlicedString* ss = SlicedString::cast(this);
-      // The SlicedString constructor should ensure that there are no
-      // SlicedStrings that are constructed directly on top of other
-      // SlicedStrings.
-      String* buf = ss->buffer();
-      ASSERT(!buf->IsSlicedString());
-      Object* ok = buf->TryFlatten();
-      if (ok->IsFailure()) return ok;
-      // Under certain circumstances (TryFlattenIfNotFlat fails in
-      // String::Slice) we can have a cons string under a slice.
-      // In this case we need to get the flat string out of the cons!
-      if (StringShape(String::cast(ok)).IsCons()) {
-        ss->set_buffer(ConsString::cast(ok)->first());
-      }
-      return this;
-    }
     case kConsStringTag: {
       ConsString* cs = ConsString::cast(this);
       if (cs->second()->length() == 0) {
@@ -771,19 +755,21 @@
   ASSERT(size >= ExternalString::kSize);
   bool is_symbol = this->IsSymbol();
   int length = this->length();
+  int hash_field = this->hash_field();
 
   // Morph the object to an external string by adjusting the map and
   // reinitializing the fields.
-  this->set_map(ExternalTwoByteString::StringMap(length));
+  this->set_map(Heap::external_string_map());
   ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
   self->set_length(length);
+  self->set_hash_field(hash_field);
   self->set_resource(resource);
   // Additionally make the object into an external symbol if the original string
   // was a symbol to start with.
   if (is_symbol) {
     self->Hash();  // Force regeneration of the hash value.
     // Now morph this external string into a external symbol.
-    self->set_map(ExternalTwoByteString::SymbolMap(length));
+    this->set_map(Heap::external_symbol_map());
   }
 
   // Fill the remainder of the string with dead wood.
@@ -815,19 +801,21 @@
   ASSERT(size >= ExternalString::kSize);
   bool is_symbol = this->IsSymbol();
   int length = this->length();
+  int hash_field = this->hash_field();
 
   // Morph the object to an external string by adjusting the map and
   // reinitializing the fields.
-  this->set_map(ExternalAsciiString::StringMap(length));
+  this->set_map(Heap::external_ascii_string_map());
   ExternalAsciiString* self = ExternalAsciiString::cast(this);
   self->set_length(length);
+  self->set_hash_field(hash_field);
   self->set_resource(resource);
   // Additionally make the object into an external symbol if the original string
   // was a symbol to start with.
   if (is_symbol) {
     self->Hash();  // Force regeneration of the hash value.
     // Now morph this external string into a external symbol.
-    self->set_map(ExternalAsciiString::SymbolMap(length));
+    this->set_map(Heap::external_ascii_symbol_map());
   }
 
   // Fill the remainder of the string with dead wood.
@@ -839,7 +827,7 @@
 
 void String::StringShortPrint(StringStream* accumulator) {
   int len = length();
-  if (len > kMaxMediumStringSize) {
+  if (len > kMaxShortPrintLength) {
     accumulator->Add("<Very long string[%u]>", len);
     return;
   }
@@ -1135,8 +1123,14 @@
       case kConsStringTag:
         reinterpret_cast<ConsString*>(this)->ConsStringIterateBody(v);
         break;
-      case kSlicedStringTag:
-        reinterpret_cast<SlicedString*>(this)->SlicedStringIterateBody(v);
+      case kExternalStringTag:
+        if ((type & kStringEncodingMask) == kAsciiStringTag) {
+          reinterpret_cast<ExternalAsciiString*>(this)->
+              ExternalAsciiStringIterateBody(v);
+        } else {
+          reinterpret_cast<ExternalTwoByteString*>(this)->
+              ExternalTwoByteStringIterateBody(v);
+        }
         break;
     }
     return;
@@ -1251,7 +1245,8 @@
 
 String* JSObject::constructor_name() {
   if (IsJSFunction()) {
-    return Heap::function_class_symbol();
+    return JSFunction::cast(this)->IsBoilerplate() ?
+      Heap::function_class_symbol() : Heap::closure_symbol();
   }
   if (map()->constructor()->IsJSFunction()) {
     JSFunction* constructor = JSFunction::cast(map()->constructor());
@@ -1473,8 +1468,8 @@
 
 
 Object* JSObject::ReplaceSlowProperty(String* name,
-                                       Object* value,
-                                       PropertyAttributes attributes) {
+                                      Object* value,
+                                      PropertyAttributes attributes) {
   StringDictionary* dictionary = property_dictionary();
   int old_index = dictionary->FindEntry(name);
   int new_enumeration_index = 0;  // 0 means "Use the next available index."
@@ -1488,6 +1483,7 @@
   return SetNormalizedProperty(name, value, new_details);
 }
 
+
 Object* JSObject::ConvertDescriptorToFieldAndMapTransition(
     String* name,
     Object* new_value,
@@ -1879,6 +1875,14 @@
   // interceptor calls.
   AssertNoContextChange ncc;
 
+  // Optimization for 2-byte strings often used as keys in a decompression
+  // dictionary.  We make these short keys into symbols to avoid constantly
+  // reallocating them.
+  if (!name->IsSymbol() && name->length() <= 2) {
+    Object* symbol_version = Heap::LookupSymbol(name);
+    if (!symbol_version->IsFailure()) name = String::cast(symbol_version);
+  }
+
   // Check access rights if needed.
   if (IsAccessCheckNeeded()
       && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
@@ -2629,33 +2633,24 @@
 
 
 // Tests for the fast common case for property enumeration:
-// - this object has an enum cache
-// - this object has no elements
-// - no prototype has enumerable properties/elements
-// - neither this object nor any prototype has interceptors
+// - This object and all prototypes has an enum cache (which means that it has
+//   no interceptors and needs no access checks).
+// - This object has no elements.
+// - No prototype has enumerable properties/elements.
 bool JSObject::IsSimpleEnum() {
-  JSObject* arguments_boilerplate =
-      Top::context()->global_context()->arguments_boilerplate();
-  JSFunction* arguments_function =
-      JSFunction::cast(arguments_boilerplate->map()->constructor());
-  if (IsAccessCheckNeeded()) return false;
-  if (map()->constructor() == arguments_function) return false;
-
   for (Object* o = this;
        o != Heap::null_value();
        o = JSObject::cast(o)->GetPrototype()) {
     JSObject* curr = JSObject::cast(o);
-    if (!curr->HasFastProperties()) return false;
     if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
+    ASSERT(!curr->HasNamedInterceptor());
+    ASSERT(!curr->HasIndexedInterceptor());
+    ASSERT(!curr->IsAccessCheckNeeded());
     if (curr->NumberOfEnumElements() > 0) return false;
-    if (curr->HasNamedInterceptor()) return false;
-    if (curr->HasIndexedInterceptor()) return false;
     if (curr != this) {
       FixedArray* curr_fixed_array =
           FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
-      if (curr_fixed_array->length() > 0) {
-        return false;
-      }
+      if (curr_fixed_array->length() > 0) return false;
     }
   }
   return true;
@@ -3561,12 +3556,7 @@
   int length = this->length();
   StringRepresentationTag string_tag = StringShape(this).representation_tag();
   String* string = this;
-  if (string_tag == kSlicedStringTag) {
-    SlicedString* sliced = SlicedString::cast(string);
-    offset += sliced->start();
-    string = sliced->buffer();
-    string_tag = StringShape(string).representation_tag();
-  } else if (string_tag == kConsStringTag) {
+  if (string_tag == kConsStringTag) {
     ConsString* cons = ConsString::cast(string);
     ASSERT(cons->second()->length() == 0);
     string = cons->first();
@@ -3592,12 +3582,7 @@
   int length = this->length();
   StringRepresentationTag string_tag = StringShape(this).representation_tag();
   String* string = this;
-  if (string_tag == kSlicedStringTag) {
-    SlicedString* sliced = SlicedString::cast(string);
-    offset += sliced->start();
-    string = String::cast(sliced->buffer());
-    string_tag = StringShape(string).representation_tag();
-  } else if (string_tag == kConsStringTag) {
+  if (string_tag == kConsStringTag) {
     ConsString* cons = ConsString::cast(string);
     ASSERT(cons->second()->length() == 0);
     string = cons->first();
@@ -3688,17 +3673,6 @@
     case kExternalStringTag:
       return ExternalTwoByteString::cast(this)->
         ExternalTwoByteStringGetData(start);
-    case kSlicedStringTag: {
-      SlicedString* sliced_string = SlicedString::cast(this);
-      String* buffer = sliced_string->buffer();
-      if (StringShape(buffer).IsCons()) {
-        ConsString* cs = ConsString::cast(buffer);
-        // Flattened string.
-        ASSERT(cs->second()->length() == 0);
-        buffer = cs->first();
-      }
-      return buffer->GetTwoByteData(start + sliced_string->start());
-    }
     case kConsStringTag:
       UNREACHABLE();
       return NULL;
@@ -3853,22 +3827,6 @@
 }
 
 
-const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb,
-                                                         unsigned* offset_ptr,
-                                                         unsigned max_chars) {
-  String* backing = buffer();
-  unsigned offset = start() + *offset_ptr;
-  unsigned length = backing->length();
-  if (max_chars > length - offset) {
-    max_chars = length - offset;
-  }
-  const unibrow::byte* answer =
-      String::ReadBlock(backing, rbb, &offset, max_chars);
-  *offset_ptr = offset - start();
-  return answer;
-}
-
-
 uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
   ASSERT(index >= 0 && index < length());
   return resource()->data()[index];
@@ -3992,10 +3950,6 @@
       return ConsString::cast(input)->ConsStringReadBlock(rbb,
                                                           offset_ptr,
                                                           max_chars);
-    case kSlicedStringTag:
-      return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
-                                                              offset_ptr,
-                                                              max_chars);
     case kExternalStringTag:
       if (input->IsAsciiRepresentation()) {
         return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
@@ -4138,20 +4092,15 @@
                                                              offset_ptr,
                                                              max_chars);
       return;
-    case kSlicedStringTag:
-      SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
-                                                                 offset_ptr,
-                                                                 max_chars);
-      return;
     case kExternalStringTag:
       if (input->IsAsciiRepresentation()) {
-         ExternalAsciiString::cast(input)->
-             ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
-       } else {
-         ExternalTwoByteString::cast(input)->
-             ExternalTwoByteStringReadBlockIntoBuffer(rbb,
-                                                      offset_ptr,
-                                                      max_chars);
+        ExternalAsciiString::cast(input)->
+            ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
+      } else {
+        ExternalTwoByteString::cast(input)->
+            ExternalTwoByteStringReadBlockIntoBuffer(rbb,
+                                                     offset_ptr,
+                                                     max_chars);
        }
        return;
     default:
@@ -4257,20 +4206,6 @@
 }
 
 
-void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
-                                                   unsigned* offset_ptr,
-                                                   unsigned max_chars) {
-  String* backing = buffer();
-  unsigned offset = start() + *offset_ptr;
-  unsigned length = backing->length();
-  if (max_chars > length - offset) {
-    max_chars = length - offset;
-  }
-  String::ReadBlockIntoBuffer(backing, rbb, &offset, max_chars);
-  *offset_ptr = offset - start();
-}
-
-
 void ConsString::ConsStringIterateBody(ObjectVisitor* v) {
   IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize);
 }
@@ -4349,15 +4284,6 @@
                   to - from);
         return;
       }
-      case kAsciiStringTag | kSlicedStringTag:
-      case kTwoByteStringTag | kSlicedStringTag: {
-        SlicedString* sliced_string = SlicedString::cast(source);
-        int start = sliced_string->start();
-        from += start;
-        to += start;
-        source = String::cast(sliced_string->buffer());
-        break;
-      }
       case kAsciiStringTag | kConsStringTag:
       case kTwoByteStringTag | kConsStringTag: {
         ConsString* cons_string = ConsString::cast(source);
@@ -4393,18 +4319,23 @@
 }
 
 
-void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) {
-  IteratePointer(v, kBufferOffset);
+#define FIELD_ADDR(p, offset) \
+  (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
+
+void ExternalAsciiString::ExternalAsciiStringIterateBody(ObjectVisitor* v) {
+  typedef v8::String::ExternalAsciiStringResource Resource;
+  v->VisitExternalAsciiString(
+      reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)));
 }
 
 
-uint16_t SlicedString::SlicedStringGet(int index) {
-  ASSERT(index >= 0 && index < this->length());
-  // Delegate to the buffer string.
-  String* underlying = buffer();
-  return underlying->Get(start() + index);
+void ExternalTwoByteString::ExternalTwoByteStringIterateBody(ObjectVisitor* v) {
+  typedef v8::String::ExternalStringResource Resource;
+  v->VisitExternalTwoByteString(
+      reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)));
 }
 
+#undef FIELD_ADDR
 
 template <typename IteratorA, typename IteratorB>
 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
@@ -4549,23 +4480,11 @@
   if (StringShape(this).IsSymbol()) return false;
 
   Map* map = this->map();
-  if (map == Heap::short_string_map()) {
-    this->set_map(Heap::undetectable_short_string_map());
+  if (map == Heap::string_map()) {
+    this->set_map(Heap::undetectable_string_map());
     return true;
-  } else if (map == Heap::medium_string_map()) {
-    this->set_map(Heap::undetectable_medium_string_map());
-    return true;
-  } else if (map == Heap::long_string_map()) {
-    this->set_map(Heap::undetectable_long_string_map());
-    return true;
-  } else if (map == Heap::short_ascii_string_map()) {
-    this->set_map(Heap::undetectable_short_ascii_string_map());
-    return true;
-  } else if (map == Heap::medium_ascii_string_map()) {
-    this->set_map(Heap::undetectable_medium_ascii_string_map());
-    return true;
-  } else if (map == Heap::long_ascii_string_map()) {
-    this->set_map(Heap::undetectable_long_ascii_string_map());
+  } else if (map == Heap::ascii_string_map()) {
+    this->set_map(Heap::undetectable_ascii_string_map());
     return true;
   }
   // Rest cannot be marked as undetectable
@@ -4588,17 +4507,17 @@
 
 uint32_t String::ComputeAndSetHash() {
   // Should only be called if hash code has not yet been computed.
-  ASSERT(!(length_field() & kHashComputedMask));
+  ASSERT(!(hash_field() & kHashComputedMask));
 
   // Compute the hash code.
   StringInputBuffer buffer(this);
-  uint32_t field = ComputeLengthAndHashField(&buffer, length());
+  uint32_t field = ComputeHashField(&buffer, length());
 
   // Store the hash code in the object.
-  set_length_field(field);
+  set_hash_field(field);
 
   // Check the hash code is there.
-  ASSERT(length_field() & kHashComputedMask);
+  ASSERT(hash_field() & kHashComputedMask);
   uint32_t result = field >> kHashShift;
   ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
   return result;
@@ -4638,9 +4557,10 @@
 bool String::SlowAsArrayIndex(uint32_t* index) {
   if (length() <= kMaxCachedArrayIndexLength) {
     Hash();  // force computation of hash code
-    uint32_t field = length_field();
+    uint32_t field = hash_field();
     if ((field & kIsArrayIndexMask) == 0) return false;
-    *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift;
+    // Isolate the array index form the full hash field.
+    *index = (kArrayIndexHashMask & field) >> kHashShift;
     return true;
   } else {
     StringInputBuffer buffer(this);
@@ -4649,37 +4569,42 @@
 }
 
 
-static inline uint32_t HashField(uint32_t hash, bool is_array_index) {
+static inline uint32_t HashField(uint32_t hash,
+                                 bool is_array_index,
+                                 int length = -1) {
   uint32_t result =
-      (hash << String::kLongLengthShift) | String::kHashComputedMask;
-  if (is_array_index) result |= String::kIsArrayIndexMask;
+      (hash << String::kHashShift) | String::kHashComputedMask;
+  if (is_array_index) {
+    // For array indexes mix the length into the hash as an array index could
+    // be zero.
+    ASSERT(length > 0);
+    ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
+           (1 << String::kArrayIndexValueBits));
+    result |= String::kIsArrayIndexMask;
+    result |= length << String::kArrayIndexHashLengthShift;
+  }
   return result;
 }
 
 
 uint32_t StringHasher::GetHashField() {
   ASSERT(is_valid());
-  if (length_ <= String::kMaxShortStringSize) {
-    uint32_t payload;
+  if (length_ <= String::kMaxHashCalcLength) {
     if (is_array_index()) {
-      payload = v8::internal::HashField(array_index(), true);
+      return v8::internal::HashField(array_index(), true, length_);
     } else {
-      payload = v8::internal::HashField(GetHash(), false);
+      return v8::internal::HashField(GetHash(), false);
     }
-    return (payload & ((1 << String::kShortLengthShift) - 1)) |
-           (length_ << String::kShortLengthShift);
-  } else if (length_ <= String::kMaxMediumStringSize) {
     uint32_t payload = v8::internal::HashField(GetHash(), false);
-    return (payload & ((1 << String::kMediumLengthShift) - 1)) |
-           (length_ << String::kMediumLengthShift);
+    return payload;
   } else {
     return v8::internal::HashField(length_, false);
   }
 }
 
 
-uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
-                                           int length) {
+uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
+                                  int length) {
   StringHasher hasher(length);
 
   // Very long strings have a trivial hash that doesn't inspect the
@@ -4704,43 +4629,10 @@
 }
 
 
-Object* String::Slice(int start, int end) {
+Object* String::SubString(int start, int end) {
   if (start == 0 && end == length()) return this;
-  if (StringShape(this).representation_tag() == kSlicedStringTag) {
-    // Translate slices of a SlicedString into slices of the
-    // underlying string buffer.
-    SlicedString* str = SlicedString::cast(this);
-    String* buf = str->buffer();
-    return Heap::AllocateSlicedString(buf,
-                                      str->start() + start,
-                                      str->start() + end);
-  }
-  Object* result = Heap::AllocateSlicedString(this, start, end);
-  if (result->IsFailure()) {
-    return result;
-  }
-  // Due to the way we retry after GC on allocation failure we are not allowed
-  // to fail on allocation after this point.  This is the one-allocation rule.
-
-  // Try to flatten a cons string that is under the sliced string.
-  // This is to avoid memory leaks and possible stack overflows caused by
-  // building 'towers' of sliced strings on cons strings.
-  // This may fail due to an allocation failure (when a GC is needed), but it
-  // will succeed often enough to avoid the problem.  We only have to do this
-  // if Heap::AllocateSlicedString actually returned a SlicedString.  It will
-  // return flat strings for small slices for efficiency reasons.
-  String* answer = String::cast(result);
-  if (StringShape(answer).IsSliced() &&
-      StringShape(this).representation_tag() == kConsStringTag) {
-    TryFlatten();
-    // If the flatten succeeded we might as well make the sliced string point
-    // to the flat string rather than the cons string.
-    String* second = ConsString::cast(this)->second();
-    if (second->length() == 0) {
-      SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first());
-    }
-  }
-  return answer;
+  Object* result = Heap::AllocateSubString(this, start, end);
+  return result;
 }
 
 
@@ -4920,13 +4812,9 @@
 
 
 void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
-    bool only_this_property_assignments,
     bool only_simple_this_property_assignments,
     FixedArray* assignments) {
   set_compiler_hints(BooleanBit::set(compiler_hints(),
-                                     kHasOnlyThisPropertyAssignments,
-                                     only_this_property_assignments));
-  set_compiler_hints(BooleanBit::set(compiler_hints(),
                                      kHasOnlySimpleThisPropertyAssignments,
                                      only_simple_this_property_assignments));
   set_this_property_assignments(assignments);
@@ -4936,9 +4824,6 @@
 
 void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
   set_compiler_hints(BooleanBit::set(compiler_hints(),
-                                     kHasOnlyThisPropertyAssignments,
-                                     false));
-  set_compiler_hints(BooleanBit::set(compiler_hints(),
                                      kHasOnlySimpleThisPropertyAssignments,
                                      false));
   set_this_property_assignments(Heap::undefined_value());
@@ -4993,7 +4878,7 @@
     return;
   }
 
-  // Get the slice of the source for this function.
+  // Get the source for the script which this function came from.
   // Don't use String::cast because we don't want more assertion errors while
   // we are already creating a stack dump.
   String* script_source =
@@ -5082,7 +4967,7 @@
 }
 
 
-void Code::Relocate(int delta) {
+void Code::Relocate(intptr_t delta) {
   for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
     it.rinfo()->apply(delta);
   }
@@ -5148,8 +5033,9 @@
     // Only look at positions after the current pc.
     if (it.rinfo()->pc() < pc) {
       // Get position and distance.
-      int dist = pc - it.rinfo()->pc();
-      int pos = it.rinfo()->data();
+
+      int dist = static_cast<int>(pc - it.rinfo()->pc());
+      int pos = static_cast<int>(it.rinfo()->data());
       // If this position is closer than the current candidate or if it has the
       // same distance as the current candidate and the position is higher then
       // this position is the new candidate.
@@ -5176,7 +5062,7 @@
   RelocIterator it(this, RelocInfo::kPositionMask);
   while (!it.done()) {
     if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
-      int p = it.rinfo()->data();
+      int p = static_cast<int>(it.rinfo()->data());
       if (statement_position < p && p <= position) {
         statement_position = p;
       }
@@ -5353,9 +5239,7 @@
   Handle<JSArray> self(this);
   Handle<FixedArray> old_backing(FixedArray::cast(elements()));
   int old_size = old_backing->length();
-  // Doubling in size would be overkill, but leave some slack to avoid
-  // constantly growing.
-  int new_size = required_size + (required_size >> 3);
+  int new_size = required_size > old_size ? required_size : old_size;
   Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size);
   // Can't use this any more now because we may have had a GC!
   for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
@@ -6284,6 +6168,18 @@
 }
 
 
+Object* JSObject::GetLocalPropertyPostInterceptor(
+    JSObject* receiver,
+    String* name,
+    PropertyAttributes* attributes) {
+  // Check local property in holder, ignore interceptor.
+  LookupResult result;
+  LocalLookupRealNamedProperty(name, &result);
+  if (!result.IsValid()) return Heap::undefined_value();
+  return GetProperty(receiver, &result, name, attributes);
+}
+
+
 Object* JSObject::GetPropertyWithInterceptor(
     JSObject* receiver,
     String* name,
@@ -6573,6 +6469,15 @@
 
 
 int JSObject::NumberOfEnumElements() {
+  // Fast case for objects with no elements.
+  if (!IsJSValue() && HasFastElements()) {
+    uint32_t length = IsJSArray() ?
+        static_cast<uint32_t>(
+            Smi::cast(JSArray::cast(this)->length())->value()) :
+        static_cast<uint32_t>(FixedArray::cast(elements())->length());
+    if (length == 0) return 0;
+  }
+  // Compute the number of enumerable elements.
   return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
 }
 
@@ -6832,19 +6737,19 @@
 class Utf8SymbolKey : public HashTableKey {
  public:
   explicit Utf8SymbolKey(Vector<const char> string)
-      : string_(string), length_field_(0) { }
+      : string_(string), hash_field_(0) { }
 
   bool IsMatch(Object* string) {
     return String::cast(string)->IsEqualTo(string_);
   }
 
   uint32_t Hash() {
-    if (length_field_ != 0) return length_field_ >> String::kHashShift;
+    if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
     unibrow::Utf8InputBuffer<> buffer(string_.start(),
                                       static_cast<unsigned>(string_.length()));
     chars_ = buffer.Length();
-    length_field_ = String::ComputeLengthAndHashField(&buffer, chars_);
-    uint32_t result = length_field_ >> String::kHashShift;
+    hash_field_ = String::ComputeHashField(&buffer, chars_);
+    uint32_t result = hash_field_ >> String::kHashShift;
     ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
     return result;
   }
@@ -6854,12 +6759,12 @@
   }
 
   Object* AsObject() {
-    if (length_field_ == 0) Hash();
-    return Heap::AllocateSymbol(string_, chars_, length_field_);
+    if (hash_field_ == 0) Hash();
+    return Heap::AllocateSymbol(string_, chars_, hash_field_);
   }
 
   Vector<const char> string_;
-  uint32_t length_field_;
+  uint32_t hash_field_;
   int chars_;  // Caches the number of characters when computing the hash code.
 };
 
@@ -6900,7 +6805,7 @@
     StringInputBuffer buffer(string_);
     return Heap::AllocateInternalSymbol(&buffer,
                                         string_->length(),
-                                        string_->length_field());
+                                        string_->hash_field());
   }
 
   static uint32_t StringHash(Object* obj) {
@@ -7429,6 +7334,67 @@
 }
 
 
+// This class is used for looking up two character strings in the symbol table.
+// If we don't have a hit we don't want to waste much time so we unroll the
+// string hash calculation loop here for speed.  Doesn't work if the two
+// characters form a decimal integer, since such strings have a different hash
+// algorithm.
+class TwoCharHashTableKey : public HashTableKey {
+ public:
+  TwoCharHashTableKey(uint32_t c1, uint32_t c2)
+    : c1_(c1), c2_(c2) {
+    // Char 1.
+    uint32_t hash = c1 + (c1 << 10);
+    hash ^= hash >> 6;
+    // Char 2.
+    hash += c2;
+    hash += hash << 10;
+    hash ^= hash >> 6;
+    // GetHash.
+    hash += hash << 3;
+    hash ^= hash >> 11;
+    hash += hash << 15;
+    if (hash == 0) hash = 27;
+#ifdef DEBUG
+    StringHasher hasher(2);
+    hasher.AddCharacter(c1);
+    hasher.AddCharacter(c2);
+    // If this assert fails then we failed to reproduce the two-character
+    // version of the string hashing algorithm above.  One reason could be
+    // that we were passed two digits as characters, since the hash
+    // algorithm is different in that case.
+    ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
+#endif
+    hash_ = hash;
+  }
+
+  bool IsMatch(Object* o) {
+    if (!o->IsString()) return false;
+    String* other = String::cast(o);
+    if (other->length() != 2) return false;
+    if (other->Get(0) != c1_) return false;
+    return other->Get(1) == c2_;
+  }
+
+  uint32_t Hash() { return hash_; }
+  uint32_t HashForObject(Object* key) {
+    if (!key->IsString()) return 0;
+    return String::cast(key)->Hash();
+  }
+
+  Object* AsObject() {
+    // The TwoCharHashTableKey is only used for looking in the symbol
+    // table, not for adding to it.
+    UNREACHABLE();
+    return NULL;
+  }
+ private:
+  uint32_t c1_;
+  uint32_t c2_;
+  uint32_t hash_;
+};
+
+
 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
   SymbolKey key(string);
   int entry = FindEntry(&key);
@@ -7443,6 +7409,22 @@
 }
 
 
+bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
+                                               uint32_t c2,
+                                               String** symbol) {
+  TwoCharHashTableKey key(c1, c2);
+  int entry = FindEntry(&key);
+  if (entry == kNotFound) {
+    return false;
+  } else {
+    String* result = String::cast(KeyAt(entry));
+    ASSERT(StringShape(result).IsSymbol());
+    *symbol = result;
+    return true;
+  }
+}
+
+
 Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
   Utf8SymbolKey key(str);
   return LookupKey(&key, s);