Improved frame merge code generated by the code generator.

Optimized String.prototype.replace.

Implemented __defineGetter__ and __defineSetter__ for properties with integer keys on non-array objects.

Improved debugger and profiler support.

Fixed a number of portability issues to allow compilation for smaller ARM devices.

Exposed object cloning through the API.

Implemented hidden properties.  This is used to expose an identity hash for objects through the API.

Implemented restarting of regular expressions if their input string changes representation during preemption.

Fixed a code generator bug that could cause assignments in loops to be ignored if using continue to break out of the loop (issue 284).


git-svn-id: http://v8.googlecode.com/svn/trunk@1598 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 941b84c..762bb63 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -143,15 +143,15 @@
 
 bool Object::IsSeqAsciiString() {
   if (!IsString()) return false;
-  StringShape shape(String::cast(this));
-  return shape.IsSequential() && shape.IsAsciiRepresentation();
+  return StringShape(String::cast(this)).IsSequential() &&
+         StringShape(String::cast(this)).IsAsciiRepresentation();
 }
 
 
 bool Object::IsSeqTwoByteString() {
   if (!IsString()) return false;
-  StringShape shape(String::cast(this));
-  return shape.IsSequential() && shape.IsTwoByteRepresentation();
+  return StringShape(String::cast(this)).IsSequential() &&
+         StringShape(String::cast(this)).IsTwoByteRepresentation();
 }
 
 
@@ -163,15 +163,15 @@
 
 bool Object::IsExternalAsciiString() {
   if (!IsString()) return false;
-  StringShape shape(String::cast(this));
-  return shape.IsExternal() && shape.IsAsciiRepresentation();
+  return StringShape(String::cast(this)).IsExternal() &&
+         StringShape(String::cast(this)).IsAsciiRepresentation();
 }
 
 
 bool Object::IsExternalTwoByteString() {
   if (!IsString()) return false;
-  StringShape shape(String::cast(this));
-  return shape.IsExternal() && shape.IsTwoByteRepresentation();
+  return StringShape(String::cast(this)).IsExternal() &&
+         StringShape(String::cast(this)).IsTwoByteRepresentation();
 }
 
 
@@ -1094,6 +1094,15 @@
 }
 
 
+Object* JSObject::InObjectPropertyAt(int index) {
+  // Adjust for the number of properties stored in the object.
+  index -= map()->inobject_properties();
+  ASSERT(index < 0);
+  int offset = map()->instance_size() + (index * kPointerSize);
+  return READ_FIELD(this, offset);
+}
+
+
 Object* JSObject::InObjectPropertyAtPut(int index,
                                         Object* value,
                                         WriteBarrierMode mode) {
@@ -1243,15 +1252,13 @@
 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 (shape.IsSymbol() && nof < kMaxElementsForLinearSearch) {
+  if (StringShape(name).IsSymbol() && nof < kMaxElementsForLinearSearch) {
     return LinearSearch(name, nof);
   }
 
@@ -1327,6 +1334,13 @@
 }
 
 
+void Dictionary::set_requires_slow_elements() {
+  set(kMaxNumberKeyIndex,
+      Smi::FromInt(kRequiresSlowElementsMask),
+      SKIP_WRITE_BARRIER);
+}
+
+
 // ------------------------------------
 // Cast operations
 
@@ -1385,27 +1399,21 @@
 
 bool String::Equals(String* other) {
   if (other == this) return true;
-  StringShape this_shape(this);
-  StringShape other_shape(other);
-  if (this_shape.IsSymbol() && other_shape.IsSymbol()) return false;
-  return SlowEquals(this_shape, other, other_shape);
+  if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) {
+    return false;
+  }
+  return SlowEquals(other);
 }
 
 
-int String::length(StringShape shape) {
-  ASSERT(shape.type() == StringShape(this).type());
+int String::length() {
   uint32_t len = READ_INT_FIELD(this, kLengthOffset);
 
   ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
   ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
   ASSERT(kLongStringTag == 0);
 
-  return len >> (shape.size_tag() + kLongLengthShift);
-}
-
-
-int String::length() {
-  return length(StringShape(this));
+  return len >> (StringShape(this).size_tag() + kLongLengthShift);
 }
 
 
@@ -1414,10 +1422,9 @@
   ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
   ASSERT(kLongStringTag == 0);
 
-  StringShape shape(this);
   WRITE_INT_FIELD(this,
                   kLengthOffset,
-                  value << (shape.size_tag() + kLongLengthShift));
+                  value << (StringShape(this).size_tag() + kLongLengthShift));
 }
 
 
