Added support for API accessors that prohibit overwriting by accessors defined in JavaScript code by using __defineGetter__ and __defineSetter__.

Improved handling of conditionals in test status files.

Introduced access control in propertyIsEnumerable.

Improved performance of some string operations by caching information about the type of the string between operations.

Fixed bug in fast-case code for switch statements that only have integer labels.


git-svn-id: http://v8.googlecode.com/svn/trunk@687 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index c73d5ae..1b8bdc4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2008-11-04: Version 0.4.3
+
+        Added support for API accessors that prohibit overwriting by
+        accessors defined in JavaScript code by using __defineGetter__ and
+        __defineSetter__.
+
+        Improved handling of conditionals in test status files.
+
+        Introduced access control in propertyIsEnumerable.
+
+        Improved performance of some string operations by caching
+        information about the type of the string between operations.
+
+        Fixed bug in fast-case code for switch statements that only have
+        integer labels.
+        
+
 2008-10-30: Version 0.4.2
 
         Improved performance of Array.prototype.concat by moving the
diff --git a/SConstruct b/SConstruct
index 6e5bc7a..c1a6ec2 100644
--- a/SConstruct
+++ b/SConstruct
@@ -238,25 +238,6 @@
   sys.exit(1)
 
 
-def GuessOS():
-  id = platform.system()
-  if id == 'Linux':
-    return 'linux'
-  elif id == 'Darwin':
-    return 'macos'
-  elif id == 'Windows':
-    return 'win32'
-  else:
-    return None
-
-
-def GuessWordsize():
-  if '64' in platform.machine():
-    return '64'
-  else:
-    return '32'
-
-
 def GuessToolchain(os):
   tools = Environment()['TOOLS']
   if 'gcc' in tools:
@@ -267,10 +248,10 @@
     return None
 
 
-OS_GUESS = GuessOS()
+OS_GUESS = utils.GuessOS()
 TOOLCHAIN_GUESS = GuessToolchain(OS_GUESS)
 ARCH_GUESS = utils.GuessArchitecture()
-WORDSIZE_GUESS = GuessWordsize()
+WORDSIZE_GUESS = utils.GuessWordsize()
 
 
 SIMPLE_OPTIONS = {
diff --git a/include/v8.h b/include/v8.h
index 70b1f52..ec51ce6 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1301,11 +1301,18 @@
  * Some accessors should be accessible across contexts.  These
  * accessors have an explicit access control parameter which specifies
  * the kind of cross-context access that should be allowed.
+ *
+ * Additionally, for security, accessors can prohibit overwriting by
+ * accessors defined in JavaScript.  For objects that have such
+ * accessors either locally or in their prototype chain it is not
+ * possible to overwrite the accessor by using __defineGetter__ or
+ * __defineSetter__ from JavaScript code.
  */
 enum AccessControl {
-  DEFAULT         = 0,
-  ALL_CAN_READ    = 1,
-  ALL_CAN_WRITE   = 2
+  DEFAULT               = 0,
+  ALL_CAN_READ          = 1,
+  ALL_CAN_WRITE         = 1 << 1,
+  PROHIBITS_OVERWRITING = 1 << 2
 };
 
 
diff --git a/src/api.cc b/src/api.cc
index 5a81fe5..d127eca 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -701,6 +701,7 @@
   obj->set_name(*Utils::OpenHandle(*name));
   if (settings & ALL_CAN_READ) obj->set_all_can_read(true);
   if (settings & ALL_CAN_WRITE) obj->set_all_can_write(true);
+  if (settings & PROHIBITS_OVERWRITING) obj->set_prohibits_overwriting(true);
   obj->set_property_attributes(static_cast<PropertyAttributes>(attributes));
 
   i::Handle<i::Object> list(Utils::OpenHandle(this)->property_accessors());
@@ -1915,7 +1916,7 @@
 
   i::Handle<i::Map> new_map =
     i::Factory::CopyMapDropTransitions(i::Handle<i::Map>(obj->map()));
-  new_map->set_is_access_check_needed();
+  new_map->set_is_access_check_needed(true);
   obj->set_map(*new_map);
 }
 
@@ -2035,7 +2036,7 @@
   i::Handle<i::String> str = Utils::OpenHandle(this);
   // Flatten the string for efficiency.  This applies whether we are
   // using StringInputBuffer or Get(i) to access the characters.
-  str->TryFlatten();
+  str->TryFlatten(i::StringShape(*str));
   int end = length;
   if ( (length == -1) || (length > str->length() - start) )
     end = str->length() - start;
@@ -2060,7 +2061,7 @@
   i::Handle<i::String> str = Utils::OpenHandle(this);
   // Flatten the string for efficiency.  This applies whether we are
   // using StringInputBuffer or Get(i) to access the characters.
-  str->TryFlatten();
+  str->TryFlatten(i::StringShape(*str));
   int end = length;
   if ( (length == -1) || (length > str->length() - start) )
     end = str->length() - start;
@@ -2078,14 +2079,16 @@
 bool v8::String::IsExternal() {
   EnsureInitialized("v8::String::IsExternal()");
   i::Handle<i::String> str = Utils::OpenHandle(this);
-  return str->IsExternalTwoByteString();
+  i::StringShape shape(*str);
+  return shape.IsExternalTwoByte();
 }
 
 
 bool v8::String::IsExternalAscii() {
   EnsureInitialized("v8::String::IsExternalAscii()");
   i::Handle<i::String> str = Utils::OpenHandle(this);
-  return str->IsExternalAsciiString();
+  i::StringShape shape(*str);
+  return shape.IsExternalAscii();
 }
 
 
@@ -2199,7 +2202,7 @@
 
 
 const char* v8::V8::GetVersion() {
-  return "0.4.2.1";
+  return "0.4.3";
 }
 
 
diff --git a/src/apinatives.js b/src/apinatives.js
index 8741f59..8ae80e7 100644
--- a/src/apinatives.js
+++ b/src/apinatives.js
@@ -82,12 +82,18 @@
 function ConfigureTemplateInstance(obj, data) {
   var properties = %GetTemplateField(data, kApiPropertyListOffset);
   if (properties) {
-    for (var i = 0; i < properties[0]; i += 3) {
-      var name = properties[i + 1];
-      var prop_data = properties[i + 2];
-      var attributes = properties[i + 3];
-      var value = Instantiate(prop_data, name);
-      %SetProperty(obj, name, value, attributes);
+    // Disable access checks while instantiating the object.
+    var requires_access_checks = %DisableAccessChecks(obj);
+    try {
+      for (var i = 0; i < properties[0]; i += 3) {
+        var name = properties[i + 1];
+        var prop_data = properties[i + 2];
+        var attributes = properties[i + 3];
+        var value = Instantiate(prop_data, name);
+        %SetProperty(obj, name, value, attributes);
+      }
+    } finally {
+      if (requires_access_checks) %EnableAccessChecks(obj);
     }
   }
 }
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 0562c23..d08baa1 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -597,7 +597,7 @@
 
       Handle<String> global_name = Factory::LookupAsciiSymbol("global");
       global_proxy_function->shared()->set_instance_class_name(*global_name);
-      global_proxy_function->initial_map()->set_is_access_check_needed();
+      global_proxy_function->initial_map()->set_is_access_check_needed(true);
 
       // Set global_proxy.__proto__ to js_global after ConfigureGlobalObjects
 
@@ -840,7 +840,7 @@
   // function and insert it into the cache.
   if (!cache->Lookup(name, &boilerplate)) {
 #ifdef DEBUG
-    ASSERT(source->IsAsciiRepresentation());
+    ASSERT(StringShape(*source).IsAsciiRepresentation());
 #endif
     Handle<String> script_name = Factory::NewStringFromUtf8(name);
     boilerplate =
diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc
index 35522b1..4c2f465 100644
--- a/src/codegen-arm.cc
+++ b/src/codegen-arm.cc
@@ -1247,10 +1247,29 @@
   ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
 
   __ pop(r0);
+
+  // Test for a Smi value in a HeapNumber.
+  Label is_smi;
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &is_smi);
+  __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag));
+  __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag));
+  __ cmp(r1, Operand(HEAP_NUMBER_TYPE));
+  __ b(ne, fail_label);
+  __ push(r0);
+  __ CallRuntime(Runtime::kNumberToSmi, 1);
+  __ bind(&is_smi);
+
   if (min_index != 0) {
-    // small positive numbers can be immediate operands.
+    // Small positive numbers can be immediate operands.
     if (min_index < 0) {
-      __ add(r0, r0, Operand(Smi::FromInt(-min_index)));
+      // If min_index is Smi::kMinValue, -min_index is not a Smi.
+      if (Smi::IsValid(-min_index)) {
+        __ add(r0, r0, Operand(Smi::FromInt(-min_index)));
+      } else {
+        __ add(r0, r0, Operand(Smi::FromInt(-min_index - 1)));
+        __ add(r0, r0, Operand(Smi::FromInt(1)));
+      }
     } else {
       __ sub(r0, r0, Operand(Smi::FromInt(min_index)));
     }
@@ -1264,7 +1283,7 @@
   // the pc-register at the above add.
   __ stop("Unreachable: Switch table alignment");
 
-  // table containing branch operations.
+  // Table containing branch operations.
   for (int i = 0; i < range; i++) {
     __ b(case_targets[i]);
   }
diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc
index eaac989..cac0f44 100644
--- a/src/codegen-ia32.cc
+++ b/src/codegen-ia32.cc
@@ -1623,9 +1623,24 @@
   // placeholders, and fill in the addresses after the labels have been
   // bound.
 
-  frame_->Pop(eax);  // supposed smi
+  frame_->Pop(eax);  // supposed Smi
   // check range of value, if outside [0..length-1] jump to default/end label.
   ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+
+  // Test whether input is a HeapNumber that is really a Smi
+  Label is_smi;
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(equal, &is_smi);
+  // It's a heap object, not a Smi or a Failure
+  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+  __ cmp(ebx, HEAP_NUMBER_TYPE);
+  __ j(not_equal, fail_label);
+  // eax points to a heap number.
+  __ push(eax);
+  __ CallRuntime(Runtime::kNumberToSmi, 1);
+  __ bind(&is_smi);
+
   if (min_index != 0) {
     __ sub(Operand(eax), Immediate(min_index << kSmiTagSize));
   }
diff --git a/src/codegen.cc b/src/codegen.cc
index 47f7842..70acf65 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -330,12 +330,14 @@
     {&v8::internal::CodeGenerator::GenerateObjectEquals,
      "_ObjectEquals"}
   };
-  if (node->name()->length() > 0 && node->name()->Get(0) == '_') {
+  Handle<String> name = node->name();
+  StringShape shape(*name);
+  if (name->length(shape) > 0 && name->Get(shape, 0) == '_') {
     for (unsigned i = 0;
          i < sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
          i++) {
       const InlineRuntimeLUT* entry = kInlineRuntimeLUT + i;
-      if (node->name()->IsEqualTo(CStrVector(entry->name))) {
+      if (name->IsEqualTo(CStrVector(entry->name))) {
         ((*this).*(entry->method))(args);
         return true;
       }
diff --git a/src/compiler.cc b/src/compiler.cc
index 771620e..53c1a66 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -157,8 +157,9 @@
                                      int line_offset, int column_offset,
                                      v8::Extension* extension,
                                      ScriptDataImpl* input_pre_data) {
-  Counters::total_load_size.Increment(source->length());
-  Counters::total_compile_size.Increment(source->length());
+  int source_length = source->length();
+  Counters::total_load_size.Increment(source_length);
+  Counters::total_compile_size.Increment(source_length);
 
   // The VM is in the COMPILER state until exiting this function.
   VMState state(COMPILER);
@@ -175,7 +176,7 @@
   if (result.is_null()) {
     // No cache entry found. Do pre-parsing and compile the script.
     ScriptDataImpl* pre_data = input_pre_data;
-    if (pre_data == NULL && source->length() >= FLAG_min_preparse_length) {
+    if (pre_data == NULL && source_length >= FLAG_min_preparse_length) {
       Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
       buf->Reset(source.location());
       pre_data = PreParse(buf.value(), extension);
@@ -208,8 +209,10 @@
 Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
                                          int line_offset,
                                          bool is_global) {
-  Counters::total_eval_size.Increment(source->length());
-  Counters::total_compile_size.Increment(source->length());
+  StringShape source_shape(*source);
+  int source_length = source->length(source_shape);
+  Counters::total_eval_size.Increment(source_length);
+  Counters::total_compile_size.Increment(source_length);
 
   // The VM is in the COMPILER state until exiting this function.
   VMState state(COMPILER);
diff --git a/src/conversions.cc b/src/conversions.cc
index a1adb22..20a394a 100644
--- a/src/conversions.cc
+++ b/src/conversions.cc
@@ -55,7 +55,8 @@
 
 
 static inline int GetChar(String* str, int index) {
-  return str->Get(index);
+  StringShape shape(str);
+  return str->Get(shape, index);
 }
 
 
@@ -75,15 +76,18 @@
 
 
 static inline const char* GetCString(String* str, int index) {
-  char* result = NewArray<char>(str->length() + 1);
-  for (int i = index; i < str->length(); i++) {
-    if (str->Get(i) <= 127) {
-      result[i - index] = static_cast<char>(str->Get(i));
+  StringShape shape(str);
+  int length = str->length(shape);
+  char* result = NewArray<char>(length + 1);
+  for (int i = index; i < length; i++) {
+    uc16 c = str->Get(shape, i);
+    if (c <= 127) {
+      result[i - index] = static_cast<char>(c);
     } else {
       result[i - index] = 127;  // Force number parsing to fail.
     }
   }
-  result[str->length() - index] = '\0';
+  result[length - index] = '\0';
   return result;
 }
 
@@ -104,7 +108,8 @@
 
 
 static inline bool IsSpace(String* str, int index) {
-  return Scanner::kIsWhiteSpace.get(str->Get(index));
+  StringShape shape(str);
+  return Scanner::kIsWhiteSpace.get(str->Get(shape, index));
 }
 
 
@@ -116,12 +121,16 @@
 
 
 static inline bool SubStringEquals(String* str, int index, const char* other) {
+  StringShape shape(str);
   HandleScope scope;
-  int len = strlen(other);
-  int end = index + len < str->length() ? index + len : str->length();
+  int str_length = str->length(shape);
+  int other_length = strlen(other);
+  int end = index + other_length < str_length ?
+            index + other_length :
+            str_length;
   Handle<String> slice =
-      Factory::NewStringSlice(Handle<String>(str), index, end);
-  return slice->IsEqualTo(Vector<const char>(other, len));
+      Factory::NewStringSlice(Handle<String>(str), shape, index, end);
+  return slice->IsEqualTo(Vector<const char>(other, other_length));
 }
 
 
diff --git a/src/factory.cc b/src/factory.cc
index 4b0faef..3b3c2c3 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -90,15 +90,24 @@
 
 
 Handle<String> Factory::NewConsString(Handle<String> first,
-                                      Handle<String> second) {
-  if (first->length() == 0) return second;
-  if (second->length() == 0) return first;
-  CALL_HEAP_FUNCTION(Heap::AllocateConsString(*first, *second), String);
+                                      StringShape first_shape,
+                                      Handle<String> second,
+                                      StringShape second_shape) {
+  if (first->length(first_shape) == 0) return second;
+  if (second->length(second_shape) == 0) return first;
+  CALL_HEAP_FUNCTION(Heap::AllocateConsString(*first,
+                                              first_shape,
+                                              *second,
+                                              second_shape),
+                     String);
 }
 
 
-Handle<String> Factory::NewStringSlice(Handle<String> str, int begin, int end) {
-  CALL_HEAP_FUNCTION(str->Slice(begin, end), String);
+Handle<String> Factory::NewStringSlice(Handle<String> str,
+                                       StringShape shape,
+                                       int begin,
+                                       int end) {
+  CALL_HEAP_FUNCTION(str->Slice(shape, begin, end), String);
 }
 
 
@@ -725,7 +734,7 @@
 
   // Mark as needs_access_check if needed.
   if (obj->needs_access_check()) {
-    map->set_is_access_check_needed();
+    map->set_is_access_check_needed(true);
   }
 
   // Set interceptor information in the map.
diff --git a/src/factory.h b/src/factory.h
index 0cd80f0..67fed57 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -98,11 +98,16 @@
 
   // Create a new cons string object which consists of a pair of strings.
   static Handle<String> NewConsString(Handle<String> first,
-                                      Handle<String> second);
+                                      StringShape first_shape,
+                                      Handle<String> second,
+                                      StringShape second_shape);
 
   // Create a new sliced string object which represents a substring of a
   // backing string.
-  static Handle<String> NewStringSlice(Handle<String> str, int begin, int end);
+  static Handle<String> NewStringSlice(Handle<String> str,
+                                       StringShape shape,
+                                       int begin,
+                                       int end);
 
   // Creates a new external String object.  There are two String encodings
   // in the system: ASCII and two byte.  Unlike other String types, it does
diff --git a/src/handles.cc b/src/handles.cc
index 5b0e1ce..7043319 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -117,9 +117,10 @@
 
 
 void FlattenString(Handle<String> string) {
-  if (string->IsFlat()) return;
-  CALL_HEAP_FUNCTION_VOID(string->Flatten());
-  ASSERT(string->IsFlat());
+  StringShape shape(*string);
+  if (string->IsFlat(shape)) return;
+  CALL_HEAP_FUNCTION_VOID(string->Flatten(shape));
+  ASSERT(string->IsFlat(StringShape(*string)));
 }
 
 
@@ -216,7 +217,7 @@
 
 
 Handle<String> SubString(Handle<String> str, int start, int end) {
-  CALL_HEAP_FUNCTION(str->Slice(start, end), String);
+  CALL_HEAP_FUNCTION(str->Slice(StringShape(*str), start, end), String);
 }
 
 
diff --git a/src/heap.cc b/src/heap.cc
index bb30deb..805ca09 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -777,13 +777,15 @@
   return ScavengeObjectSlow(p, object);
 }
 
+
 static inline bool IsShortcutCandidate(HeapObject* object, Map* map) {
-  // A ConString object with Heap::empty_string() as the right side
+  // A ConsString object with Heap::empty_string() as the right side
   // is a candidate for being shortcut by the scavenger.
   ASSERT(object->map() == map);
-  return (map->instance_type() < FIRST_NONSTRING_TYPE) &&
-      (String::cast(object)->map_representation_tag(map) == kConsStringTag) &&
-      (ConsString::cast(object)->second() == Heap::empty_string());
+  if (map->instance_type() >= FIRST_NONSTRING_TYPE) return false;
+  StringShape shape(map);
+  return (shape.representation_tag() == kConsStringTag) &&
+         (ConsString::cast(object)->unchecked_second() == Heap::empty_string());
 }
 
 
@@ -794,7 +796,7 @@
 
   // Optimization: Bypass flattened ConsString objects.
   if (IsShortcutCandidate(object, first_word.ToMap())) {
-    object = HeapObject::cast(ConsString::cast(object)->first());
+    object = HeapObject::cast(ConsString::cast(object)->unchecked_first());
     *p = object;
     // After patching *p we have to repeat the checks that object is in the
     // active semispace of the young generation and not already copied.
@@ -1344,32 +1346,43 @@
 }
 
 
-Object* Heap::AllocateConsString(String* first, String* second) {
-  int first_length = first->length();
-  int second_length = second->length();
+Object* Heap::AllocateConsString(String* first,
+                                 StringShape first_shape,
+                                 String* second,
+                                 StringShape second_shape) {
+  int first_length = first->length(first_shape);
+  int second_length = second->length(second_shape);
   int length = first_length + second_length;
-  bool is_ascii = first->is_ascii_representation()
-      && second->is_ascii_representation();
+  bool is_ascii = first_shape.IsAsciiRepresentation()
+      && second_shape.IsAsciiRepresentation();
 
   // If the resulting string is small make a flat string.
   if (length < String::kMinNonFlatLength) {
-    ASSERT(first->IsFlat());
-    ASSERT(second->IsFlat());
+    ASSERT(first->IsFlat(first_shape));
+    ASSERT(second->IsFlat(second_shape));
     if (is_ascii) {
       Object* result = AllocateRawAsciiString(length);
       if (result->IsFailure()) return result;
       // Copy the characters into the new object.
       char* dest = SeqAsciiString::cast(result)->GetChars();
-      String::WriteToFlat(first, dest, 0, first_length);
-      String::WriteToFlat(second, dest + first_length, 0, second_length);
+      String::WriteToFlat(first, first_shape, dest, 0, first_length);
+      String::WriteToFlat(second,
+                          second_shape,
+                          dest + first_length,
+                          0,
+                          second_length);
       return result;
     } else {
       Object* result = AllocateRawTwoByteString(length);
       if (result->IsFailure()) return result;
       // Copy the characters into the new object.
       uc16* dest = SeqTwoByteString::cast(result)->GetChars();
-      String::WriteToFlat(first, dest, 0, first_length);
-      String::WriteToFlat(second, dest + first_length, 0, second_length);
+      String::WriteToFlat(first, first_shape, dest, 0, first_length);
+      String::WriteToFlat(second,
+                          second_shape,
+                          dest + first_length,
+                          0,
+                          second_length);
       return result;
     }
   }
@@ -1397,24 +1410,30 @@
 }
 
 
-Object* Heap::AllocateSlicedString(String* buffer, int start, int end) {
+Object* Heap::AllocateSlicedString(String* buffer,
+                                   StringShape buffer_shape,
+                                   int start,
+                                   int end) {
   int length = end - start;
 
   // If the resulting string is small make a sub string.
   if (end - start <= String::kMinNonFlatLength) {
-    return Heap::AllocateSubString(buffer, start, end);
+    return Heap::AllocateSubString(buffer, buffer_shape, start, end);
   }
 
   Map* map;
   if (length <= String::kMaxShortStringSize) {
-    map = buffer->is_ascii_representation() ? short_sliced_ascii_string_map()
-      : short_sliced_string_map();
+    map = buffer_shape.IsAsciiRepresentation() ?
+      short_sliced_ascii_string_map() :
+      short_sliced_string_map();
   } else if (length <= String::kMaxMediumStringSize) {
-    map = buffer->is_ascii_representation() ? medium_sliced_ascii_string_map()
-      : medium_sliced_string_map();
+    map = buffer_shape.IsAsciiRepresentation() ?
+      medium_sliced_ascii_string_map() :
+      medium_sliced_string_map();
   } else {
-    map = buffer->is_ascii_representation() ? long_sliced_ascii_string_map()
-      : long_sliced_string_map();
+    map = buffer_shape.IsAsciiRepresentation() ?
+      long_sliced_ascii_string_map() :
+      long_sliced_string_map();
   }
 
   Object* result = Allocate(map, NEW_SPACE);
@@ -1429,34 +1448,42 @@
 }
 
 
-Object* Heap::AllocateSubString(String* buffer, int start, int end) {
+Object* Heap::AllocateSubString(String* buffer,
+                                StringShape buffer_shape,
+                                int start,
+                                int end) {
   int length = end - start;
 
   if (length == 1) {
-    return Heap::LookupSingleCharacterStringFromCode(buffer->Get(start));
+    return Heap::LookupSingleCharacterStringFromCode(
+        buffer->Get(buffer_shape, start));
   }
 
   // Make an attempt to flatten the buffer to reduce access time.
-  buffer->TryFlatten();
+  if (!buffer->IsFlat(buffer_shape)) {
+    buffer->TryFlatten(buffer_shape);
+    buffer_shape = StringShape(buffer);
+  }
 
-  Object* result = buffer->is_ascii_representation()
+  Object* result = buffer_shape.IsAsciiRepresentation()
       ? AllocateRawAsciiString(length)
       : AllocateRawTwoByteString(length);
   if (result->IsFailure()) return result;
 
   // Copy the characters into the new object.
   String* string_result = String::cast(result);
+  StringShape result_shape(string_result);
   StringHasher hasher(length);
   int i = 0;
   for (; i < length && hasher.is_array_index(); i++) {
-    uc32 c = buffer->Get(start + i);
+    uc32 c = buffer->Get(buffer_shape, start + i);
     hasher.AddCharacter(c);
-    string_result->Set(i, c);
+    string_result->Set(result_shape, i, c);
   }
   for (; i < length; i++) {
-    uc32 c = buffer->Get(start + i);
+    uc32 c = buffer->Get(buffer_shape, start + i);
     hasher.AddCharacterNoIndex(c);
-    string_result->Set(i, c);
+    string_result->Set(result_shape, i, c);
   }
   string_result->set_length_field(hasher.GetHashField());
   return result;
@@ -1525,8 +1552,9 @@
 
   Object* result = Heap::AllocateRawTwoByteString(1);
   if (result->IsFailure()) return result;
-  String::cast(result)->Set(0, code);
-  return result;
+  String* answer = String::cast(result);
+  answer->Set(StringShape(answer), 0, code);
+  return answer;
 }
 
 
@@ -1905,9 +1933,10 @@
   // Convert and copy the characters into the new object.
   String* string_result = String::cast(result);
   decoder->Reset(string.start(), string.length());
+  StringShape result_shape(string_result);
   for (int i = 0; i < chars; i++) {
     uc32 r = decoder->GetNext();
-    string_result->Set(i, r);
+    string_result->Set(result_shape, i, r);
   }
   return result;
 }
@@ -1930,8 +1959,9 @@
   // Copy the characters into the new object, which may be either ASCII or
   // UTF-16.
   String* string_result = String::cast(result);
+  StringShape result_shape(string_result);
   for (int i = 0; i < string.length(); i++) {
-    string_result->Set(i, string[i]);
+    string_result->Set(result_shape, i, string[i]);
   }
   return result;
 }
@@ -2043,15 +2073,17 @@
 
   reinterpret_cast<HeapObject*>(result)->set_map(map);
   // The hash value contains the length of the string.
-  String::cast(result)->set_length_field(length_field);
+  String* answer = String::cast(result);
+  StringShape answer_shape(answer);
+  answer->set_length_field(length_field);
 
-  ASSERT_EQ(size, String::cast(result)->Size());
+  ASSERT_EQ(size, answer->Size());
 
   // Fill in the characters.
   for (int i = 0; i < chars; i++) {
-    String::cast(result)->Set(i, buffer->GetNext());
+    answer->Set(answer_shape, i, buffer->GetNext());
   }
-  return result;
+  return answer;
 }
 
 
diff --git a/src/heap.h b/src/heap.h
index 958b4eb..dc50c73 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -494,7 +494,10 @@
   // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
   // failed.
   // Please note this does not perform a garbage collection.
-  static Object* AllocateConsString(String* first, String* second);
+  static Object* AllocateConsString(String* first,
+                                    StringShape first_shape,
+                                    String* second,
+                                    StringShape second_shape);
 
   // Allocates a new sliced string object which is a slice of an underlying
   // string buffer stretching from the index start (inclusive) to the index
@@ -502,7 +505,10 @@
   // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
   // failed.
   // Please note this does not perform a garbage collection.
-  static Object* AllocateSlicedString(String* buffer, int start, int end);
+  static Object* AllocateSlicedString(String* buffer,
+                                      StringShape buffer_shape,
+                                      int start,
+                                      int end);
 
   // Allocates a new sub string object which is a substring of an underlying
   // string buffer stretching from the index start (inclusive) to the index
@@ -510,7 +516,10 @@
   // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
   // failed.
   // Please note this does not perform a garbage collection.
-  static Object* AllocateSubString(String* buffer, int start, int end);
+  static Object* AllocateSubString(String* buffer,
+                                   StringShape buffer_shape,
+                                   int start,
+                                   int end);
 
   // Allocate a new external string object, which is backed by a string
   // resource that resides outside the V8 heap.
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index d8c49ea..2203b5c 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -129,34 +129,37 @@
 // Converts a source string to a 16 bit flat string or a SlicedString containing
 // a 16 bit flat string).
 Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) {
-  if (!pattern->IsFlat()) {
+  StringShape shape(*pattern);
+  if (!pattern->IsFlat(shape)) {
     FlattenString(pattern);
   }
-  Handle<String> flat_string(pattern->IsConsString() ?
+  Handle<String> flat_string(shape.IsCons() ?
     String::cast(ConsString::cast(*pattern)->first()) :
     *pattern);
-  ASSERT(!flat_string->IsConsString());
-  ASSERT(flat_string->IsSeqString() || flat_string->IsSlicedString() ||
-         flat_string->IsExternalString());
-  if (!flat_string->IsAsciiRepresentation()) {
+  ASSERT(flat_string->IsString());
+  StringShape flat_shape(*flat_string);
+  ASSERT(!flat_shape.IsCons());
+  ASSERT(flat_shape.IsSequential() ||
+         flat_shape.IsSliced() ||
+         flat_shape.IsExternal());
+  if (!flat_shape.IsAsciiRepresentation()) {
     return flat_string;
   }
 
+  int len = flat_string->length(flat_shape);
   Handle<String> two_byte_string =
-    Factory::NewRawTwoByteString(flat_string->length(), TENURED);
-  static StringInputBuffer convert_to_two_byte_buffer;
-  convert_to_two_byte_buffer.Reset(*flat_string);
-  for (int i = 0; convert_to_two_byte_buffer.has_more(); i++) {
-    two_byte_string->Set(i, convert_to_two_byte_buffer.GetNext());
-  }
+    Factory::NewRawTwoByteString(len, TENURED);
+  uc16* dest = SeqTwoByteString::cast(*two_byte_string)->GetChars();
+  String::WriteToFlat(*flat_string, flat_shape, dest, 0, len);
   return two_byte_string;
 }
 
 
 static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) {
   int flags = JSRegExp::NONE;
-  for (int i = 0; i < str->length(); i++) {
-    switch (str->Get(i)) {
+  StringShape shape(*str);
+  for (int i = 0; i < str->length(shape); i++) {
+    switch (str->Get(shape, i)) {
       case 'i':
         flags |= JSRegExp::IGNORE_CASE;
         break;
@@ -182,13 +185,14 @@
   Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags);
   bool in_cache = !cached.is_null();
   Handle<Object> result;
+  StringShape shape(*pattern);
   if (in_cache) {
     re->set_data(*cached);
     result = re;
   } else {
     bool is_atom = !flags.is_ignore_case();
-    for (int i = 0; is_atom && i < pattern->length(); i++) {
-      if (is_reg_exp_special_char.get(pattern->Get(i)))
+    for (int i = 0; is_atom && i < pattern->length(shape); i++) {
+      if (is_reg_exp_special_char.get(pattern->Get(shape, i)))
         is_atom = false;
     }
     if (is_atom) {
diff --git a/src/log.cc b/src/log.cc
index 25fa5e5..c7b1539 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -350,11 +350,12 @@
 
 #ifdef ENABLE_LOGGING_AND_PROFILING
 void Logger::LogString(Handle<String> str) {
-  int len = str->length();
+  StringShape shape(*str);
+  int len = str->length(shape);
   if (len > 256)
     len = 256;
   for (int i = 0; i < len; i++) {
-    uc32 c = str->Get(i);
+    uc32 c = str->Get(shape, i);
     if (c < 32 || (c > 126 && c <= 255)) {
       fprintf(logfile_, "\\x%02x", c);
     } else if (c > 255) {
@@ -430,7 +431,8 @@
   LogRegExpSource(regexp);
   fprintf(logfile_, ",");
   LogString(input_string);
-  fprintf(logfile_, ",%d..%d\n", start_index, input_string->length());
+  StringShape shape(*input_string);
+  fprintf(logfile_, ",%d..%d\n", start_index, input_string->length(shape));
 #endif
 }
 
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index d67544e..f2dd3b5 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -465,19 +465,20 @@
 
 
 void String::StringPrint() {
-  if (IsSymbol()) {
+  StringShape shape(this);
+  if (shape.IsSymbol()) {
     PrintF("#");
-  } else if (IsConsString()) {
+  } else if (shape.IsCons()) {
     PrintF("c\"");
   } else {
     PrintF("\"");
   }
 
   for (int i = 0; i < length(); i++) {
-    PrintF("%c", Get(i));
+    PrintF("%c", Get(shape, i));
   }
 
-  if (!IsSymbol()) PrintF("\"");
+  if (!shape.IsSymbol()) PrintF("\"");
 }
 
 
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 03448fd..97c6819 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -114,85 +114,168 @@
 }
 
 
-bool Object::IsSeqString() {
-  return IsString()
-    && (String::cast(this)->representation_tag() == kSeqStringTag);
-}
-
-
-bool Object::IsSeqAsciiString() {
-  return IsSeqString()
-      && String::cast(this)->IsAsciiRepresentation();
-}
-
-
-bool String::IsSeqAsciiString() {
-  return (this->representation_tag() == kSeqStringTag)
-    && is_ascii_representation();
-}
-
-
-bool Object::IsSeqTwoByteString() {
-  return IsSeqString()
-      && !String::cast(this)->IsAsciiRepresentation();
-}
-
-
-bool Object::IsAsciiStringRepresentation() {
-  return IsString() && (String::cast(this)->is_ascii_representation());
-}
-
-
-bool Object::IsTwoByteStringRepresentation() {
-  return IsString() && (!String::cast(this)->is_ascii_representation());
+bool Object::IsSymbol() {
+  if (!this->IsHeapObject()) return false;
+  uint32_t type = HeapObject::cast(this)->map()->instance_type();
+  return (type & (kIsNotStringMask | kIsSymbolMask)) ==
+         (kStringTag | kSymbolTag);
 }
 
 
 bool Object::IsConsString() {
-  return IsString()
-    && (String::cast(this)->representation_tag() == kConsStringTag);
+  if (!this->IsHeapObject()) return false;
+  uint32_t type = HeapObject::cast(this)->map()->instance_type();
+  return (type & (kIsNotStringMask | kStringRepresentationMask)) ==
+         (kStringTag | kConsStringTag);
 }
 
 
-bool Object::IsSlicedString() {
-  return IsString()
-    && (String::cast(this)->representation_tag() == kSlicedStringTag);
+#ifdef DEBUG
+// These are for cast checks.  If you need one of these in release
+// mode you should consider using a StringShape before moving it out
+// of the ifdef
+
+bool Object::IsSeqString() {
+  if (!IsString()) return false;
+  return StringShape(String::cast(this)).IsSequential();
+}
+
+
+bool Object::IsSeqAsciiString() {
+  if (!IsString()) return false;
+  StringShape shape(String::cast(this));
+  return shape.IsSequential() && shape.IsAsciiRepresentation();
+}
+
+
+bool Object::IsSeqTwoByteString() {
+  if (!IsString()) return false;
+  StringShape shape(String::cast(this));
+  return shape.IsSequential() && shape.IsTwoByteRepresentation();
 }
 
 
 bool Object::IsExternalString() {
-  return IsString()
-    && (String::cast(this)->representation_tag() == kExternalStringTag);
+  if (!IsString()) return false;
+  return StringShape(String::cast(this)).IsExternal();
 }
 
 
 bool Object::IsExternalAsciiString() {
-  return IsExternalString() && (String::cast(this)->is_ascii_representation());
+  if (!IsString()) return false;
+  StringShape shape(String::cast(this));
+  return shape.IsExternal() && shape.IsAsciiRepresentation();
 }
 
 
 bool Object::IsExternalTwoByteString() {
-  return IsExternalString() && (!String::cast(this)->is_ascii_representation());
+  if (!IsString()) return false;
+  StringShape shape(String::cast(this));
+  return shape.IsExternal() && shape.IsTwoByteRepresentation();
 }
 
 
-bool Object::IsShortString() {
-  return IsString() && (String::cast(this)->size_tag() == kShortStringTag);
+bool Object::IsSlicedString() {
+  if (!IsString()) return false;
+  return StringShape(String::cast(this)).IsSliced();
 }
 
 
-bool Object::IsMediumString() {
-  return IsString() && (String::cast(this)->size_tag() == kMediumStringTag);
+#endif  // DEBUG
+
+
+StringShape::StringShape(String* str)
+  : type_(str->map()->instance_type()) {
+  set_valid();
+  ASSERT((type_ & kIsNotStringMask) == kStringTag);
 }
 
 
-bool Object::IsLongString() {
-  return IsString() && (String::cast(this)->size_tag() == kLongStringTag);
+StringShape::StringShape(Map* map)
+  : type_(map->instance_type()) {
+  set_valid();
+  ASSERT((type_ & kIsNotStringMask) == kStringTag);
 }
 
 
-bool Object::IsSymbol() {
-  return IsString() && (String::cast(this)->is_symbol());
+StringShape::StringShape(InstanceType t)
+  : type_(static_cast<uint32_t>(t)) {
+  set_valid();
+  ASSERT((type_ & kIsNotStringMask) == kStringTag);
+}
+
+
+bool StringShape::IsSymbol() {
+  ASSERT(valid());
+  return (type_ & kIsSymbolMask) == kSymbolTag;
+}
+
+
+bool StringShape::IsAsciiRepresentation() {
+  return (type_ & kStringEncodingMask) == kAsciiStringTag;
+}
+
+
+bool StringShape::IsTwoByteRepresentation() {
+  return (type_ & kStringEncodingMask) == kTwoByteStringTag;
+}
+
+
+bool StringShape::IsCons() {
+  return (type_ & kStringRepresentationMask) == kConsStringTag;
+}
+
+
+bool StringShape::IsSliced() {
+  return (type_ & kStringRepresentationMask) == kSlicedStringTag;
+}
+
+
+bool StringShape::IsExternal() {
+  return (type_ & kStringRepresentationMask) == kExternalStringTag;
+}
+
+
+bool StringShape::IsSequential() {
+  return (type_ & kStringRepresentationMask) == kSeqStringTag;
+}
+
+
+StringRepresentationTag StringShape::representation_tag() {
+  uint32_t tag = (type_ & kStringRepresentationMask);
+  return static_cast<StringRepresentationTag>(tag);
+}
+
+
+uint32_t StringShape::full_representation_tag() {
+  return (type_ & (kStringRepresentationMask | kStringEncodingMask));
+}
+
+
+uint32_t StringShape::size_tag() {
+  return (type_ & kStringSizeMask);
+}
+
+
+bool StringShape::IsSequentialAscii() {
+  return full_representation_tag() == (kSeqStringTag | kAsciiStringTag);
+}
+
+
+bool StringShape::IsSequentialTwoByte() {
+  return (type_ & (kStringRepresentationMask | kStringEncodingMask)) ==
+         (kSeqStringTag | kTwoByteStringTag);
+}
+
+
+bool StringShape::IsExternalAscii() {
+  return full_representation_tag() == (kExternalStringTag | kAsciiStringTag);
+}
+
+
+bool StringShape::IsExternalTwoByte() {
+  return (type_ & (kStringRepresentationMask | kStringEncodingMask)) ==
+         (kExternalStringTag | kTwoByteStringTag);
 }
 
 
@@ -1128,13 +1211,15 @@
 int DescriptorArray::Search(String* name) {
   SLOW_ASSERT(IsSortedNoDuplicates());
 
+  StringShape shape(name);
+
   // Check for empty descriptor array.
   int nof = number_of_descriptors();
   if (nof == 0) return kNotFound;
 
   // Fast case: do linear search for small arrays.
   const int kMaxElementsForLinearSearch = 8;
-  if (name->IsSymbol() && nof < kMaxElementsForLinearSearch) {
+  if (shape.IsSymbol() && nof < kMaxElementsForLinearSearch) {
     return LinearSearch(name, nof);
   }
 
@@ -1268,19 +1353,27 @@
 
 bool String::Equals(String* other) {
   if (other == this) return true;
-  if (IsSymbol() && other->IsSymbol()) return false;
-  return SlowEquals(other);
+  StringShape this_shape(this);
+  StringShape other_shape(other);
+  if (this_shape.IsSymbol() && other_shape.IsSymbol()) return false;
+  return SlowEquals(this_shape, other, other_shape);
 }
 
 
-int String::length() {
+int String::length(StringShape shape) {
+  ASSERT(shape.type() == StringShape(this).type());
   uint32_t len = READ_INT_FIELD(this, kLengthOffset);
 
   ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
   ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
   ASSERT(kLongStringTag == 0);
 
-  return len >> (size_tag() + kLongLengthShift);
+  return len >> (shape.size_tag() + kLongLengthShift);
+}
+
+
+int String::length() {
+  return length(StringShape(this));
 }
 
 
@@ -1289,9 +1382,10 @@
   ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
   ASSERT(kLongStringTag == 0);
 
+  StringShape shape(this);
   WRITE_INT_FIELD(this,
                   kLengthOffset,
-                  value << (size_tag() + kLongLengthShift));
+                  value << (shape.size_tag() + kLongLengthShift));
 }
 
 
@@ -1305,31 +1399,34 @@
 }
 
 
-void String::TryFlatten() {
+void String::TryFlatten(StringShape shape) {
+  ASSERT(shape.type() == StringShape(this).type());
   // We don't need to flatten strings that are already flat.  Since this code
   // is inlined, it can be helpful in the flat case to not call out to Flatten.
-  StringRepresentationTag str_type = representation_tag();
-  if (str_type != kSeqStringTag && str_type != kExternalStringTag) {
-    Flatten();
+  if (!IsFlat(shape)) {
+    Flatten(shape);
   }
 }
 
 
-uint16_t String::Get(int index) {
-  ASSERT(index >= 0 && index < length());
-  switch (representation_tag()) {
-    case kSeqStringTag:
-      return is_ascii_representation()
-        ? SeqAsciiString::cast(this)->SeqAsciiStringGet(index)
-        : SeqTwoByteString::cast(this)->SeqTwoByteStringGet(index);
-    case kConsStringTag:
+uint16_t String::Get(StringShape shape, int index) {
+  ASSERT(shape.type() == StringShape(this).type());
+  ASSERT(index >= 0 && index < length(shape));
+  switch (shape.full_representation_tag()) {
+    case kSeqStringTag | kAsciiStringTag:
+      return SeqAsciiString::cast(this)->SeqAsciiStringGet(index);
+    case kSeqStringTag | kTwoByteStringTag:
+      return SeqTwoByteString::cast(this)->SeqTwoByteStringGet(index);
+    case kConsStringTag | kAsciiStringTag:
+    case kConsStringTag | kTwoByteStringTag:
       return ConsString::cast(this)->ConsStringGet(index);
-    case kSlicedStringTag:
+    case kSlicedStringTag | kAsciiStringTag:
+    case kSlicedStringTag | kTwoByteStringTag:
       return SlicedString::cast(this)->SlicedStringGet(index);
-    case kExternalStringTag:
-      return is_ascii_representation()
-        ? ExternalAsciiString::cast(this)->ExternalAsciiStringGet(index)
-        : ExternalTwoByteString::cast(this)->ExternalTwoByteStringGet(index);
+    case kExternalStringTag | kAsciiStringTag:
+      return ExternalAsciiString::cast(this)->ExternalAsciiStringGet(index);
+    case kExternalStringTag | kTwoByteStringTag:
+      return ExternalTwoByteString::cast(this)->ExternalTwoByteStringGet(index);
     default:
       break;
   }
@@ -1339,86 +1436,29 @@
 }
 
 
-void String::Set(int index, uint16_t value) {
-  ASSERT(index >= 0 && index < length());
-  ASSERT(IsSeqString());
+void String::Set(StringShape shape, int index, uint16_t value) {
+  ASSERT(shape.type() == StringShape(this).type());
+  ASSERT(shape.type() == StringShape(this).type());
+  ASSERT(index >= 0 && index < length(shape));
+  ASSERT(shape.IsSequential());
 
-  return is_ascii_representation()
+  return shape.IsAsciiRepresentation()
       ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value)
       : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value);
 }
 
 
-bool String::IsAsciiRepresentation() {
-  return is_ascii_representation();
-}
-
-
-bool String::StringIsConsString() {
-  return representation_tag() == kConsStringTag;
-}
-
-
-bool String::StringIsSlicedString() {
-  return representation_tag() == kSlicedStringTag;
-}
-
-
-uint32_t String::size_tag() {
-  return map_size_tag(map());
-}
-
-
-uint32_t String::map_size_tag(Map* map) {
-  return map->instance_type() & kStringSizeMask;
-}
-
-
-bool String::is_symbol() {
-  return is_symbol_map(map());
-}
-
-
-bool String::is_symbol_map(Map* map) {
-  return (map->instance_type() & kIsSymbolMask) != 0;
-}
-
-
-bool String::is_ascii_representation() {
-  return is_ascii_representation_map(map());
-}
-
-
-bool String::is_ascii_representation_map(Map* map) {
-  return (map->instance_type() & kStringEncodingMask) != 0;
-}
-
-
-int String::full_representation_tag() {
-  return map()->instance_type() &
-         (kStringRepresentationMask | kStringEncodingMask);
-}
-
-
-StringRepresentationTag String::representation_tag() {
-  return map_representation_tag(map());
-}
-
-
-StringRepresentationTag String::map_representation_tag(Map* map) {
-  uint32_t tag = map->instance_type() & kStringRepresentationMask;
-  return static_cast<StringRepresentationTag>(tag);
-}
-
-
-bool String::IsFlat() {
-  switch (this->representation_tag()) {
-    case kConsStringTag:
+bool String::IsFlat(StringShape shape) {
+  ASSERT(shape.type() == StringShape(this).type());
+  switch (shape.representation_tag()) {
+    case kConsStringTag: {
+      String* second = ConsString::cast(this)->second();
       // Only flattened strings have second part empty.
-      return String::cast(ConsString::cast(this)->second())->length() == 0;
+      return second->length() == 0;
+    }
     case kSlicedStringTag: {
-      String* slice = String::cast(SlicedString::cast(this)->buffer());
-      StringRepresentationTag tag = slice->representation_tag();
+      StringShape slice_shape = StringShape(SlicedString::cast(this)->buffer());
+      StringRepresentationTag tag = slice_shape.representation_tag();
       return tag == kSeqStringTag || tag == kExternalStringTag;
     }
     default:
@@ -1472,7 +1512,7 @@
 }
 
 
-int SeqTwoByteString::SeqTwoByteStringSize(Map* map) {
+int SeqTwoByteString::SeqTwoByteStringSize(StringShape shape) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
 
   ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
@@ -1481,13 +1521,13 @@
 
   // Use the map (and not 'this') to compute the size tag, since
   // TwoByteStringSize is called during GC when maps are encoded.
-  length >>= map_size_tag(map) + kLongLengthShift;
+  length >>= shape.size_tag() + kLongLengthShift;
 
   return SizeFor(length);
 }
 
 
-int SeqAsciiString::SeqAsciiStringSize(Map* map) {
+int SeqAsciiString::SeqAsciiStringSize(StringShape shape) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
 
   ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
@@ -1496,40 +1536,50 @@
 
   // Use the map (and not 'this') to compute the size tag, since
   // AsciiStringSize is called during GC when maps are encoded.
-  length >>= map_size_tag(map) + kLongLengthShift;
+  length >>= shape.size_tag() + kLongLengthShift;
 
   return SizeFor(length);
 }
 
 
-Object* ConsString::first() {
+String* ConsString::first() {
+  return String::cast(READ_FIELD(this, kFirstOffset));
+}
+
+
+Object* ConsString::unchecked_first() {
   return READ_FIELD(this, kFirstOffset);
 }
 
 
-void ConsString::set_first(Object* value, WriteBarrierMode mode) {
+void ConsString::set_first(String* value, WriteBarrierMode mode) {
   WRITE_FIELD(this, kFirstOffset, value);
   CONDITIONAL_WRITE_BARRIER(this, kFirstOffset, mode);
 }
 
 
-Object* ConsString::second() {
+String* ConsString::second() {
+  return String::cast(READ_FIELD(this, kSecondOffset));
+}
+
+
+Object* ConsString::unchecked_second() {
   return READ_FIELD(this, kSecondOffset);
 }
 
 
-void ConsString::set_second(Object* value, WriteBarrierMode mode) {
+void ConsString::set_second(String* value, WriteBarrierMode mode) {
   WRITE_FIELD(this, kSecondOffset, value);
   CONDITIONAL_WRITE_BARRIER(this, kSecondOffset, mode);
 }
 
 
-Object* SlicedString::buffer() {
-  return READ_FIELD(this, kBufferOffset);
+String* SlicedString::buffer() {
+  return String::cast(READ_FIELD(this, kBufferOffset));
 }
 
 
-void SlicedString::set_buffer(Object* buffer) {
+void SlicedString::set_buffer(String* buffer) {
   WRITE_FIELD(this, kBufferOffset, buffer);
   WRITE_BARRIER(this, kBufferOffset);
 }
@@ -1677,6 +1727,20 @@
 }
 
 
+void Map::set_is_access_check_needed(bool access_check_needed) {
+  if (access_check_needed) {
+    set_bit_field(bit_field() | (1 << kIsAccessCheckNeeded));
+  } else {
+    set_bit_field(bit_field() & ~(1 << kIsAccessCheckNeeded));
+  }
+}
+
+
+bool Map::is_access_check_needed() {
+  return ((1 << kIsAccessCheckNeeded) & bit_field()) != 0;
+}
+
+
 Code::Flags Code::flags() {
   return static_cast<Flags>(READ_INT_FIELD(this, kFlagsOffset));
 }
@@ -2298,6 +2362,16 @@
 }
 
 
+bool AccessorInfo::prohibits_overwriting() {
+  return BooleanBit::get(flag(), kProhibitsOverwritingBit);
+}
+
+
+void AccessorInfo::set_prohibits_overwriting(bool value) {
+  set_flag(BooleanBit::set(flag(), kProhibitsOverwritingBit, value));
+}
+
+
 PropertyAttributes AccessorInfo::property_attributes() {
   return AttributesField::decode(static_cast<uint32_t>(flag()->value()));
 }
diff --git a/src/objects.cc b/src/objects.cc
index 68dd330..23c8061 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -266,6 +266,70 @@
 }
 
 
+PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
+    Object* receiver,
+    LookupResult* result,
+    String* name,
+    bool continue_search) {
+  if (result->IsValid()) {
+    switch (result->type()) {
+      case CALLBACKS: {
+        // Only allow API accessors.
+        Object* obj = result->GetCallbackObject();
+        if (obj->IsAccessorInfo()) {
+          AccessorInfo* info = AccessorInfo::cast(obj);
+          if (info->all_can_read()) {
+            return result->GetAttributes();
+          }
+        }
+        break;
+      }
+
+      case NORMAL:
+      case FIELD:
+      case CONSTANT_FUNCTION: {
+        if (!continue_search) break;
+        // Search ALL_CAN_READ accessors in prototype chain.
+        LookupResult r;
+        result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
+        if (r.IsValid()) {
+          return GetPropertyAttributeWithFailedAccessCheck(receiver,
+                                                           &r,
+                                                           name,
+                                                           continue_search);
+        }
+        break;
+      }
+
+      case INTERCEPTOR: {
+        // If the object has an interceptor, try real named properties.
+        // No access check in GetPropertyAttributeWithInterceptor.
+        LookupResult r;
+        if (continue_search) {
+          result->holder()->LookupRealNamedProperty(name, &r);
+        } else {
+          result->holder()->LocalLookupRealNamedProperty(name, &r);
+        }
+        if (r.IsValid()) {
+          return GetPropertyAttributeWithFailedAccessCheck(receiver,
+                                                           &r,
+                                                           name,
+                                                           continue_search);
+        }
+        break;
+      }
+
+      default: {
+        break;
+      }
+    }
+  }
+
+  Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+  return ABSENT;
+}
+
+
 Object* JSObject::GetLazyProperty(Object* receiver,
                                   LookupResult* result,
                                   String* name,
@@ -475,25 +539,26 @@
 // We don't use the BBC's overcorrect "an historic occasion" though if
 // you speak a dialect you may well say "an 'istoric occasion".
 static bool AnWord(String* str) {
-  if (str->length() == 0) return false;  // a nothing
-  int c0 = str->Get(0);
-  int c1 = str->length() > 1 ? str->Get(1) : 0;
+  StringShape shape(str);
+  if (str->length(shape) == 0) return false;  // A nothing.
+  int c0 = str->Get(shape, 0);
+  int c1 = str->length(shape) > 1 ? str->Get(shape, 1) : 0;
   if (c0 == 'U') {
     if (c1 > 'Z') {
-      return true;  // an Umpire, but a UTF8String, a U
+      return true;  // An Umpire, but a UTF8String, a U.
     }
   } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
-    return true;   // an Ape, an ABCBook
+    return true;    // An Ape, an ABCBook.
   } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
            (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
             c0 == 'S' || c0 == 'X')) {
-    return true;   // an MP3File, an M
+    return true;    // An MP3File, an M.
   }
   return false;
 }
 
 
-Object* String::Flatten() {
+Object* String::Flatten(StringShape shape) {
 #ifdef DEBUG
   // Do not attempt to flatten in debug mode when allocation is not
   // allowed.  This is to avoid an assertion failure when allocating.
@@ -502,44 +567,48 @@
   if (!Heap::IsAllocationAllowed()) return this;
 #endif
 
-  switch (representation_tag()) {
+  switch (shape.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.
-      ASSERT(!ss->buffer()->IsSlicedString());
-      Object* ok = String::cast(ss->buffer())->Flatten();
+      String* buf = ss->buffer();
+      ASSERT(!buf->IsSlicedString());
+      Object* ok = buf->Flatten(StringShape(buf));
       if (ok->IsFailure()) return ok;
       // Under certain circumstances (TryFlatten 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 (String::cast(ok)->StringIsConsString()) {
+      if (StringShape(String::cast(ok)).IsCons()) {
         ss->set_buffer(ConsString::cast(ok)->first());
       }
       return this;
     }
     case kConsStringTag: {
       ConsString* cs = ConsString::cast(this);
-      if (String::cast(cs->second())->length() == 0) {
+      if (cs->second()->length() == 0) {
         return this;
       }
       // There's little point in putting the flat string in new space if the
       // cons string is in old space.  It can never get GCed until there is
       // an old space GC.
       PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED;
-      int len = length();
+      int len = length(shape);
       Object* object;
       String* result;
-      if (IsAsciiRepresentation()) {
+      if (shape.IsAsciiRepresentation()) {
         object = Heap::AllocateRawAsciiString(len, tenure);
         if (object->IsFailure()) return object;
         result = String::cast(object);
-        String* first = String::cast(cs->first());
-        int first_length = first->length();
+        String* first = cs->first();
+        StringShape first_shape(first);
+        int first_length = first->length(first_shape);
         char* dest = SeqAsciiString::cast(result)->GetChars();
-        WriteToFlat(first, dest, 0, first_length);
-        WriteToFlat(String::cast(cs->second()),
+        WriteToFlat(first, first_shape, dest, 0, first_length);
+        String* second = cs->second();
+        WriteToFlat(second,
+                    StringShape(second),
                     dest + first_length,
                     0,
                     len - first_length);
@@ -548,10 +617,13 @@
         if (object->IsFailure()) return object;
         result = String::cast(object);
         uc16* dest = SeqTwoByteString::cast(result)->GetChars();
-        String* first = String::cast(cs->first());
-        int first_length = first->length();
-        WriteToFlat(first, dest, 0, first_length);
-        WriteToFlat(String::cast(cs->second()),
+        String* first = cs->first();
+        StringShape first_shape(first);
+        int first_length = first->length(first_shape);
+        WriteToFlat(first, first_shape, dest, 0, first_length);
+        String* second = cs->second();
+        WriteToFlat(second,
+                    StringShape(second),
                     dest + first_length,
                     0,
                     len - first_length);
@@ -567,7 +639,8 @@
 
 
 void String::StringShortPrint(StringStream* accumulator) {
-  int len = length();
+  StringShape shape(this);
+  int len = length(shape);
   if (len > kMaxMediumStringSize) {
     accumulator->Add("<Very long string[%u]>", len);
     return;
@@ -595,7 +668,7 @@
   }
   buf.Reset(this);
   if (ascii) {
-    accumulator->Add("<String[%u]: ", length());
+    accumulator->Add("<String[%u]: ", length(shape));
     for (int i = 0; i < len; i++) {
       accumulator->Put(buf.GetNext());
     }
@@ -603,7 +676,7 @@
   } else {
     // Backslash indicates that the string contains control
     // characters and that backslashes are therefore escaped.
-    accumulator->Add("<String[%u]\\: ", length());
+    accumulator->Add("<String[%u]\\: ", length(shape));
     for (int i = 0; i < len; i++) {
       int c = buf.GetNext();
       if (c == '\n') {
@@ -781,13 +854,13 @@
   InstanceType instance_type = map->instance_type();
 
   if (instance_type < FIRST_NONSTRING_TYPE
-      && (reinterpret_cast<String*>(this)->map_representation_tag(map)
-          == kSeqStringTag)) {
-    if (reinterpret_cast<String*>(this)->is_ascii_representation_map(map)) {
-      return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(map);
+      && (StringShape(instance_type).IsSequential())) {
+    StringShape shape(instance_type);
+    if (shape.IsAsciiRepresentation()) {
+      return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(shape);
     } else {
       SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this);
-      return self->SeqTwoByteStringSize(map);
+      return self->SeqTwoByteStringSize(shape);
     }
   }
 
@@ -1720,8 +1793,10 @@
   // Check access rights if needed.
   if (IsAccessCheckNeeded() &&
       !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
-    Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
-    return ABSENT;
+    return GetPropertyAttributeWithFailedAccessCheck(receiver,
+                                                     result,
+                                                     name,
+                                                     continue_search);
   }
   if (result->IsValid()) {
     switch (result->type()) {
@@ -2257,9 +2332,19 @@
        current != Heap::null_value();
        current = JSObject::cast(current)->GetPrototype()) {
     JSObject::cast(current)->LocalLookup(name, result);
-    if (result->IsValid() && !result->IsTransitionType()) {
-      return;
-    }
+    if (result->IsValid() && !result->IsTransitionType()) return;
+  }
+  result->NotFound();
+}
+
+
+// Search object and it's prototype chain for callback properties.
+void JSObject::LookupCallback(String* name, LookupResult* result) {
+  for (Object* current = this;
+       current != Heap::null_value();
+       current = JSObject::cast(current)->GetPrototype()) {
+    JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
+    if (result->IsValid() && result->type() == CALLBACKS) return;
   }
   result->NotFound();
 }
@@ -2279,12 +2364,28 @@
   }
 
   // TryFlatten before operating on the string.
-  name->TryFlatten();
+  name->TryFlatten(StringShape(name));
 
   // Make sure name is not an index.
   uint32_t index;
   if (name->AsArrayIndex(&index)) return Heap::undefined_value();
 
+  // Check if there is an API defined callback object which prohibits
+  // callback overwriting in this object or it's prototype chain.
+  // This mechanism is needed for instance in a browser setting, where
+  // certain accessors such as window.location should not be allowed
+  // to be overwriten because allowing overwriting could potentially
+  // cause security problems.
+  LookupResult callback_result;
+  LookupCallback(name, &callback_result);
+  if (callback_result.IsValid()) {
+    Object* obj = callback_result.GetCallbackObject();
+    if (obj->IsAccessorInfo() &&
+        AccessorInfo::cast(obj)->prohibits_overwriting()) {
+      return Heap::undefined_value();
+    }
+  }
+
   // Lookup the name.
   LookupResult result;
   LocalLookup(name, &result);
@@ -2902,27 +3003,21 @@
 
 
 bool String::LooksValid() {
-  if (!Heap::Contains(this))
-    return false;
-  switch (representation_tag()) {
-    case kSeqStringTag:
-    case kConsStringTag:
-    case kSlicedStringTag:
-    case kExternalStringTag:
-      return true;
-    default:
-      return false;
-  }
+  if (!Heap::Contains(this)) return false;
+  return true;
 }
 
 
 int String::Utf8Length() {
-  if (is_ascii_representation()) return length();
+  StringShape shape(this);
+  if (shape.IsAsciiRepresentation()) return length(shape);
   // Attempt to flatten before accessing the string.  It probably
   // doesn't make Utf8Length faster, but it is very likely that
   // the string will be accessed later (for example by WriteUtf8)
   // so it's still a good idea.
-  TryFlatten();
+  if (!IsFlat(shape)) {
+    TryFlatten(shape);  // shape is now no longer valid.
+  }
   Access<StringInputBuffer> buffer(&string_input_buffer);
   buffer->Reset(0, this);
   int result = 0;
@@ -2933,23 +3028,26 @@
 
 
 Vector<const char> String::ToAsciiVector() {
-  ASSERT(IsAsciiRepresentation());
-  ASSERT(IsFlat());
+  StringShape shape(this);
+  ASSERT(shape.IsAsciiRepresentation());
+  ASSERT(IsFlat(shape));
 
   int offset = 0;
-  int length = this->length();
-  StringRepresentationTag string_tag = representation_tag();
+  int length = this->length(shape);
+  StringRepresentationTag string_tag = shape.representation_tag();
   String* string = this;
   if (string_tag == kSlicedStringTag) {
     SlicedString* sliced = SlicedString::cast(string);
     offset += sliced->start();
-    string = String::cast(sliced->buffer());
-    string_tag = string->representation_tag();
+    string = sliced->buffer();
+    shape = StringShape(string);
+    string_tag = shape.representation_tag();
   } else if (string_tag == kConsStringTag) {
     ConsString* cons = ConsString::cast(string);
-    ASSERT(String::cast(cons->second())->length() == 0);
-    string = String::cast(cons->first());
-    string_tag = string->representation_tag();
+    ASSERT(cons->second()->length(StringShape(cons->second())) == 0);
+    string = cons->first();
+    shape = StringShape(string);
+    string_tag = shape.representation_tag();
   }
   if (string_tag == kSeqStringTag) {
     SeqAsciiString* seq = SeqAsciiString::cast(string);
@@ -2964,23 +3062,26 @@
 
 
 Vector<const uc16> String::ToUC16Vector() {
-  ASSERT(IsTwoByteStringRepresentation());
-  ASSERT(IsFlat());
+  StringShape shape(this);
+  ASSERT(shape.IsTwoByteRepresentation());
+  ASSERT(IsFlat(shape));
 
   int offset = 0;
-  int length = this->length();
-  StringRepresentationTag string_tag = representation_tag();
+  int length = this->length(shape);
+  StringRepresentationTag string_tag = shape.representation_tag();
   String* string = this;
   if (string_tag == kSlicedStringTag) {
     SlicedString* sliced = SlicedString::cast(string);
     offset += sliced->start();
     string = String::cast(sliced->buffer());
-    string_tag = string->representation_tag();
+    shape = StringShape(string);
+    string_tag = shape.representation_tag();
   } else if (string_tag == kConsStringTag) {
     ConsString* cons = ConsString::cast(string);
-    ASSERT(String::cast(cons->second())->length() == 0);
-    string = String::cast(cons->first());
-    string_tag = string->representation_tag();
+    ASSERT(cons->second()->length(StringShape(cons->second())) == 0);
+    string = cons->first();
+    shape = StringShape(string);
+    string_tag = shape.representation_tag();
   }
   if (string_tag == kSeqStringTag) {
     SeqTwoByteString* seq = SeqTwoByteString::cast(string);
@@ -3060,8 +3161,9 @@
 
 
 const uc16* String::GetTwoByteData(unsigned start) {
-  ASSERT(!IsAsciiRepresentation());
-  switch (representation_tag()) {
+  StringShape shape(this);
+  ASSERT(!shape.IsAsciiRepresentation());
+  switch (shape.representation_tag()) {
     case kSeqStringTag:
       return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
     case kExternalStringTag:
@@ -3069,12 +3171,12 @@
         ExternalTwoByteStringGetData(start);
     case kSlicedStringTag: {
       SlicedString* sliced_string = SlicedString::cast(this);
-      String* buffer = String::cast(sliced_string->buffer());
-      if (buffer->StringIsConsString()) {
-        ConsString* cons_string = ConsString::cast(buffer);
+      String* buffer = sliced_string->buffer();
+      if (StringShape(buffer).IsCons()) {
+        ConsString* cs = ConsString::cast(buffer);
         // Flattened string.
-        ASSERT(String::cast(cons_string->second())->length() == 0);
-        buffer = String::cast(cons_string->first());
+        ASSERT(cs->second()->length(StringShape(cs->second())) == 0);
+        buffer = cs->first();
       }
       return buffer->GetTwoByteData(start + sliced_string->start());
     }
@@ -3175,8 +3277,9 @@
   int offset_correction = 0;
 
   while (true) {
-    String* left = String::cast(current->first());
-    unsigned left_length = (unsigned)left->length();
+    String* left = current->first();
+    StringShape left_shape(left);
+    unsigned left_length = (unsigned)left->length(left_shape);
     if (left_length > offset &&
         (max_chars <= left_length - offset ||
          (rbb->capacity <= left_length - offset &&
@@ -3188,7 +3291,7 @@
       // the point where we switch to the -IntoBuffer routines (below) in order
       // to maximize the chances of delegating a big chunk of work to the
       // efficient *AsciiStringReadBlock routines.
-      if (left->StringIsConsString()) {
+      if (left_shape.IsCons()) {
         current = ConsString::cast(left);
         continue;
       } else {
@@ -3200,10 +3303,10 @@
     } else if (left_length <= offset) {
       // Right hand side only - iterate unless we have reached the bottom of
       // the cons tree.
-      String* right = String::cast(current->second());
+      String* right = current->second();
       offset -= left_length;
       offset_correction += left_length;
-      if (right->StringIsConsString()) {
+      if (StringShape(right).IsCons()) {
         current = ConsString::cast(right);
         continue;
       } else {
@@ -3235,7 +3338,7 @@
 const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb,
                                                          unsigned* offset_ptr,
                                                          unsigned max_chars) {
-  String* backing = String::cast(buffer());
+  String* backing = buffer();
   unsigned offset = start() + *offset_ptr;
   unsigned length = backing->length();
   if (max_chars > length - offset) {
@@ -3353,9 +3456,10 @@
     rbb->remaining = 0;
     return NULL;
   }
-  switch (input->representation_tag()) {
+  StringShape shape(input);
+  switch (shape.representation_tag()) {
     case kSeqStringTag:
-      if (input->is_ascii_representation()) {
+      if (shape.IsAsciiRepresentation()) {
         SeqAsciiString* str = SeqAsciiString::cast(input);
         return str->SeqAsciiStringReadBlock(&rbb->remaining,
                                             offset_ptr,
@@ -3376,7 +3480,7 @@
                                                               offset_ptr,
                                                               max_chars);
     case kExternalStringTag:
-      if (input->is_ascii_representation()) {
+      if (shape.IsAsciiRepresentation()) {
         return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
             &rbb->remaining,
             offset_ptr,
@@ -3415,12 +3519,13 @@
                                  ReadBlockBuffer* rbb,
                                  unsigned* offset_ptr,
                                  unsigned max_chars) {
-  ASSERT(*offset_ptr <= (unsigned)input->length());
+  StringShape shape(input);
+  ASSERT(*offset_ptr <= (unsigned)input->length(shape));
   if (max_chars == 0) return;
 
-  switch (input->representation_tag()) {
+  switch (shape.representation_tag()) {
     case kSeqStringTag:
-      if (input->is_ascii_representation()) {
+      if (shape.IsAsciiRepresentation()) {
         SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
                                                                  offset_ptr,
                                                                  max_chars);
@@ -3442,7 +3547,7 @@
                                                                  max_chars);
       return;
     case kExternalStringTag:
-      if (input->is_ascii_representation()) {
+      if (shape.IsAsciiRepresentation()) {
          ExternalAsciiString::cast(input)->
              ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
        } else {
@@ -3466,11 +3571,12 @@
                                        unsigned capacity,
                                        unsigned* remaining,
                                        unsigned* offset_ptr) {
-  ASSERT(*offset_ptr <= (unsigned)input->length());
-  unsigned chars = input->length() - *offset_ptr;
+  StringShape shape(input);
+  ASSERT(*offset_ptr <= (unsigned)input->length(shape));
+  unsigned chars = input->length(shape) - *offset_ptr;
   ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
   const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
-  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
+  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape)));
   *remaining = rbb.remaining;
   return answer;
 }
@@ -3481,13 +3587,14 @@
                                        unsigned capacity,
                                        unsigned* remaining,
                                        unsigned* offset_ptr) {
+  StringShape shape(*raw_input);
   Handle<String> input(raw_input);
-  ASSERT(*offset_ptr <= (unsigned)input->length());
-  unsigned chars = input->length() - *offset_ptr;
+  ASSERT(*offset_ptr <= (unsigned)input->length(shape));
+  unsigned chars = input->length(shape) - *offset_ptr;
   if (chars > capacity) chars = capacity;
   ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
   ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
-  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
+  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape)));
   *remaining = rbb.remaining;
   return rbb.util_buffer;
 }
@@ -3506,13 +3613,14 @@
   int offset_correction = 0;
 
   while (true) {
-    String* left = String::cast(current->first());
-    unsigned left_length = (unsigned)left->length();
+    String* left = current->first();
+    StringShape left_shape(left);
+    unsigned left_length = (unsigned)left->length(left_shape);
     if (left_length > offset &&
       max_chars <= left_length - offset) {
       // Left hand side only - iterate unless we have reached the bottom of
       // the cons tree.
-      if (left->StringIsConsString()) {
+      if (left_shape.IsCons()) {
         current = ConsString::cast(left);
         continue;
       } else {
@@ -3525,8 +3633,8 @@
       // the cons tree.
       offset -= left_length;
       offset_correction += left_length;
-      String* right = String::cast(current->second());
-      if (right->StringIsConsString()) {
+      String* right = current->second();
+      if (StringShape(right).IsCons()) {
         current = ConsString::cast(right);
         continue;
       } else {
@@ -3558,7 +3666,7 @@
 void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
                                                    unsigned* offset_ptr,
                                                    unsigned max_chars) {
-  String* backing = String::cast(buffer());
+  String* backing = buffer();
   unsigned offset = start() + *offset_ptr;
   unsigned length = backing->length();
   if (max_chars > length - offset) {
@@ -3578,24 +3686,29 @@
   ASSERT(index >= 0 && index < this->length());
 
   // Check for a flattened cons string
-  if (String::cast(second())->length() == 0) {
-    return String::cast(first())->Get(index);
+  if (second()->length() == 0) {
+    String* left = first();
+    return left->Get(StringShape(left), index);
   }
 
   String* string = String::cast(this);
+  StringShape shape(string);
 
   while (true) {
-    if (string->StringIsConsString()) {
+    if (shape.IsCons()) {
       ConsString* cons_string = ConsString::cast(string);
-      String* left = String::cast(cons_string->first());
-      if (left->length() > index) {
+      String* left = cons_string->first();
+      StringShape left_shape(left);
+      if (left->length(left_shape) > index) {
         string = left;
+        shape = left_shape;
       } else {
-        index -= left->length();
-        string = String::cast(cons_string->second());
+        index -= left->length(left_shape);
+        string = cons_string->second();
+        shape = StringShape(string);
       }
     } else {
-      return string->Get(index);
+      return string->Get(shape, index);
     }
   }
 
@@ -3609,9 +3722,10 @@
   // SlicedStrings that are constructed directly on top of other
   // SlicedStrings.
   String* buf = String::cast(buffer());
-  ASSERT(!buf->StringIsSlicedString());
-  if (buf->StringIsConsString()) {
-    Object* ok = buf->Flatten();
+  StringShape buf_shape(buf);
+  ASSERT(!buf_shape.IsSliced());
+  if (buf_shape.IsCons()) {
+    Object* ok = buf->Flatten(buf_shape);
     if (ok->IsFailure()) return ok;
   }
   return this;
@@ -3620,15 +3734,17 @@
 
 template <typename sinkchar>
 void String::WriteToFlat(String* src,
+                         StringShape src_shape,
                          sinkchar* sink,
                          int f,
                          int t) {
   String* source = src;
+  StringShape shape = src_shape;
   int from = f;
   int to = t;
   while (true) {
-    ASSERT(0 <= from && from <= to && to <= source->length());
-    switch (source->full_representation_tag()) {
+    ASSERT(0 <= from && from <= to && to <= source->length(shape));
+    switch (shape.full_representation_tag()) {
       case kAsciiStringTag | kExternalStringTag: {
         CopyChars(sink,
                   ExternalAsciiString::cast(source)->resource()->data() + from,
@@ -3662,35 +3778,40 @@
         from += start;
         to += start;
         source = String::cast(sliced_string->buffer());
+        shape = StringShape(source);
         break;
       }
       case kAsciiStringTag | kConsStringTag:
       case kTwoByteStringTag | kConsStringTag: {
         ConsString* cons_string = ConsString::cast(source);
-        String* first = String::cast(cons_string->first());
-        int boundary = first->length();
+        String* first = cons_string->first();
+        StringShape first_shape(first);
+        int boundary = first->length(first_shape);
         if (to - boundary >= boundary - from) {
           // Right hand side is longer.  Recurse over left.
           if (from < boundary) {
-            WriteToFlat(first, sink, from, boundary);
+            WriteToFlat(first, first_shape, sink, from, boundary);
             sink += boundary - from;
             from = 0;
           } else {
             from -= boundary;
           }
           to -= boundary;
-          source = String::cast(cons_string->second());
+          source = cons_string->second();
+          shape = StringShape(source);
         } else {
           // Left hand side is longer.  Recurse over right.
           if (to > boundary) {
-            String* second = String::cast(cons_string->second());
+            String* second = cons_string->second();
             WriteToFlat(second,
+                        StringShape(second),
                         sink + boundary - from,
                         0,
                         to - boundary);
             to = boundary;
           }
           source = first;
+          shape = first_shape;
         }
         break;
       }
@@ -3707,7 +3828,8 @@
 uint16_t SlicedString::SlicedStringGet(int index) {
   ASSERT(index >= 0 && index < this->length());
   // Delegate to the buffer string.
-  return String::cast(buffer())->Get(start() + index);
+  String* underlying = buffer();
+  return underlying->Get(StringShape(underlying), start() + index);
 }
 
 
@@ -3771,8 +3893,9 @@
 
 template <typename IteratorA>
 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
-  if (b->IsFlat()) {
-    if (b->IsAsciiRepresentation()) {
+  StringShape b_shape(b);
+  if (b->IsFlat(b_shape)) {
+    if (b_shape.IsAsciiRepresentation()) {
       VectorIterator<char> ib(b->ToAsciiVector());
       return CompareStringContents(ia, &ib);
     } else {
@@ -3789,10 +3912,12 @@
 static StringInputBuffer string_compare_buffer_a;
 
 
-bool String::SlowEquals(String* other) {
+bool String::SlowEquals(StringShape this_shape,
+                        String* other,
+                        StringShape other_shape) {
   // Fast check: negative check with lengths.
-  int len = length();
-  if (len != other->length()) return false;
+  int len = length(this_shape);
+  if (len != other->length(other_shape)) return false;
   if (len == 0) return true;
 
   // Fast check: if hash code is computed for both strings
@@ -3801,18 +3926,18 @@
     if (Hash() != other->Hash()) return false;
   }
 
-  if (this->IsSeqAsciiString() && other->IsSeqAsciiString()) {
+  if (this_shape.IsSequentialAscii() && other_shape.IsSequentialAscii()) {
     const char* str1 = SeqAsciiString::cast(this)->GetChars();
     const char* str2 = SeqAsciiString::cast(other)->GetChars();
     return CompareRawStringContents(Vector<const char>(str1, len),
                                     Vector<const char>(str2, len));
   }
 
-  if (this->IsFlat()) {
-    if (this->IsAsciiRepresentation()) {
+  if (this->IsFlat(this_shape)) {
+    if (this_shape.IsAsciiRepresentation()) {
       Vector<const char> vec1 = this->ToAsciiVector();
-      if (other->IsFlat()) {
-        if (other->IsAsciiRepresentation()) {
+      if (other->IsFlat(other_shape)) {
+        if (other_shape.IsAsciiRepresentation()) {
           Vector<const char> vec2 = other->ToAsciiVector();
           return CompareRawStringContents(vec1, vec2);
         } else {
@@ -3827,8 +3952,8 @@
       }
     } else {
       Vector<const uc16> vec1 = this->ToUC16Vector();
-      if (other->IsFlat()) {
-        if (other->IsAsciiRepresentation()) {
+      if (other->IsFlat(other_shape)) {
+        if (other_shape.IsAsciiRepresentation()) {
           VectorIterator<uc16> buf1(vec1);
           VectorIterator<char> ib(other->ToAsciiVector());
           return CompareStringContents(&buf1, &ib);
@@ -3850,7 +3975,8 @@
 
 
 bool String::MarkAsUndetectable() {
-  if (this->IsSymbol()) return false;
+  StringShape shape(this);
+  if (shape.IsSymbol()) return false;
 
   Map* map = this->map();
   if (map == Heap::short_string_map()) {
@@ -3878,13 +4004,14 @@
 
 
 bool String::IsEqualTo(Vector<const char> str) {
-  int slen = length();
+  StringShape this_shape(this);
+  int slen = length(this_shape);
   Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
   decoder->Reset(str.start(), str.length());
   int i;
   for (i = 0; i < slen && decoder->has_more(); i++) {
     uc32 r = decoder->GetNext();
-    if (Get(i) != r) return false;
+    if (Get(this_shape, i) != r) return false;
   }
   return i == slen && !decoder->has_more();
 }
@@ -3938,7 +4065,8 @@
 
 
 bool String::SlowAsArrayIndex(uint32_t* index) {
-  if (length() <= kMaxCachedArrayIndexLength) {
+  StringShape shape(this);
+  if (length(shape) <= kMaxCachedArrayIndexLength) {
     Hash();  // force computation of hash code
     uint32_t field = length_field();
     if ((field & kIsArrayIndexMask) == 0) return false;
@@ -3946,7 +4074,7 @@
     return true;
   } else {
     StringInputBuffer buffer(this);
-    return ComputeArrayIndex(&buffer, index, length());
+    return ComputeArrayIndex(&buffer, index, length(shape));
   }
 }
 
@@ -4006,20 +4134,21 @@
 }
 
 
-Object* String::Slice(int start, int end) {
-  if (start == 0 && end == length()) return this;
-  int representation = representation_tag();
-  if (representation == kSlicedStringTag) {
+Object* String::Slice(StringShape shape, int start, int end) {
+  if (start == 0 && end == length(shape)) return this;
+  if (shape.representation_tag() == kSlicedStringTag) {
     // Translate slices of a SlicedString into slices of the
     // underlying string buffer.
     SlicedString* str = SlicedString::cast(this);
-    return Heap::AllocateSlicedString(String::cast(str->buffer()),
+    String* buf = str->buffer();
+    return Heap::AllocateSlicedString(buf,
+                                      StringShape(buf),
                                       str->start() + start,
                                       str->start() + end);
   }
-  Object* answer = Heap::AllocateSlicedString(this, start, end);
-  if (answer->IsFailure()) {
-    return answer;
+  Object* result = Heap::AllocateSlicedString(this, shape, 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.
@@ -4031,12 +4160,15 @@
   // 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.
-  if (String::cast(answer)->StringIsSlicedString() &&
-      representation == kConsStringTag) {
-    TryFlatten();
+  String* answer = String::cast(result);
+  StringShape answer_shape(answer);
+  if (answer_shape.IsSliced() &&
+      shape.representation_tag() == kConsStringTag) {
+    TryFlatten(shape);
     // If the flatten succeeded we might as well make the sliced string point
     // to the flat string rather than the cons string.
-    if (String::cast(ConsString::cast(this)->second())->length() == 0) {
+    String* second = ConsString::cast(this)->second();
+    if (second->length(StringShape(second)) == 0) {
       SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first());
     }
   }
@@ -4045,9 +4177,10 @@
 
 
 void String::PrintOn(FILE* file) {
-  int length = this->length();
+  StringShape shape(this);
+  int length = this->length(shape);
   for (int i = 0; i < length; i++) {
-    fprintf(file, "%c", Get(i));
+    fprintf(file, "%c", Get(shape, i));
   }
 }
 
@@ -5532,12 +5665,13 @@
     Object* val = JSValue::cast(this)->value();
     if (val->IsString()) {
       String* str = String::cast(val);
+      StringShape shape(str);
       if (storage) {
-        for (int i = 0; i < str->length(); i++) {
+        for (int i = 0; i < str->length(shape); i++) {
           storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER);
         }
       }
-      counter += str->length();
+      counter += str->length(shape);
     }
   }
   ASSERT(!storage || storage->length() == counter);
@@ -5722,11 +5856,12 @@
   Object* GetObject() {
     // If the string is a cons string, attempt to flatten it so that
     // symbols will most often be flat strings.
-    if (string_->IsConsString()) {
+    StringShape shape(string_);
+    if (shape.IsCons()) {
       ConsString* cons_string = ConsString::cast(string_);
-      cons_string->TryFlatten();
+      cons_string->TryFlatten(shape);
       if (cons_string->second() == Heap::empty_string()) {
-        string_ = String::cast(cons_string->first());
+        string_ = cons_string->first();
       }
     }
     // Transform string to symbol if possible.
@@ -5884,7 +6019,7 @@
     return false;
   } else {
     String* result = String::cast(KeyAt(entry));
-    ASSERT(result->is_symbol());
+    ASSERT(StringShape(result).IsSymbol());
     *symbol = result;
     return true;
   }
diff --git a/src/objects.h b/src/objects.h
index f2f9e18..a291822 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -595,20 +595,16 @@
   inline bool IsHeapObject();
   inline bool IsHeapNumber();
   inline bool IsString();
+  inline bool IsSymbol();
   inline bool IsSeqString();
-  inline bool IsAsciiStringRepresentation();
-  inline bool IsTwoByteStringRepresentation();
-  inline bool IsSeqAsciiString();
-  inline bool IsSeqTwoByteString();
-  inline bool IsConsString();
   inline bool IsSlicedString();
   inline bool IsExternalString();
-  inline bool IsExternalAsciiString();
+  inline bool IsConsString();
   inline bool IsExternalTwoByteString();
-  inline bool IsShortString();
-  inline bool IsMediumString();
-  inline bool IsLongString();
-  inline bool IsSymbol();
+  inline bool IsExternalAsciiString();
+  inline bool IsSeqTwoByteString();
+  inline bool IsSeqAsciiString();
+
   inline bool IsNumber();
   inline bool IsByteArray();
   inline bool IsFailure();
@@ -1280,6 +1276,7 @@
   void LookupRealNamedProperty(String* name, LookupResult* result);
   void LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result);
   void LookupCallbackSetterInPrototypes(String* name, LookupResult* result);
+  void LookupCallback(String* name, LookupResult* result);
 
   // Returns the number of properties on this object filtering out properties
   // with the specified attributes (ignoring interceptors).
@@ -1452,6 +1449,11 @@
   PropertyAttributes GetPropertyAttributeWithInterceptor(JSObject* receiver,
                                                          String* name,
                                                          bool continue_search);
+  PropertyAttributes GetPropertyAttributeWithFailedAccessCheck(
+      Object* receiver,
+      LookupResult* result,
+      String* name,
+      bool continue_search);
   PropertyAttributes GetPropertyAttribute(JSObject* receiver,
                                           LookupResult* result,
                                           String* name,
@@ -2364,13 +2366,8 @@
 
   // Tells whether the instance needs security checks when accessing its
   // properties.
-  inline void set_is_access_check_needed() {
-    set_bit_field(bit_field() | (1 << kIsAccessCheckNeeded));
-  }
-
-  inline bool is_access_check_needed() {
-    return ((1 << kIsAccessCheckNeeded) & bit_field()) != 0;
-  }
+  inline void set_is_access_check_needed(bool access_check_needed);
+  inline bool is_access_check_needed();
 
   // [prototype]: implicit prototype object.
   DECL_ACCESSORS(prototype, Object)
@@ -3021,6 +3018,56 @@
 };
 
 
+// The characteristics of a string are stored in its map.  Retrieving these
+// few bits of information is moderately expensive, involving two memory
+// loads where the second is dependent on the first.  To improve efficiency
+// the shape of the string is given its own class so that it can be retrieved
+// once and used for several string operations.  A StringShape is small enough
+// to be passed by value and is immutable, but be aware that flattening a
+// string can potentially alter its shape.
+//
+// Most of the methods designed to interrogate a string as to its exact nature
+// have been made into methods on StringShape in order to encourage the use of
+// StringShape.  The String class has both a length() and a length(StringShape)
+// operation.  The former is simpler to type, but the latter is faster if you
+// need the StringShape for some other operation immediately before or after.
+class StringShape BASE_EMBEDDED {
+ public:
+  inline explicit StringShape(String* s);
+  inline explicit StringShape(Map* s);
+  inline explicit StringShape(InstanceType t);
+  inline bool IsAsciiRepresentation();
+  inline bool IsTwoByteRepresentation();
+  inline bool IsSequential();
+  inline bool IsExternal();
+  inline bool IsCons();
+  inline bool IsSliced();
+  inline bool IsExternalAscii();
+  inline bool IsExternalTwoByte();
+  inline bool IsSequentialAscii();
+  inline bool IsSequentialTwoByte();
+  inline bool IsSymbol();
+  inline StringRepresentationTag representation_tag();
+  inline uint32_t full_representation_tag();
+  inline uint32_t size_tag();
+#ifdef DEBUG
+  inline uint32_t type() { return type_; }
+  inline void invalidate() { valid_ = false; }
+  inline bool valid() { return valid_; }
+#else
+  inline void invalidate() { }
+#endif
+ private:
+  uint32_t type_;
+#ifdef DEBUG
+  inline void set_valid() { valid_ = true; }
+  bool valid_;
+#else
+  inline void set_valid() { }
+#endif
+};
+
+
 // The String abstract class captures JavaScript string values:
 //
 // Ecma-262:
@@ -3032,6 +3079,9 @@
 class String: public HeapObject {
  public:
   // Get and set the length of the string.
+  // Fast version.
+  inline int length(StringShape shape);
+  // Easy version.
   inline int length();
   inline void set_length(int value);
 
@@ -3043,32 +3093,20 @@
   inline void set_length_field(uint32_t value);
 
   // Get and set individual two byte chars in the string.
-  inline void Set(int index, uint16_t value);
+  inline void Set(StringShape shape, int index, uint16_t value);
   // Get individual two byte char in the string.  Repeated calls
   // to this method are not efficient unless the string is flat.
-  inline uint16_t Get(int index);
+  inline uint16_t Get(StringShape shape, int index);
 
   // Flatten the top level ConsString that is hiding behind this
   // string.  This is a no-op unless the string is a ConsString or a
   // SlicedString.  Flatten mutates the ConsString and might return a
   // failure.
-  Object* Flatten();
+  Object* Flatten(StringShape shape);
   // Try to flatten the string.  Do not allow handling of allocation
   // failures.  After calling TryFlatten, the string could still be a
   // ConsString.
-  inline void TryFlatten();
-
-  // Is this string an ascii string.
-  inline bool IsAsciiRepresentation();
-
-  // Specialization of this function from Object that skips the
-  // string check.
-  inline bool IsSeqAsciiString();
-
-  // Fast testing routines that assume the receiver is a string and
-  // just check whether it is a certain kind of string.
-  inline bool StringIsSlicedString();
-  inline bool StringIsConsString();
+  inline void TryFlatten(StringShape shape);
 
   Vector<const char> ToAsciiVector();
   Vector<const uc16> ToUC16Vector();
@@ -3078,7 +3116,7 @@
   bool MarkAsUndetectable();
 
   // Slice the string and return a substring.
-  Object* Slice(int from, int to);
+  Object* Slice(StringShape shape, int from, int to);
 
   // String equality operations.
   inline bool Equals(String* other);
@@ -3134,24 +3172,6 @@
 
   void PrintOn(FILE* out);
 
-  // Get the size tag.
-  inline uint32_t size_tag();
-  static inline uint32_t map_size_tag(Map* map);
-
-  // True if the string is a symbol.
-  inline bool is_symbol();
-  static inline bool is_symbol_map(Map* map);
-
-  // True if the string is ASCII.
-  inline bool is_ascii_representation();
-  static inline bool is_ascii_representation_map(Map* map);
-
-  // Get the representation tag.
-  inline StringRepresentationTag representation_tag();
-  // Get the representation and ASCII tag.
-  inline int full_representation_tag();
-  static inline StringRepresentationTag map_representation_tag(Map* map);
-
   // For use during stack traces.  Performs rudimentary sanity check.
   bool LooksValid();
 
@@ -3161,7 +3181,7 @@
   void StringPrint();
   void StringVerify();
 #endif
-  inline bool IsFlat();
+  inline bool IsFlat(StringShape shape);
 
   // Layout description.
   static const int kLengthOffset = HeapObject::kHeaderSize;
@@ -3221,6 +3241,7 @@
   // Helper function for flattening strings.
   template <typename sinkchar>
   static void WriteToFlat(String* source,
+                          StringShape shape,
                           sinkchar* sink,
                           int from,
                           int to);
@@ -3261,7 +3282,9 @@
  private:
   // Slow case of String::Equals.  This implementation works on any strings
   // but it is most efficient on strings that are almost flat.
-  bool SlowEquals(String* other);
+  bool SlowEquals(StringShape this_shape,
+                  String* other,
+                  StringShape other_shape);
 
   // Slow case of AsArrayIndex.
   bool SlowAsArrayIndex(uint32_t* index);
@@ -3308,7 +3331,7 @@
   // Garbage collection support.  This method is called by the
   // garbage collector to compute the actual size of an AsciiString
   // instance.
-  inline int SeqAsciiStringSize(Map* map);
+  inline int SeqAsciiStringSize(StringShape shape);
 
   // Computes the size for an AsciiString instance of a given length.
   static int SizeFor(int length) {
@@ -3353,7 +3376,7 @@
   // Garbage collection support.  This method is called by the
   // garbage collector to compute the actual size of a TwoByteString
   // instance.
-  inline int SeqTwoByteStringSize(Map* map);
+  inline int SeqTwoByteStringSize(StringShape shape);
 
   // Computes the size for a TwoByteString instance of a given length.
   static int SizeFor(int length) {
@@ -3383,14 +3406,20 @@
 // values in a left-to-right depth-first traversal of the tree.
 class ConsString: public String {
  public:
-  // First object of the cons cell.
-  inline Object* first();
-  inline void set_first(Object* first,
+  // First string of the cons cell.
+  inline String* first();
+  // Doesn't check that the result is a string, even in debug mode.  This is
+  // useful during GC where the mark bits confuse the checks.
+  inline Object* unchecked_first();
+  inline void set_first(String* first,
                         WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
 
-  // Second object of the cons cell.
-  inline Object* second();
-  inline void set_second(Object* second,
+  // Second string of the cons cell.
+  inline String* second();
+  // Doesn't check that the result is a string, even in debug mode.  This is
+  // useful during GC where the mark bits confuse the checks.
+  inline Object* unchecked_second();
+  inline void set_second(String* second,
                          WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
 
   // Dispatched behavior.
@@ -3432,8 +3461,8 @@
 class SlicedString: public String {
  public:
   // The underlying string buffer.
-  inline Object* buffer();
-  inline void set_buffer(Object* buffer);
+  inline String* buffer();
+  inline void set_buffer(String* buffer);
 
   // The start index of the slice.
   inline int start();
@@ -3717,6 +3746,9 @@
   inline bool all_can_write();
   inline void set_all_can_write(bool value);
 
+  inline bool prohibits_overwriting();
+  inline void set_prohibits_overwriting(bool value);
+
   inline PropertyAttributes property_attributes();
   inline void set_property_attributes(PropertyAttributes attributes);
 
@@ -3736,9 +3768,10 @@
 
  private:
   // Bit positions in flag.
-  static const int kAllCanReadBit  = 0;
+  static const int kAllCanReadBit = 0;
   static const int kAllCanWriteBit = 1;
-  class AttributesField: public BitField<PropertyAttributes, 2, 3> {};
+  static const int kProhibitsOverwritingBit = 2;
+  class AttributesField: public BitField<PropertyAttributes, 3, 3> {};
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(AccessorInfo);
 };
diff --git a/src/parser.cc b/src/parser.cc
index 9090dbb..ef92e3c 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -737,10 +737,11 @@
   ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
 
   StatsRateScope timer(&Counters::parse);
-  Counters::total_parse_size.Increment(source->length());
+  StringShape shape(*source);
+  Counters::total_parse_size.Increment(source->length(shape));
 
   // Initialize parser state.
-  source->TryFlatten();
+  source->TryFlatten(shape);
   scanner_.Init(source, stream, 0);
   ASSERT(target_stack_ == NULL);
 
@@ -767,7 +768,7 @@
                                    temp_scope.materialized_literal_count(),
                                    temp_scope.contains_array_literal(),
                                    temp_scope.expected_property_count(),
-                                   0, 0, source->length(), false));
+                                   0, 0, source->length(shape), false));
     } else if (scanner().stack_overflow()) {
       Top::StackOverflow();
     }
@@ -789,11 +790,12 @@
                                    bool is_expression) {
   ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
   StatsRateScope timer(&Counters::parse_lazy);
-  Counters::total_parse_size.Increment(source->length());
+  StringShape shape(*source);
+  source->TryFlatten(shape);
+  Counters::total_parse_size.Increment(source->length(shape));
   SafeStringInputBuffer buffer(source.location());
 
   // Initialize parser state.
-  source->TryFlatten();
   scanner_.Init(source, &buffer, start_position);
   ASSERT(target_stack_ == NULL);
   mode_ = PARSE_EAGERLY;
diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
index ecaa7c5..39af187 100644
--- a/src/prettyprinter.cc
+++ b/src/prettyprinter.cc
@@ -503,9 +503,10 @@
   Object* object = *value;
   if (object->IsString()) {
     String* string = String::cast(object);
+    StringShape shape(string);
     if (quote) Print("\"");
-    for (int i = 0; i < string->length(); i++) {
-      Print("%c", string->Get(i));
+    for (int i = 0; i < string->length(shape); i++) {
+      Print("%c", string->Get(shape, i));
     }
     if (quote) Print("\"");
   } else if (object == Heap::null_value()) {
diff --git a/src/property.h b/src/property.h
index dc72bb3..9af6cbb 100644
--- a/src/property.h
+++ b/src/property.h
@@ -45,7 +45,7 @@
   }
 
   Object* KeyToSymbol() {
-    if (!key_->IsSymbol()) {
+    if (!StringShape(key_).IsSymbol()) {
       Object* result = Heap::LookupSymbol(key_);
       if (result->IsFailure()) return result;
       key_ = String::cast(result);
diff --git a/src/runtime.cc b/src/runtime.cc
index 8459af1..1949cc4 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -336,6 +336,23 @@
 }
 
 
+static Object* Runtime_DisableAccessChecks(Arguments args) {
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(HeapObject, object, args[0]);
+  bool needs_access_checks = object->map()->is_access_check_needed();
+  object->map()->set_is_access_check_needed(false);
+  return needs_access_checks ? Heap::true_value() : Heap::false_value();
+}
+
+
+static Object* Runtime_EnableAccessChecks(Arguments args) {
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(HeapObject, object, args[0]);
+  object->map()->set_is_access_check_needed(true);
+  return Heap::undefined_value();
+}
+
+
 static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
   HandleScope scope;
   Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
@@ -952,9 +969,12 @@
   // Flatten the string.  If someone wants to get a char at an index
   // in a cons string, it is likely that more indices will be
   // accessed.
-  subject->TryFlatten();
-  if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value();
-  return Smi::FromInt(subject->Get(i));
+  StringShape shape(subject);
+  subject->TryFlatten(shape);  // shape no longer valid!
+  if (i >= static_cast<uint32_t>(subject->length(StringShape(subject)))) {
+    return Heap::nan_value();
+  }
+  return Smi::FromInt(subject->Get(StringShape(subject), i));
 }
 
 
@@ -1334,39 +1354,51 @@
                          Handle<String> pat,
                          int start_index) {
   ASSERT(0 <= start_index);
-  ASSERT(start_index <= sub->length());
+  StringShape sub_shape(*sub);
+  StringShape pat_shape(*pat);
+  ASSERT(start_index <= sub->length(sub_shape));
 
-  int pattern_length = pat->length();
+  int pattern_length = pat->length(pat_shape);
   if (pattern_length == 0) return start_index;
 
-  int subject_length = sub->length();
+  int subject_length = sub->length(sub_shape);
   if (start_index + pattern_length > subject_length) return -1;
 
-  FlattenString(sub);
+  if (!sub->IsFlat(sub_shape)) {
+    FlattenString(sub);
+    sub_shape = StringShape(*sub);
+  }
   // Searching for one specific character is common.  For one
   // character patterns linear search is necessary, so any smart
   // algorithm is unnecessary overhead.
   if (pattern_length == 1) {
     AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
-    if (sub->is_ascii_representation()) {
-      return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(0), start_index);
+    if (sub_shape.IsAsciiRepresentation()) {
+      return SingleCharIndexOf(sub->ToAsciiVector(),
+                               pat->Get(pat_shape, 0),
+                               start_index);
     }
-    return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index);
+    return SingleCharIndexOf(sub->ToUC16Vector(),
+                             pat->Get(pat_shape, 0),
+                             start_index);
   }
 
-  FlattenString(pat);
+  if (!pat->IsFlat(pat_shape)) {
+    FlattenString(pat);
+    pat_shape = StringShape(*pat);
+  }
 
   AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
   // dispatch on type of strings
-  if (pat->is_ascii_representation()) {
+  if (pat_shape.IsAsciiRepresentation()) {
     Vector<const char> pat_vector = pat->ToAsciiVector();
-    if (sub->is_ascii_representation()) {
+    if (sub_shape.IsAsciiRepresentation()) {
       return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
     }
     return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
   }
   Vector<const uc16> pat_vector = pat->ToUC16Vector();
-  if (sub->is_ascii_representation()) {
+  if (sub_shape.IsAsciiRepresentation()) {
     return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
   }
   return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
@@ -1384,6 +1416,7 @@
   uint32_t start_index;
   if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
 
+  RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
   int position = Runtime::StringMatch(sub, pat, start_index);
   return Smi::FromInt(position);
 }
@@ -1397,14 +1430,17 @@
   CONVERT_CHECKED(String, pat, args[1]);
   Object* index = args[2];
 
-  sub->TryFlatten();
-  pat->TryFlatten();
+  sub->TryFlatten(StringShape(sub));
+  pat->TryFlatten(StringShape(pat));
+
+  StringShape sub_shape(sub);
+  StringShape pat_shape(pat);
 
   uint32_t start_index;
   if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
 
-  uint32_t pattern_length = pat->length();
-  uint32_t sub_length = sub->length();
+  uint32_t pattern_length = pat->length(pat_shape);
+  uint32_t sub_length = sub->length(sub_shape);
 
   if (start_index + pattern_length > sub_length) {
     start_index = sub_length - pattern_length;
@@ -1413,7 +1449,7 @@
   for (int i = start_index; i >= 0; i--) {
     bool found = true;
     for (uint32_t j = 0; j < pattern_length; j++) {
-      if (sub->Get(i + j) != pat->Get(j)) {
+      if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) {
         found = false;
         break;
       }
@@ -1433,8 +1469,10 @@
   CONVERT_CHECKED(String, str2, args[1]);
 
   if (str1 == str2) return Smi::FromInt(0);  // Equal.
-  int str1_length = str1->length();
-  int str2_length = str2->length();
+  StringShape shape1(str1);
+  StringShape shape2(str2);
+  int str1_length = str1->length(shape1);
+  int str2_length = str2->length(shape2);
 
   // Decide trivial cases without flattening.
   if (str1_length == 0) {
@@ -1449,11 +1487,11 @@
   // No need to flatten if we are going to find the answer on the first
   // character.  At this point we know there is at least one character
   // in each string, due to the trivial case handling above.
-  int d = str1->Get(0) - str2->Get(0);
+  int d = str1->Get(shape1, 0) - str2->Get(shape2, 0);
   if (d != 0) return Smi::FromInt(d);
 
-  str1->TryFlatten();
-  str2->TryFlatten();
+  str1->TryFlatten(shape1);  // Shapes are no longer valid now!
+  str2->TryFlatten(shape2);
 
   static StringInputBuffer buf1;
   static StringInputBuffer buf2;
@@ -1482,10 +1520,12 @@
   int start = FastD2I(from_number);
   int end = FastD2I(to_number);
 
+  StringShape shape(value);
+
   RUNTIME_ASSERT(end >= start);
   RUNTIME_ASSERT(start >= 0);
-  RUNTIME_ASSERT(end <= value->length());
-  return value->Slice(start, end);
+  RUNTIME_ASSERT(end <= value->length(shape));
+  return value->Slice(shape, start, end);
 }
 
 
@@ -1588,9 +1628,11 @@
 // Returns a single character string where first character equals
 // string->Get(index).
 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
-  if (index < static_cast<uint32_t>(string->length())) {
-    string->TryFlatten();
-    return LookupSingleCharacterStringFromCode(string->Get(index));
+  StringShape shape(*string);
+  if (index < static_cast<uint32_t>(string->length(shape))) {
+    string->TryFlatten(shape);  // Invalidates shape!
+    return LookupSingleCharacterStringFromCode(
+        string->Get(StringShape(*string), index));
   }
   return Execution::CharAt(string, index);
 }
@@ -1775,7 +1817,7 @@
       result = SetElement(js_object, index, value);
     } else {
       Handle<String> key_string = Handle<String>::cast(key);
-      key_string->TryFlatten();
+      key_string->TryFlatten(StringShape(*key_string));
       result = SetProperty(js_object, key_string, value, attr);
     }
     if (result.is_null()) return Failure::Exception();
@@ -1866,7 +1908,8 @@
     uint32_t index;
     if (key->AsArrayIndex(&index)) {
       String* string = String::cast(args[0]);
-      if (index < static_cast<uint32_t>(string->length()))
+      StringShape shape(string);
+      if (index < static_cast<uint32_t>(string->length(shape)))
         return Heap::true_value();
     }
   }
@@ -1915,10 +1958,8 @@
     return Heap::ToBoolean(object->HasElement(index));
   }
 
-  LookupResult result;
-  object->LocalLookup(key, &result);
-  if (!result.IsProperty()) return Heap::false_value();
-  return Heap::ToBoolean(!result.IsDontEnum());
+  PropertyAttributes att = object->GetLocalPropertyAttribute(key);
+  return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
 }
 
 
@@ -2049,7 +2090,7 @@
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, subject, args[0]);
-  subject->TryFlatten();
+  subject->TryFlatten(StringShape(subject));
   return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
 }
 
@@ -2079,10 +2120,11 @@
 
   if (object->IsFailure()) return object;
   String* result = String::cast(object);
+  StringShape result_shape(result);
   for (int i = 0; i < length; i++) {
     Object* element = codes->GetElement(i);
     CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
-    result->Set(i, chr & 0xffff);
+    result->Set(result_shape, i, chr & 0xffff);
   }
   return result;
 }
@@ -2131,7 +2173,7 @@
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, source, args[0]);
 
-  source->TryFlatten();
+  source->TryFlatten(StringShape(source));
 
   int escaped_length = 0;
   int length = source->length();
@@ -2161,27 +2203,28 @@
   Object* o = Heap::AllocateRawAsciiString(escaped_length);
   if (o->IsFailure()) return o;
   String* destination = String::cast(o);
+  StringShape dshape(destination);
   int dest_position = 0;
 
   Access<StringInputBuffer> buffer(&string_input_buffer);
   buffer->Rewind();
   while (buffer->has_more()) {
-    uint16_t character = buffer->GetNext();
-    if (character >= 256) {
-      destination->Set(dest_position, '%');
-      destination->Set(dest_position+1, 'u');
-      destination->Set(dest_position+2, hex_chars[character >> 12]);
-      destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]);
-      destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]);
-      destination->Set(dest_position+5, hex_chars[character & 0xf]);
+    uint16_t chr = buffer->GetNext();
+    if (chr >= 256) {
+      destination->Set(dshape, dest_position, '%');
+      destination->Set(dshape, dest_position+1, 'u');
+      destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]);
+      destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]);
+      destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]);
+      destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]);
       dest_position += 6;
-    } else if (IsNotEscaped(character)) {
-      destination->Set(dest_position, character);
+    } else if (IsNotEscaped(chr)) {
+      destination->Set(dshape, dest_position, chr);
       dest_position++;
     } else {
-      destination->Set(dest_position, '%');
-      destination->Set(dest_position+1, hex_chars[character >> 4]);
-      destination->Set(dest_position+2, hex_chars[character & 0xf]);
+      destination->Set(dshape, dest_position, '%');
+      destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]);
+      destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]);
       dest_position += 3;
     }
   }
@@ -2209,19 +2252,27 @@
 }
 
 
-static inline int Unescape(String* source, int i, int length, int* step) {
-  uint16_t character = source->Get(i);
-  int32_t hi, lo;
+static inline int Unescape(String* source,
+                           StringShape shape,
+                           int i,
+                           int length,
+                           int* step) {
+  uint16_t character = source->Get(shape, i);
+  int32_t hi = 0;
+  int32_t lo = 0;
   if (character == '%' &&
       i <= length - 6 &&
-      source->Get(i + 1) == 'u' &&
-      (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 &&
-      (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) {
+      source->Get(shape, i + 1) == 'u' &&
+      (hi = TwoDigitHex(source->Get(shape, i + 2),
+                        source->Get(shape, i + 3))) != -1 &&
+      (lo = TwoDigitHex(source->Get(shape, i + 4),
+                        source->Get(shape, i + 5))) != -1) {
     *step = 6;
     return (hi << 8) + lo;
   } else if (character == '%' &&
       i <= length - 3 &&
-      (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) {
+      (lo = TwoDigitHex(source->Get(shape, i + 1),
+                        source->Get(shape, i + 2))) != -1) {
     *step = 3;
     return lo;
   } else {
@@ -2236,15 +2287,21 @@
   ASSERT(args.length() == 1);
   CONVERT_CHECKED(String, source, args[0]);
 
-  source->TryFlatten();
+  source->TryFlatten(StringShape(source));
+  StringShape source_shape(source);
 
   bool ascii = true;
-  int length = source->length();
+  int length = source->length(source_shape);
 
   int unescaped_length = 0;
   for (int i = 0; i < length; unescaped_length++) {
     int step;
-    if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode)
+    if (Unescape(source,
+                 source_shape,
+                 i,
+                 length,
+                 &step) >
+        String::kMaxAsciiCharCode)
       ascii = false;
     i += step;
   }
@@ -2258,11 +2315,14 @@
               Heap::AllocateRawTwoByteString(unescaped_length);
   if (o->IsFailure()) return o;
   String* destination = String::cast(o);
+  StringShape destination_shape(destination);
 
   int dest_position = 0;
   for (int i = 0; i < length; dest_position++) {
     int step;
-    destination->Set(dest_position, Unescape(source, i, length, &step));
+    destination->Set(destination_shape,
+                     dest_position,
+                     Unescape(source, source_shape, i, length, &step));
     i += step;
   }
   return destination;
@@ -2276,31 +2336,33 @@
   CONVERT_DOUBLE_CHECKED(n, args[1]);
   int radix = FastD2I(n);
 
-  s->TryFlatten();
+  s->TryFlatten(StringShape(s));
 
-  int len = s->length();
+  StringShape shape(s);
+
+  int len = s->length(shape);
   int i;
 
   // Skip leading white space.
-  for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
+  for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ;
   if (i == len) return Heap::nan_value();
 
   // Compute the sign (default to +).
   int sign = 1;
-  if (s->Get(i) == '-') {
+  if (s->Get(shape, i) == '-') {
     sign = -1;
     i++;
-  } else if (s->Get(i) == '+') {
+  } else if (s->Get(shape, i) == '+') {
     i++;
   }
 
   // Compute the radix if 0.
   if (radix == 0) {
     radix = 10;
-    if (i < len && s->Get(i) == '0') {
+    if (i < len && s->Get(shape, i) == '0') {
       radix = 8;
       if (i + 1 < len) {
-        int c = s->Get(i + 1);
+        int c = s->Get(shape, i + 1);
         if (c == 'x' || c == 'X') {
           radix = 16;
           i += 2;
@@ -2309,8 +2371,8 @@
     }
   } else if (radix == 16) {
     // Allow 0x or 0X prefix if radix is 16.
-    if (i + 1 < len && s->Get(i) == '0') {
-      int c = s->Get(i + 1);
+    if (i + 1 < len && s->Get(shape, i) == '0') {
+      int c = s->Get(shape, i + 1);
       if (c == 'x' || c == 'X') i += 2;
     }
   }
@@ -2347,12 +2409,14 @@
   NoHandleAllocation ha;
 
   CONVERT_CHECKED(String, s, args[0]);
-  int raw_string_length = s->length();
+  s->TryFlatten(StringShape(s));
+  StringShape shape(s);
+
+  int raw_string_length = s->length(shape);
   // Assume that the string is not empty; we need this assumption later
   if (raw_string_length == 0) return s;
   int length = raw_string_length;
 
-  s->TryFlatten();
 
   // We try this twice, once with the assumption that the result is
   // no longer than the input and, if that assumption breaks, again
@@ -2368,11 +2432,12 @@
   // character is also ascii.  This is currently the case, but it
   // might break in the future if we implement more context and locale
   // dependent upper/lower conversions.
-  Object* o = s->IsAsciiRepresentation()
+  Object* o = shape.IsAsciiRepresentation()
       ? Heap::AllocateRawAsciiString(length)
       : Heap::AllocateRawTwoByteString(length);
   if (o->IsFailure()) return o;
   String* result = String::cast(o);
+  StringShape result_shape(result);
   bool has_changed_character = false;
 
   // Convert all characters to upper case, assuming that they will fit
@@ -2389,12 +2454,12 @@
     int char_length = mapping->get(current, next, chars);
     if (char_length == 0) {
       // The case conversion of this character is the character itself.
-      result->Set(i, current);
+      result->Set(result_shape, i, current);
       i++;
     } else if (char_length == 1) {
       // Common case: converting the letter resulted in one character.
       ASSERT(static_cast<uc32>(chars[0]) != current);
-      result->Set(i, chars[0]);
+      result->Set(result_shape, i, chars[0]);
       has_changed_character = true;
       i++;
     } else if (length == raw_string_length) {
@@ -2429,7 +2494,7 @@
       goto try_convert;
     } else {
       for (int j = 0; j < char_length; j++) {
-        result->Set(i, chars[j]);
+        result->Set(result_shape, i, chars[j]);
         i++;
       }
       has_changed_character = true;
@@ -2458,22 +2523,6 @@
 }
 
 
-static Object* Runtime_ConsStringFst(Arguments args) {
-  NoHandleAllocation ha;
-
-  CONVERT_CHECKED(ConsString, str, args[0]);
-  return str->first();
-}
-
-
-static Object* Runtime_ConsStringSnd(Arguments args) {
-  NoHandleAllocation ha;
-
-  CONVERT_CHECKED(ConsString, str, args[0]);
-  return str->second();
-}
-
-
 static Object* Runtime_NumberToString(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
@@ -2538,6 +2587,26 @@
 }
 
 
+// Converts a Number to a Smi, if possible. Returns NaN if the number is not
+// a small integer.
+static Object* Runtime_NumberToSmi(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  Object* obj = args[0];
+  if (obj->IsSmi()) {
+    return obj;
+  }
+  if (obj->IsHeapNumber()) {
+    double value = HeapNumber::cast(obj)->value();
+    int int_value = FastD2I(value);
+    if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
+      return Smi::FromInt(int_value);
+    }
+  }
+  return Heap::nan_value();
+}
+
 static Object* Runtime_NumberAdd(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 2);
@@ -2613,8 +2682,10 @@
 
   CONVERT_CHECKED(String, str1, args[0]);
   CONVERT_CHECKED(String, str2, args[1]);
-  int len1 = str1->length();
-  int len2 = str2->length();
+  StringShape shape1(str1);
+  StringShape shape2(str2);
+  int len1 = str1->length(shape1);
+  int len2 = str2->length(shape2);
   if (len1 == 0) return str2;
   if (len2 == 0) return str1;
   int length_sum = len1 + len2;
@@ -2624,12 +2695,13 @@
     Top::context()->mark_out_of_memory();
     return Failure::OutOfMemoryException();
   }
-  return Heap::AllocateConsString(str1, str2);
+  return Heap::AllocateConsString(str1, shape1, str2, shape2);
 }
 
 
 template<typename sinkchar>
 static inline void StringBuilderConcatHelper(String* special,
+                                             StringShape special_shape,
                                              sinkchar* sink,
                                              FixedArray* fixed_array,
                                              int array_length) {
@@ -2640,12 +2712,17 @@
       int len = Smi::cast(element)->value();
       int pos = len >> 11;
       len &= 0x7ff;
-      String::WriteToFlat(special, sink + position, pos, pos + len);
+      String::WriteToFlat(special,
+                          special_shape,
+                          sink + position,
+                          pos,
+                          pos + len);
       position += len;
     } else {
       String* string = String::cast(element);
-      int element_length = string->length();
-      String::WriteToFlat(string, sink + position, 0, element_length);
+      StringShape shape(string);
+      int element_length = string->length(shape);
+      String::WriteToFlat(string, shape, sink + position, 0, element_length);
       position += element_length;
     }
   }
@@ -2657,7 +2734,8 @@
   ASSERT(args.length() == 2);
   CONVERT_CHECKED(JSArray, array, args[0]);
   CONVERT_CHECKED(String, special, args[1]);
-  int special_length = special->length();
+  StringShape special_shape(special);
+  int special_length = special->length(special_shape);
   Object* smi_array_length = array->length();
   if (!smi_array_length->IsSmi()) {
     Top::context()->mark_out_of_memory();
@@ -2679,7 +2757,7 @@
     if (first->IsString()) return first;
   }
 
-  bool ascii = special->IsAsciiRepresentation();
+  bool ascii = special_shape.IsAsciiRepresentation();
   int position = 0;
   for (int i = 0; i < array_length; i++) {
     Object* elt = fixed_array->get(i);
@@ -2693,13 +2771,14 @@
       position += len;
     } else if (elt->IsString()) {
       String* element = String::cast(elt);
-      int element_length = element->length();
+      StringShape element_shape(element);
+      int element_length = element->length(element_shape);
       if (!Smi::IsValid(element_length + position)) {
         Top::context()->mark_out_of_memory();
         return Failure::OutOfMemoryException();
       }
       position += element_length;
-      if (ascii && !element->IsAsciiRepresentation()) {
+      if (ascii && !element_shape.IsAsciiRepresentation()) {
         ascii = false;
       }
     } else {
@@ -2715,6 +2794,7 @@
     if (object->IsFailure()) return object;
     SeqAsciiString* answer = SeqAsciiString::cast(object);
     StringBuilderConcatHelper(special,
+                              special_shape,
                               answer->GetChars(),
                               fixed_array,
                               array_length);
@@ -2724,6 +2804,7 @@
     if (object->IsFailure()) return object;
     SeqTwoByteString* answer = SeqTwoByteString::cast(object);
     StringBuilderConcatHelper(special,
+                              special_shape,
                               answer->GetChars(),
                               fixed_array,
                               array_length);
@@ -2918,21 +2999,24 @@
   CONVERT_CHECKED(String, x, args[0]);
   CONVERT_CHECKED(String, y, args[1]);
 
+  StringShape x_shape(x);
+  StringShape y_shape(y);
+
   // A few fast case tests before we flatten.
   if (x == y) return Smi::FromInt(EQUAL);
-  if (y->length() == 0) {
-    if (x->length() == 0) return Smi::FromInt(EQUAL);
+  if (y->length(y_shape) == 0) {
+    if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL);
     return Smi::FromInt(GREATER);
-  } else if (x->length() == 0) {
+  } else if (x->length(x_shape) == 0) {
     return Smi::FromInt(LESS);
   }
 
-  int d = x->Get(0) - y->Get(0);
+  int d = x->Get(x_shape, 0) - y->Get(y_shape, 0);
   if (d < 0) return Smi::FromInt(LESS);
   else if (d > 0) return Smi::FromInt(GREATER);
 
-  x->TryFlatten();
-  y->TryFlatten();
+  x->TryFlatten(x_shape);  // Shapes are no longer valid!
+  y->TryFlatten(y_shape);
 
   static StringInputBuffer bufx;
   static StringInputBuffer bufy;
diff --git a/src/runtime.h b/src/runtime.h
index 25931d9..36a7180 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -66,10 +66,6 @@
   F(PushIfAbsent, 2) \
   F(ArrayConcat, 1) \
   \
-  /* ConsStrings */ \
-  F(ConsStringFst, 1) \
-  F(ConsStringSnd, 1) \
-  \
   /* Conversions */ \
   F(ToBool, 1) \
   F(Typeof, 1) \
@@ -88,6 +84,7 @@
   F(NumberToInteger, 1) \
   F(NumberToJSUint32, 1) \
   F(NumberToJSInt32, 1) \
+  F(NumberToSmi, 1) \
   \
   /* Arithmetic operations */ \
   F(NumberAdd, 2) \
@@ -179,6 +176,8 @@
   F(CreateApiFunction, 1) \
   F(IsTemplate, 1) \
   F(GetTemplateField, 2) \
+  F(DisableAccessChecks, 1) \
+  F(EnableAccessChecks, 1) \
   \
   /* Dates */ \
   F(DateCurrentTime, 0) \
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index 5516353..9996eeb 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -26,6 +26,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "v8.h"
+#include "accessors.h"
 #include "top.h"
 
 #include "cctest.h"
@@ -87,12 +88,13 @@
   return Smi::FromInt(42);
 }
 
+
 static Handle<Object> Test() {
   CALL_HEAP_FUNCTION(AllocateAfterFailures(), Object);
 }
 
 
-TEST(Stress) {
+TEST(StressHandles) {
   v8::Persistent<v8::Context> env = v8::Context::New();
   v8::HandleScope scope;
   env->Enter();
@@ -100,3 +102,45 @@
   CHECK(o->IsSmi() && Smi::cast(*o)->value() == 42);
   env->Exit();
 }
+
+
+static Object* TestAccessorGet(Object* object, void*) {
+  return AllocateAfterFailures();
+}
+
+
+const AccessorDescriptor kDescriptor = {
+  TestAccessorGet,
+  0,
+  0
+};
+
+
+TEST(StressJS) {
+  v8::Persistent<v8::Context> env = v8::Context::New();
+  v8::HandleScope scope;
+  env->Enter();
+  Handle<JSFunction> function =
+      Factory::NewFunction(Factory::function_symbol(), Factory::null_value());
+  // Force the creation of an initial map and set the code to
+  // something empty.
+  Factory::NewJSObject(function);
+  function->set_code(Builtins::builtin(Builtins::EmptyFunction));
+  // Patch the map to have an accessor for "get".
+  Handle<Map> map(function->initial_map());
+  Handle<DescriptorArray> instance_descriptors(map->instance_descriptors());
+  Handle<Proxy> proxy = Factory::NewProxy(&kDescriptor);
+  instance_descriptors = Factory::CopyAppendProxyDescriptor(
+      instance_descriptors,
+      Factory::NewStringFromAscii(Vector<const char>("get", 3)),
+      proxy,
+      static_cast<PropertyAttributes>(0));
+  map->set_instance_descriptors(*instance_descriptors);
+  // Add the Foo constructor the global object.
+  env->Global()->Set(v8::String::New("Foo"), v8::Utils::ToLocal(function));
+  // Call the accessor through JavaScript.
+  v8::Handle<v8::Value> result =
+      v8::Script::Compile(v8::String::New("(new Foo).get"))->Run();
+  CHECK_EQ(42, result->Int32Value());
+  env->Exit();
+}
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 0b4f6e5..0e8a508 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -1027,6 +1027,15 @@
 }
 
 
+THREADED_TEST(UndefinedIsNotEnumerable) {
+  v8::HandleScope scope;
+  LocalContext env;
+  v8::Handle<Value> result = Script::Compile(v8_str(
+      "this.propertyIsEnumerable(undefined)"))->Run();
+  CHECK(result->IsFalse());
+}
+
+
 v8::Handle<Script> call_recursively_script;
 static const int kTargetRecursionDepth = 300;  // near maximum
 
@@ -3186,6 +3195,41 @@
 }
 
 
+THREADED_TEST(CrossDomainIsPropertyEnumerable) {
+  v8::HandleScope handle_scope;
+  LocalContext env1;
+  v8::Persistent<Context> env2 = Context::New();
+
+  Local<Value> foo = v8_str("foo");
+  Local<Value> bar = v8_str("bar");
+
+  // Set to the same domain.
+  env1->SetSecurityToken(foo);
+  env2->SetSecurityToken(foo);
+
+  env1->Global()->Set(v8_str("prop"), v8_num(3));
+  env2->Global()->Set(v8_str("env1"), env1->Global());
+
+  // env1.prop is enumerable in env2.
+  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
+  {
+    Context::Scope scope_env2(env2);
+    Local<Value> result = Script::Compile(test)->Run();
+    CHECK(result->IsTrue());
+  }
+
+  // Change env2 to a different domain and test again.
+  env2->SetSecurityToken(bar);
+  {
+    Context::Scope scope_env2(env2);
+    Local<Value> result = Script::Compile(test)->Run();
+    CHECK(result->IsFalse());
+  }
+
+  env2.Dispose();
+}
+
+
 THREADED_TEST(CrossDomainForIn) {
   v8::HandleScope handle_scope;
   LocalContext env1;
@@ -3342,7 +3386,7 @@
       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
 
   // Add an accessor that is not accessible by cross-domain JS code.
-  global_template->SetAccessor(v8_str("blocked_access_prop"),
+  global_template->SetAccessor(v8_str("blocked_prop"),
                                UnreachableGetter, UnreachableSetter,
                                v8::Handle<Value>(),
                                v8::DEFAULT);
@@ -3368,6 +3412,9 @@
   value = v8_compile("other.blocked_prop")->Run();
   CHECK(value->IsUndefined());
 
+  value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
+  CHECK(value->IsFalse());
+
   // Access accessible property
   value = v8_compile("other.accessible_prop = 3")->Run();
   CHECK(value->IsNumber());
@@ -3377,6 +3424,21 @@
   CHECK(value->IsNumber());
   CHECK_EQ(3, value->Int32Value());
 
+  value =
+    v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
+  CHECK(value->IsTrue());
+
+  // Enumeration doesn't enumerate accessors from inaccessible objects in
+  // the prototype chain even if the accessors are in themselves accessible.
+  Local<Value> result =
+      CompileRun("(function(){var obj = {'__proto__':other};"
+                 "for (var p in obj)"
+                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
+                 "     return false;"
+                 "   }"
+                 "return true;})()");
+  CHECK(result->IsTrue());
+
   context1->Exit();
   context0->Exit();
   context1.Dispose();
@@ -5075,3 +5137,80 @@
   const char* elmv3[] = {"w", "z", "x", "y"};
   CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
 }
+
+
+static v8::Handle<Value> AccessorProhibitsOverwritingGetter(
+    Local<String> name,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  return v8::True();
+}
+
+
+THREADED_TEST(AccessorProhibitsOverwriting) {
+  v8::HandleScope scope;
+  LocalContext context;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetAccessor(v8_str("x"),
+                     AccessorProhibitsOverwritingGetter,
+                     0,
+                     v8::Handle<Value>(),
+                     v8::PROHIBITS_OVERWRITING,
+                     v8::ReadOnly);
+  Local<v8::Object> instance = templ->NewInstance();
+  context->Global()->Set(v8_str("obj"), instance);
+  Local<Value> value = CompileRun(
+      "obj.__defineGetter__('x', function() { return false; });"
+      "obj.x");
+  CHECK(value->BooleanValue());
+  value = CompileRun(
+      "var setter_called = false;"
+      "obj.__defineSetter__('x', function() { setter_called = true; });"
+      "obj.x = 42;"
+      "setter_called");
+  CHECK(!value->BooleanValue());
+  value = CompileRun(
+      "obj2 = {};"
+      "obj2.__proto__ = obj;"
+      "obj2.__defineGetter__('x', function() { return false; });"
+      "obj2.x");
+  CHECK(value->BooleanValue());
+  value = CompileRun(
+      "var setter_called = false;"
+      "obj2 = {};"
+      "obj2.__proto__ = obj;"
+      "obj2.__defineSetter__('x', function() { setter_called = true; });"
+      "obj2.x = 42;"
+      "setter_called");
+  CHECK(!value->BooleanValue());
+}
+
+
+static bool NamedSetAccessBlocker(Local<v8::Object> obj,
+                                  Local<Value> name,
+                                  v8::AccessType type,
+                                  Local<Value> data) {
+  return type != v8::ACCESS_SET;
+}
+
+
+static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
+                                    uint32_t key,
+                                    v8::AccessType type,
+                                    Local<Value> data) {
+  return type != v8::ACCESS_SET;
+}
+
+
+THREADED_TEST(DisableAccessChecksWhileConfiguring) {
+  v8::HandleScope scope;
+  LocalContext context;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
+                                 IndexedSetAccessBlocker);
+  templ->Set(v8_str("x"), v8::True());
+  Local<v8::Object> instance = templ->NewInstance();
+  context->Global()->Set(v8_str("obj"), instance);
+  Local<Value> value = CompileRun("obj.x");
+  CHECK(value->BooleanValue());
+}
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 0a4f90f..4ac1ae4 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -248,9 +248,10 @@
 
 static void VerifyStringAllocation(const char* string) {
   String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string)));
-  CHECK_EQ(static_cast<int>(strlen(string)), s->length());
-  for (int index = 0; index < s->length(); index++) {
-    CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));  }
+  StringShape shape(s);
+  CHECK_EQ(static_cast<int>(strlen(string)), s->length(shape));
+  for (int index = 0; index < s->length(shape); index++) {
+    CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(shape, index));  }
 }
 
 
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index 4484dd5..ec080e2 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -62,7 +62,8 @@
         building_blocks[i] =
             Factory::NewStringFromTwoByte(Vector<const uc16>(buf, len));
         for (int j = 0; j < len; j++) {
-          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
+          StringShape shape(*building_blocks[i]);
+          CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
         }
         break;
       }
@@ -74,7 +75,8 @@
         building_blocks[i] =
             Factory::NewStringFromAscii(Vector<const char>(buf, len));
         for (int j = 0; j < len; j++) {
-          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
+          StringShape shape(*building_blocks[i]);
+          CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
         }
         break;
       }
@@ -99,7 +101,8 @@
         Resource* resource = new Resource(Vector<const uc16>(buf, len));
         building_blocks[i] = Factory::NewExternalStringFromTwoByte(resource);
         for (int j = 0; j < len; j++) {
-          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
+          StringShape shape(*building_blocks[i]);
+          CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
         }
         break;
       }
@@ -111,7 +114,8 @@
         building_blocks[i] =
             Factory::NewStringFromAscii(Vector<const char>(buf, len));
         for (int j = 0; j < len; j++) {
-          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
+          StringShape shape(*building_blocks[i]);
+          CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
         }
         break;
       }
@@ -125,9 +129,11 @@
     int depth) {
   Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
   for (int i = 0; i < depth; i++) {
-    answer =
-        Factory::NewConsString(answer,
-                               building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]);
+    answer = Factory::NewConsString(
+        answer,
+        StringShape(*answer),
+        building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
+        StringShape(*building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]));
   }
   return answer;
 }
@@ -138,9 +144,11 @@
     int depth) {
   Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
   for (int i = depth - 1; i >= 0; i--) {
-    answer =
-        Factory::NewConsString(building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
-                               answer);
+    answer = Factory::NewConsString(
+        building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
+        StringShape(*building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]),
+        answer,
+        StringShape(*answer));
   }
   return answer;
 }
@@ -157,11 +165,19 @@
   if (to - from == 2) {
     return Factory::NewConsString(
         building_blocks[from % NUMBER_OF_BUILDING_BLOCKS],
-        building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]);
+        StringShape(*building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]),
+        building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS],
+        StringShape(*building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]));
   }
+  Handle<String> part1 =
+    ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
+  Handle<String> part2 =
+    ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
   return Factory::NewConsString(
-    ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2)),
-    ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to));
+      part1,
+      StringShape(*part1),
+      part2,
+      StringShape(*part2));
 }
 
 
@@ -199,8 +215,10 @@
     CHECK_EQ(c, buffer2.GetNext());
     i++;
   }
-  s1->Get(s1->length() - 1);
-  s2->Get(s2->length() - 1);
+  StringShape shape1(*s1);
+  StringShape shape2(*s2);
+  s1->Get(shape1, s1->length(shape1) - 1);
+  s2->Get(shape2, s2->length(shape2) - 1);
 }
 
 
@@ -233,10 +251,12 @@
   printf("7\n");
   Handle<String> right_deep_slice =
       Factory::NewStringSlice(left_deep_asymmetric,
+                              StringShape(*left_deep_asymmetric),
                               left_deep_asymmetric->length() - 1050,
                               left_deep_asymmetric->length() - 50);
   Handle<String> left_deep_slice =
       Factory::NewStringSlice(right_deep_asymmetric,
+                              StringShape(*right_deep_asymmetric),
                               right_deep_asymmetric->length() - 1050,
                               right_deep_asymmetric->length() - 50);
   printf("8\n");
@@ -262,7 +282,10 @@
 static Handle<String> SliceOf(Handle<String> underlying) {
   int start = gen() % underlying->length();
   int end = start + gen() % (underlying->length() - start);
-  return Factory::NewStringSlice(underlying, start, end);
+  return Factory::NewStringSlice(underlying,
+                                 StringShape(*underlying),
+                                 start,
+                                 end);
 }
 
 
@@ -280,11 +303,19 @@
     Handle<String> rhs = building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS];
     if (gen() % 2 == 0)
       rhs = SliceOf(rhs);
-    return Factory::NewConsString(lhs, rhs);
+    return Factory::NewConsString(lhs,
+                                  StringShape(*lhs),
+                                  rhs,
+                                  StringShape(*rhs));
   }
-  Handle<String> branch = Factory::NewConsString(
-    ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2)),
-    ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to));
+  Handle<String> part1 =
+    ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
+  Handle<String> part2 =
+    ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
+  Handle<String> branch = Factory::NewConsString(part1,
+                                                 StringShape(*part1),
+                                                 part2,
+                                                 StringShape(*part2));
   if (gen() % 2 == 0)
     return branch;
   return(SliceOf(branch));
@@ -324,9 +355,15 @@
       Factory::NewStringFromAscii(Vector<const char>(foo, DEEP_ASCII_DEPTH));
   Handle<String> foo_string = Factory::NewStringFromAscii(CStrVector("foo"));
   for (int i = 0; i < DEEP_ASCII_DEPTH; i += 10) {
-    string = Factory::NewConsString(string, foo_string);
+    string = Factory::NewConsString(string,
+                                    StringShape(*string),
+                                    foo_string,
+                                    StringShape(*foo_string));
   }
-  Handle<String> flat_string = Factory::NewConsString(string, foo_string);
+  Handle<String> flat_string = Factory::NewConsString(string,
+                                                      StringShape(*string),
+                                                      foo_string,
+                                                      StringShape(*foo_string));
   FlattenString(flat_string);
 
   for (int i = 0; i < 500; i++) {
diff --git a/test/cctest/testcfg.py b/test/cctest/testcfg.py
index 08226aa..72f7d74 100644
--- a/test/cctest/testcfg.py
+++ b/test/cctest/testcfg.py
@@ -29,7 +29,7 @@
 import os
 from os.path import join, dirname, exists
 import platform
-
+import utils
 
 DEBUG_FLAGS = ['--enable-slow-asserts', '--debug-code', '--verify-heap']
 
@@ -65,7 +65,7 @@
 
   def ListTests(self, current_path, path, mode):
     executable = join('obj', 'test', mode, 'cctest')
-    if (platform.system() == 'Windows'):
+    if utils.IsWindows():
       executable += '.exe'
     output = test.Execute([executable, '--list'], self.context)
     if output.exit_code != 0:
diff --git a/test/mjsunit/fuzz-natives.js b/test/mjsunit/fuzz-natives.js
index 315270c..d716d18 100644
--- a/test/mjsunit/fuzz-natives.js
+++ b/test/mjsunit/fuzz-natives.js
@@ -106,6 +106,14 @@
   "SetScriptBreakPoint": true,
   "ChangeBreakOnException": true,
   "PrepareStep": true,
+
+  // Too slow.
+  "DebugReferencedBy": true,
+
+  // Calling disable/enable access checks may interfere with the
+  // the rest of the tests.
+  "DisableAccessChecks": true,
+  "EnableAccessChecks": true,
   
   // These functions should not be callable as runtime functions.
   "NewContext": true,
diff --git a/test/mjsunit/regress/regress-137.js b/test/mjsunit/regress/regress-137.js
new file mode 100644
index 0000000..cc7b68c
--- /dev/null
+++ b/test/mjsunit/regress/regress-137.js
@@ -0,0 +1,46 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// See <URL:http://code.google.com/p/v8/issues/detail?id=137>
+
+(function () {
+  var strNum = 170;
+  var base = strNum / 16;
+  var rem = strNum % 16;
+  var base = base - (rem / 16);  // base is now HeapNumber with valid Smi value.
+
+  switch(base) {
+    case 10: return "A";  // Expected result.
+    case 11: return "B";
+    case 12: return "C";
+    case 13: return "D";
+    case 14: return "E";
+    case 15: return "F";  // Enough cases to trigger fast-case Smi switch.
+  };
+  fail("case 10", "Default case", "Heap number not recognized as Smi value");
+})();
+
diff --git a/test/mjsunit/switch.js b/test/mjsunit/switch.js
index ae5ce2b..821a4f3 100644
--- a/test/mjsunit/switch.js
+++ b/test/mjsunit/switch.js
@@ -224,4 +224,46 @@
 assertEquals(4032, f6(128), "largeSwitch.128");
 assertEquals(4222, f6(148), "largeSwitch.148"); 
  
- 
+
+function f7(value) {
+  switch (value) {
+  case 0: return "0";
+  case -0: return "-0";
+  case 1: case 2: case 3: case 4:  // Dummy fillers.
+  }
+  switch (value) {
+  case 0x3fffffff: return "MaxSmi";
+  case 0x3ffffffe:
+  case 0x3ffffffd:
+  case 0x3ffffffc:
+  case 0x3ffffffb:
+  case 0x3ffffffa:  // Dummy fillers
+  }
+  switch (value) {
+  case -0x40000000: return "MinSmi";
+  case -0x3fffffff:
+  case -0x3ffffffe:
+  case -0x3ffffffd:
+  case -0x3ffffffc:
+  case -0x3ffffffb:  // Dummy fillers
+  }
+  switch (value) {
+  case 10: return "A";
+  case 11:
+  case 12:
+  case 13:
+  case 14: 
+  case 15:  // Dummy fillers
+  }
+  return "default";
+}
+
+
+assertEquals("default", f7(0.1), "0-1-switch.double-0.1");
+assertEquals("0", f7(-0), "0-1-switch.double-neg0");
+assertEquals("MaxSmi", f7((1<<30)-1), "0-1-switch.maxsmi");
+assertEquals("MinSmi", f7(-(1<<30)), "0-1-switch.minsmi");
+assertEquals("default", f7(1<<30), "0-1-switch.maxsmi++");
+assertEquals("default", f7(-(1<<30)-1), "0-1-switch.minsmi--");
+assertEquals("A", f7((170/16)-(170%16/16)), "0-1-switch.heapnum");
+
diff --git a/tools/test.py b/tools/test.py
index 5b3579b..e193e27 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -370,7 +370,7 @@
     return not outcome in self.test.outcomes
 
   def HasCrashed(self):
-    if platform.system() == 'Windows':
+    if utils.IsWindows():
       return 0x80000000 & self.output.exit_code and not (0x3FFFFF00 & self.output.exit_code)
     else:
       # Timed out tests will have exit_code -signal.SIGTERM.
@@ -388,7 +388,7 @@
 
 
 def KillProcessWithID(pid):
-  if platform.system() == 'Windows':
+  if utils.IsWindows():
     os.popen('taskkill /T /F /PID %d' % pid)
   else:
     os.kill(pid, signal.SIGTERM)
@@ -414,17 +414,17 @@
   if context.verbose: print "#", " ".join(args)
   popen_args = args
   prev_error_mode = SEM_INVALID_VALUE;
-  if platform.system() == 'Windows':
+  if utils.IsWindows():
     popen_args = '"' + subprocess.list2cmdline(args) + '"'
     if context.suppress_dialogs:
       # Try to change the error mode to avoid dialogs on fatal errors.
       Win32SetErrorMode(SEM_NOGPFAULTERRORBOX)
   process = subprocess.Popen(
-    shell = (platform.system() == 'Windows'),
+    shell = utils.IsWindows(),
     args = popen_args,
     **rest
   )
-  if platform.system() == 'Windows' and context.suppress_dialogs and prev_error_mode != SEM_INVALID_VALUE:
+  if utils.IsWindows() and context.suppress_dialogs and prev_error_mode != SEM_INVALID_VALUE:
     Win32SetErrorMode(prev_error_mode)
   # Compute the end time - if the process crosses this limit we
   # consider it timed out.
@@ -600,7 +600,7 @@
 
   def GetVm(self, mode):
     name = self.vm_root + PREFIX[mode]
-    if platform.system() == 'Windows':
+    if utils.IsWindows():
       return name + '.exe'
     else:
       return name
@@ -886,7 +886,7 @@
 def ParseConditionalExpression(scan):
   left = ParseOperatorExpression(scan)
   if not left: return None
-  while scan.HasMore() and (scan.Current() == 'IF'):
+  while scan.HasMore() and (scan.Current() == 'if'):
     scan.Advance()
     right = ParseOperatorExpression(scan)
     if not right:
@@ -920,6 +920,9 @@
   if not ast:
     print "Malformed expression: '%s'" % expr
     return None
+  if scan.HasMore():
+    print "Malformed expression: '%s'" % expr
+    return None
   return ast
 
 
@@ -1238,7 +1241,7 @@
     for mode in options.mode:
       env = {
         'mode': mode,
-        'system': platform.system().lower(),
+        'system': utils.GuessOS(),
         'arch': options.arch
       }
       test_list = root.ListTests([], path, context, mode)
diff --git a/tools/utils.py b/tools/utils.py
index e10bb7b..fa402c3 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -43,6 +43,20 @@
   return list
 
   
+def GuessOS():
+  id = platform.system()
+  if id == 'Linux':
+    return 'linux'
+  elif id == 'Darwin':
+    return 'macos'
+  elif id == 'Windows' or id == 'Microsoft':
+    # On Windows Vista platform.system() can return 'Microsoft' with some
+    # versions of Python, see http://bugs.python.org/issue1082
+    return 'win32'
+  else:
+    return None
+
+
 def GuessArchitecture():
   id = platform.machine()
   if id.startswith('arm'):
@@ -51,3 +65,14 @@
     return 'ia32'
   else:
     return None
+
+
+def GuessWordsize():
+  if '64' in platform.machine():
+    return '64'
+  else:
+    return '32'
+
+
+def IsWindows():
+  return GuessOS() == 'win32'