@@ -1431,21 +1438,19 @@
 }
 
 
-Object* String::TryFlattenIfNotFlat(StringShape shape) {
-  ASSERT(shape.type() == StringShape(this).type());
+Object* String::TryFlattenIfNotFlat() {
   // 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.
-  if (!IsFlat(shape)) {
-    return TryFlatten(shape);
+  if (!IsFlat()) {
+    return TryFlatten();
   }
   return this;
 }
 
 
-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()) {
+uint16_t String::Get(int index) {
+  ASSERT(index >= 0 && index < length());
+  switch (StringShape(this).full_representation_tag()) {
     case kSeqStringTag | kAsciiStringTag:
       return SeqAsciiString::cast(this)->SeqAsciiStringGet(index);
     case kSeqStringTag | kTwoByteStringTag:
@@ -1469,29 +1474,26 @@
 }
 
 
-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());
+void String::Set(int index, uint16_t value) {
+  ASSERT(index >= 0 && index < length());
+  ASSERT(StringShape(this).IsSequential());
 
-  return shape.IsAsciiRepresentation()
+  return StringShape(this).IsAsciiRepresentation()
       ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value)
       : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value);
 }
 
 
-bool String::IsFlat(StringShape shape) {
-  ASSERT(shape.type() == StringShape(this).type());
-  switch (shape.representation_tag()) {
+bool String::IsFlat() {
+  switch (StringShape(this).representation_tag()) {
     case kConsStringTag: {
       String* second = ConsString::cast(this)->second();
       // Only flattened strings have second part empty.
       return second->length() == 0;
     }
     case kSlicedStringTag: {
-      StringShape slice_shape = StringShape(SlicedString::cast(this)->buffer());
-      StringRepresentationTag tag = slice_shape.representation_tag();
+      StringRepresentationTag tag =
+          StringShape(SlicedString::cast(this)->buffer()).representation_tag();
       return tag == kSeqStringTag || tag == kExternalStringTag;
     }
     default:
@@ -1545,7 +1547,7 @@
 }
 
 
-int SeqTwoByteString::SeqTwoByteStringSize(StringShape shape) {
+int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
 
   ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
@@ -1554,13 +1556,13 @@
 
   // Use the map (and not 'this') to compute the size tag, since
   // TwoByteStringSize is called during GC when maps are encoded.
-  length >>= shape.size_tag() + kLongLengthShift;
+  length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
 
   return SizeFor(length);
 }
 
 
-int SeqAsciiString::SeqAsciiStringSize(StringShape shape) {
+int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
 
   ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
@@ -1569,13 +1571,18 @@
 
   // Use the map (and not 'this') to compute the size tag, since
   // AsciiStringSize is called during GC when maps are encoded.
-  length >>= shape.size_tag() + kLongLengthShift;
+  length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
 
   return SizeFor(length);
 }
 
 
 String* ConsString::first() {
+  ASSERT(String::cast(READ_FIELD(this, kSecondOffset))->length() != 0 ||
+      StringShape(
+          String::cast(
+              READ_FIELD(this, kFirstOffset))).IsAsciiRepresentation()
+          == StringShape(this).IsAsciiRepresentation());
   return String::cast(READ_FIELD(this, kFirstOffset));
 }
 
@@ -1608,6 +1615,10 @@
 
 
 String* SlicedString::buffer() {
+  ASSERT(
+      StringShape(
+          String::cast(READ_FIELD(this, kBufferOffset))).IsAsciiRepresentation()
+      == StringShape(this).IsAsciiRepresentation());
   return String::cast(READ_FIELD(this, kBufferOffset));
 }
 
@@ -2316,6 +2327,19 @@
 }
 
 
+int JSRegExp::CaptureCount() {
+  switch (TypeTag()) {
+    case ATOM:
+      return 0;
+    case IRREGEXP:
+      return Smi::cast(DataAt(kIrregexpCaptureCountIndex))->value();
+    default:
+      UNREACHABLE();
+      return -1;
+  }
+}
+
+
 JSRegExp::Flags JSRegExp::GetFlags() {
   ASSERT(this->data()->IsFixedArray());
   Object* data = this->data();