Revision: 3339
Author: [email protected]
Date: Fri Nov 20 04:14:52 2009
Log: Push version 2.0.1 to trunk.

Fixed crash bug in String.prototype.replace.

Reverted a change which caused Chromium interactive ui test failures.

http://code.google.com/p/v8/source/detail?r=3339

Added:
  /trunk/test/mjsunit/regress/regress-515.js
Modified:
  /trunk/ChangeLog
  /trunk/src/arm/codegen-arm.cc
  /trunk/src/arm/codegen-arm.h
  /trunk/src/codegen.cc
  /trunk/src/compiler.cc
  /trunk/src/heap.cc
  /trunk/src/heap.h
  /trunk/src/ia32/codegen-ia32.cc
  /trunk/src/ia32/codegen-ia32.h
  /trunk/src/macros.py
  /trunk/src/objects-inl.h
  /trunk/src/objects.cc
  /trunk/src/objects.h
  /trunk/src/runtime.cc
  /trunk/src/version.cc
  /trunk/src/x64/codegen-x64.cc
  /trunk/src/x64/codegen-x64.h

=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-515.js  Fri Nov 20 04:14:52 2009
@@ -0,0 +1,40 @@
+// Copyright 2009 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.
+
+// Regression test for http://code.google.com/p/v8/issues/detail?id=515.
+//
+// The test passes if it does not crash.
+
+var length = 2048;
+var s = "";
+for (var i = 0; i < 2048; i++) {
+  s += '.';
+}
+
+var string = s + 'x' + s + 'x' + s;
+
+string.replace(/x/g, "")
=======================================
--- /trunk/ChangeLog    Wed Nov 18 06:12:51 2009
+++ /trunk/ChangeLog    Fri Nov 20 04:14:52 2009
@@ -1,3 +1,11 @@
+2009-11-20: Version 2.0.1
+
+        Fixed crash bug in String.prototype.replace.
+
+        Reverted a change which caused Chromium interactive ui test
+        failures.
+
+
  2009-11-18: Version 2.0.0

          Added support for VFP on ARM.
=======================================
--- /trunk/src/arm/codegen-arm.cc       Wed Nov 18 06:12:51 2009
+++ /trunk/src/arm/codegen-arm.cc       Fri Nov 20 04:14:52 2009
@@ -3383,6 +3383,51 @@
    answer.Bind();
    cc_reg_ = eq;
  }
+
+
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
+  VirtualFrame::SpilledScope spilled_scope;
+  ASSERT(args->length() == 1);
+  LoadAndSpill(args->at(0));
+  frame_->EmitPop(r1);
+  __ tst(r1, Operand(kSmiTagMask));
+  false_target()->Branch(eq);
+
+  __ LoadRoot(ip, Heap::kNullValueRootIndex);
+  __ cmp(r1, ip);
+  true_target()->Branch(eq);
+
+  Register map_reg = r2;
+  __ ldr(map_reg, FieldMemOperand(r1, HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined when tested with typeof.
+  __ ldrb(r1, FieldMemOperand(map_reg, Map::kBitFieldOffset));
+  __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
+  __ cmp(r1, Operand(1 << Map::kIsUndetectable));
+  false_target()->Branch(eq);
+
+  __ ldrb(r1, FieldMemOperand(map_reg, Map::kInstanceTypeOffset));
+  __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
+  false_target()->Branch(lt);
+  __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
+  cc_reg_ = le;
+}
+
+
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (%_ClassOf(arg) === 'Function')
+  VirtualFrame::SpilledScope spilled_scope;
+  ASSERT(args->length() == 1);
+  LoadAndSpill(args->at(0));
+  frame_->EmitPop(r0);
+  __ tst(r0, Operand(kSmiTagMask));
+  false_target()->Branch(eq);
+  Register map_reg = r2;
+  __ CompareObjectType(r0, map_reg, r1, JS_FUNCTION_TYPE);
+  cc_reg_ = eq;
+}


  void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
=======================================
--- /trunk/src/arm/codegen-arm.h        Wed Nov 18 06:12:51 2009
+++ /trunk/src/arm/codegen-arm.h        Fri Nov 20 04:14:52 2009
@@ -334,6 +334,8 @@
    void GenerateIsSmi(ZoneList<Expression*>* args);
    void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
    void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsObject(ZoneList<Expression*>* args);
+  void GenerateIsFunction(ZoneList<Expression*>* args);

    // Support for construct call checks.
    void GenerateIsConstructCall(ZoneList<Expression*>* args);
=======================================
--- /trunk/src/codegen.cc       Wed Nov 18 06:12:51 2009
+++ /trunk/src/codegen.cc       Fri Nov 20 04:14:52 2009
@@ -343,7 +343,9 @@
    {&CodeGenerator::GenerateLog, "_Log"},
    {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
    {&CodeGenerator::GenerateMathSin, "_Math_sin"},
-  {&CodeGenerator::GenerateMathCos, "_Math_cos"}
+  {&CodeGenerator::GenerateMathCos, "_Math_cos"},
+  {&CodeGenerator::GenerateIsObject, "_IsObject"},
+  {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
  };


=======================================
--- /trunk/src/compiler.cc      Wed Nov 18 06:12:51 2009
+++ /trunk/src/compiler.cc      Fri Nov 20 04:14:52 2009
@@ -646,8 +646,9 @@


  void CodeGenSelector::VisitDeclaration(Declaration* decl) {
-  if (decl->fun() != NULL) {
-    ProcessExpression(decl->fun(), Expression::kValue);
+  Variable* var = decl->proxy()->var();
+  if (!var->is_global() || var->mode() == Variable::CONST) {
+    BAILOUT("Non-global declaration");
    }
  }

=======================================
--- /trunk/src/heap.cc  Wed Nov 18 06:12:51 2009
+++ /trunk/src/heap.cc  Fri Nov 20 04:14:52 2009
@@ -1760,6 +1760,41 @@
    share->set_this_property_assignments(undefined_value());
    return result;
  }
+
+
+// Returns true for a character in a range.  Both limits are inclusive.
+static inline bool Between(uint32_t character, uint32_t from, uint32_t to)  
{
+  // This makes uses of the the unsigned wraparound.
+  return character - from <= to - from;
+}
+
+
+static inline Object* MakeOrFindTwoCharacterString(uint32_t c1, uint32_t  
c2) {
+  String* symbol;
+  // Numeric strings have a different hash algorithm not known by
+  // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
+  if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
+      Heap::symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol))  
{
+    return symbol;
+  // Now we know the length is 2, we might as well make use of that fact
+  // when building the new string.
+  } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) {  // We can do this
+    ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1));  // because of  
this.
+    Object* result = Heap::AllocateRawAsciiString(2);
+    if (result->IsFailure()) return result;
+    char* dest = SeqAsciiString::cast(result)->GetChars();
+    dest[0] = c1;
+    dest[1] = c2;
+    return result;
+  } else {
+    Object* result = Heap::AllocateRawTwoByteString(2);
+    if (result->IsFailure()) return result;
+    uc16* dest = SeqTwoByteString::cast(result)->GetChars();
+    dest[0] = c1;
+    dest[1] = c2;
+    return result;
+  }
+}


  Object* Heap::AllocateConsString(String* first, String* second) {
@@ -1774,6 +1809,16 @@
    }

    int length = first_length + second_length;
+
+  // Optimization for 2-byte strings often used as keys in a decompression
+  // dictionary.  Check whether we already have the string in the symbol
+  // table to prevent creation of many unneccesary strings.
+  if (length == 2) {
+    unsigned c1 = first->Get(0);
+    unsigned c2 = second->Get(0);
+    return MakeOrFindTwoCharacterString(c1, c2);
+  }
+
    bool is_ascii = first->IsAsciiRepresentation()
        && second->IsAsciiRepresentation();

@@ -1843,6 +1888,13 @@
    if (length == 1) {
      return Heap::LookupSingleCharacterStringFromCode(
          buffer->Get(start));
+  } else if (length == 2) {
+    // Optimization for 2-byte strings often used as keys in a  
decompression
+    // dictionary.  Check whether we already have the string in the symbol
+    // table to prevent creation of many unneccesary strings.
+    unsigned c1 = buffer->Get(start);
+    unsigned c2 = buffer->Get(start + 1);
+    return MakeOrFindTwoCharacterString(c1, c2);
    }

    // Make an attempt to flatten the buffer to reduce access time.
=======================================
--- /trunk/src/heap.h   Wed Nov 18 06:12:51 2009
+++ /trunk/src/heap.h   Fri Nov 20 04:14:52 2009
@@ -631,6 +631,7 @@
    }
    static Object* LookupSymbol(String* str);
    static bool LookupSymbolIfExists(String* str, String** symbol);
+  static bool LookupTwoCharsSymbolIfExists(String* str, String** symbol);

    // Compute the matching symbol map for a string if possible.
    // NULL is returned if string is in new space or not flattened.
=======================================
--- /trunk/src/ia32/codegen-ia32.cc     Wed Nov 18 06:12:51 2009
+++ /trunk/src/ia32/codegen-ia32.cc     Fri Nov 20 04:14:52 2009
@@ -4868,6 +4868,55 @@
    temp.Unuse();
    destination()->Split(equal);
  }
+
+
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result obj = frame_->Pop();
+  obj.ToRegister();
+
+  __ test(obj.reg(), Immediate(kSmiTagMask));
+  destination()->false_target()->Branch(zero);
+  __ cmp(obj.reg(), Factory::null_value());
+  destination()->true_target()->Branch(equal);
+
+  Result map = allocator()->Allocate();
+  ASSERT(map.is_valid());
+  __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined when tested with typeof.
+  __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset));
+  __ test(map.reg(), Immediate(1 << Map::kIsUndetectable));
+  destination()->false_target()->Branch(not_zero);
+  __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
+  __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset));
+  __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE);
+  destination()->false_target()->Branch(less);
+  __ cmp(map.reg(), LAST_JS_OBJECT_TYPE);
+  obj.Unuse();
+  map.Unuse();
+  destination()->Split(less_equal);
+}
+
+
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (%_ClassOf(arg) === 'Function')
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result obj = frame_->Pop();
+  obj.ToRegister();
+  __ test(obj.reg(), Immediate(kSmiTagMask));
+  destination()->false_target()->Branch(zero);
+  Result temp = allocator()->Allocate();
+  ASSERT(temp.is_valid());
+  __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, temp.reg());
+  obj.Unuse();
+  temp.Unuse();
+  destination()->Split(equal);
+}


  void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
=======================================
--- /trunk/src/ia32/codegen-ia32.h      Wed Nov 18 06:12:51 2009
+++ /trunk/src/ia32/codegen-ia32.h      Fri Nov 20 04:14:52 2009
@@ -512,6 +512,8 @@
    void GenerateIsSmi(ZoneList<Expression*>* args);
    void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
    void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsObject(ZoneList<Expression*>* args);
+  void GenerateIsFunction(ZoneList<Expression*>* args);

    // Support for construct call checks.
    void GenerateIsConstructCall(ZoneList<Expression*>* args);
=======================================
--- /trunk/src/macros.py        Wed Nov 18 06:12:51 2009
+++ /trunk/src/macros.py        Fri Nov 20 04:14:52 2009
@@ -79,11 +79,10 @@
  macro IS_UNDEFINED(arg)         = (typeof(arg) === 'undefined');
  macro IS_NUMBER(arg)            = (typeof(arg) === 'number');
  macro IS_STRING(arg)            = (typeof(arg) === 'string');
-macro IS_OBJECT(arg)            = (typeof(arg) === 'object' | 
| %_ClassOf(arg) == 'RegExp');
  macro IS_BOOLEAN(arg)           = (typeof(arg) === 'boolean');
+macro IS_OBJECT(arg)            = (%_IsObject(arg));
  macro IS_ARRAY(arg)             = (%_IsArray(arg));
-# IS_FUNCTION uses %_ClassOf rather than typeof so as to exclude regexps.
-macro IS_FUNCTION(arg)          = (%_ClassOf(arg) === 'Function');
+macro IS_FUNCTION(arg)          = (%_IsFunction(arg));
  macro IS_REGEXP(arg)            = (%_ClassOf(arg) === 'RegExp');
  macro IS_DATE(arg)              = (%_ClassOf(arg) === 'Date');
  macro IS_NUMBER_WRAPPER(arg)    = (%_ClassOf(arg) === 'Number');
=======================================
--- /trunk/src/objects-inl.h    Wed Nov 18 06:12:51 2009
+++ /trunk/src/objects-inl.h    Fri Nov 20 04:14:52 2009
@@ -3103,8 +3103,19 @@

  void JSArray::EnsureSize(int required_size) {
    ASSERT(HasFastElements());
-  if (elements()->length() >= required_size) return;
-  Expand(required_size);
+  Array* elts = elements();
+  const int kArraySizeThatFitsComfortablyInNewSpace = 128;
+  if (elts->length() < required_size) {
+    // Doubling in size would be overkill, but leave some slack to avoid
+    // constantly growing.
+    Expand(required_size + (required_size >> 3));
+    // It's a performance benefit to keep a frequently used array in  
new-space.
+  } else if (!Heap::new_space()->Contains(elts) &&
+             required_size < kArraySizeThatFitsComfortablyInNewSpace) {
+    // Expand will allocate a new backing store in new space even if the  
size
+    // we asked for isn't larger than what we had before.
+    Expand(required_size);
+  }
  }


=======================================
--- /trunk/src/objects.cc       Wed Nov 18 06:12:51 2009
+++ /trunk/src/objects.cc       Fri Nov 20 04:14:52 2009
@@ -1463,8 +1463,8 @@


  Object* JSObject::ReplaceSlowProperty(String* name,
-                                       Object* value,
-                                       PropertyAttributes attributes) {
+                                      Object* value,
+                                      PropertyAttributes attributes) {
    StringDictionary* dictionary = property_dictionary();
    int old_index = dictionary->FindEntry(name);
    int new_enumeration_index = 0;  // 0 means "Use the next available  
index."
@@ -1477,6 +1477,7 @@
    PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
    return SetNormalizedProperty(name, value, new_details);
  }
+

  Object* JSObject::ConvertDescriptorToFieldAndMapTransition(
      String* name,
@@ -1868,6 +1869,14 @@
    // Make sure that the top context does not change when doing callbacks or
    // interceptor calls.
    AssertNoContextChange ncc;
+
+  // Optimization for 2-byte strings often used as keys in a decompression
+  // dictionary.  We make these short keys into symbols to avoid constantly
+  // reallocating them.
+  if (!name->IsSymbol() && name->length() <= 2) {
+    Object* symbol_version = Heap::LookupSymbol(name);
+    if (!symbol_version->IsFailure()) name = String::cast(symbol_version);
+  }

    // Check access rights if needed.
    if (IsAccessCheckNeeded()
@@ -5240,9 +5249,7 @@
    Handle<JSArray> self(this);
    Handle<FixedArray> old_backing(FixedArray::cast(elements()));
    int old_size = old_backing->length();
-  // Doubling in size would be overkill, but leave some slack to avoid
-  // constantly growing.
-  int new_size = required_size + (required_size >> 3);
+  int new_size = required_size > old_size ? required_size : old_size;
    Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size);
    // Can't use this any more now because we may have had a GC!
    for (int i = 0; i < old_size; i++) new_backing->set(i,  
old_backing->get(i));
@@ -7325,6 +7332,67 @@
    SymbolKey key(string);
    return LookupKey(&key, s);
  }
+
+
+// This class is used for looking up two character strings in the symbol  
table.
+// If we don't have a hit we don't want to waste much time so we unroll the
+// string hash calculation loop here for speed.  Doesn't work if the two
+// characters form a decimal integer, since such strings have a different  
hash
+// algorithm.
+class TwoCharHashTableKey : public HashTableKey {
+ public:
+  TwoCharHashTableKey(uint32_t c1, uint32_t c2)
+    : c1_(c1), c2_(c2) {
+    // Char 1.
+    uint32_t hash = c1 + (c1 << 10);
+    hash ^= hash >> 6;
+    // Char 2.
+    hash += c2;
+    hash += hash << 10;
+    hash ^= hash >> 6;
+    // GetHash.
+    hash += hash << 3;
+    hash ^= hash >> 11;
+    hash += hash << 15;
+    if (hash == 0) hash = 27;
+#ifdef DEBUG
+    StringHasher hasher(2);
+    hasher.AddCharacter(c1);
+    hasher.AddCharacter(c2);
+    // If this assert fails then we failed to reproduce the two-character
+    // version of the string hashing algorithm above.  One reason could be
+    // that we were passed two digits as characters, since the hash
+    // algorithm is different in that case.
+    ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
+#endif
+    hash_ = hash;
+  }
+
+  bool IsMatch(Object* o) {
+    if (!o->IsString()) return false;
+    String* other = String::cast(o);
+    if (other->length() != 2) return false;
+    if (other->Get(0) != c1_) return false;
+    return other->Get(1) == c2_;
+  }
+
+  uint32_t Hash() { return hash_; }
+  uint32_t HashForObject(Object* key) {
+    if (!key->IsString()) return 0;
+    return String::cast(key)->Hash();
+  }
+
+  Object* AsObject() {
+    // The TwoCharHashTableKey is only used for looking in the symbol
+    // table, not for adding to it.
+    UNREACHABLE();
+    return NULL;
+  }
+ private:
+  uint32_t c1_;
+  uint32_t c2_;
+  uint32_t hash_;
+};


  bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
@@ -7339,6 +7407,22 @@
      return true;
    }
  }
+
+
+bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
+                                               uint32_t c2,
+                                               String** symbol) {
+  TwoCharHashTableKey key(c1, c2);
+  int entry = FindEntry(&key);
+  if (entry == kNotFound) {
+    return false;
+  } else {
+    String* result = String::cast(KeyAt(entry));
+    ASSERT(StringShape(result).IsSymbol());
+    *symbol = result;
+    return true;
+  }
+}


  Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
=======================================
--- /trunk/src/objects.h        Wed Nov 18 06:12:51 2009
+++ /trunk/src/objects.h        Fri Nov 20 04:14:52 2009
@@ -2188,6 +2188,7 @@
    // true if it is found, assigning the symbol to the given output
    // parameter.
    bool LookupSymbolIfExists(String* str, String** symbol);
+  bool LookupTwoCharsSymbolIfExists(uint32_t c1, uint32_t c2, String**  
symbol);

    // Casting.
    static inline SymbolTable* cast(Object* obj);
@@ -3846,6 +3847,7 @@
    bool is_array_index_;
    bool is_first_char_;
    bool is_valid_;
+  friend class TwoCharHashTableKey;
  };


=======================================
--- /trunk/src/runtime.cc       Wed Nov 18 06:12:51 2009
+++ /trunk/src/runtime.cc       Fri Nov 20 04:14:52 2009
@@ -1750,10 +1750,10 @@
    // Index of end of last match.
    int prev = 0;

-  // Number of parts added by compiled replacement plus preceeding string
-  // and possibly suffix after last match. It is possible for compiled
-  // replacements to use two elements when encoded as two smis.
-  const int parts_added_per_loop = compiled_replacement.parts() * 2 + 2;
+  // Number of parts added by compiled replacement plus preceeding
+  // string and possibly suffix after last match.  It is possible for
+  // all components to use two elements when encoded as two smis.
+  const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
    bool matched = true;
    do {
      ASSERT(last_match_info_handle->HasFastElements());
@@ -2356,12 +2356,20 @@
    ASSERT(args.length() == 3);

    CONVERT_CHECKED(String, value, args[0]);
-  CONVERT_DOUBLE_CHECKED(from_number, args[1]);
-  CONVERT_DOUBLE_CHECKED(to_number, args[2]);
-
-  int start = FastD2I(from_number);
-  int end = FastD2I(to_number);
-
+  Object* from = args[1];
+  Object* to = args[2];
+  int start, end;
+  // We have a fast integer-only case here to avoid a conversion to double  
in
+  // the common case where from and to are Smis.
+  if (from->IsSmi() && to->IsSmi()) {
+    start = Smi::cast(from)->value();
+    end = Smi::cast(to)->value();
+  } else {
+    CONVERT_DOUBLE_CHECKED(from_number, from);
+    CONVERT_DOUBLE_CHECKED(to_number, to);
+    start = FastD2I(from_number);
+    end = FastD2I(to_number);
+  }
    RUNTIME_ASSERT(end >= start);
    RUNTIME_ASSERT(start >= 0);
    RUNTIME_ASSERT(end <= value->length());
=======================================
--- /trunk/src/version.cc       Wed Nov 18 06:12:51 2009
+++ /trunk/src/version.cc       Fri Nov 20 04:14:52 2009
@@ -34,7 +34,7 @@
  // cannot be changed without changing the SCons build script.
  #define MAJOR_VERSION     2
  #define MINOR_VERSION     0
-#define BUILD_NUMBER      0
+#define BUILD_NUMBER      1
  #define PATCH_LEVEL       0
  #define CANDIDATE_VERSION false

=======================================
--- /trunk/src/x64/codegen-x64.cc       Wed Nov 18 06:12:51 2009
+++ /trunk/src/x64/codegen-x64.cc       Fri Nov 20 04:14:52 2009
@@ -3614,6 +3614,48 @@
    value.Unuse();
    destination()->Split(equal);
  }
+
+
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result obj = frame_->Pop();
+  obj.ToRegister();
+  Condition is_smi = masm_->CheckSmi(obj.reg());
+  destination()->false_target()->Branch(is_smi);
+
+  __ Move(kScratchRegister, Factory::null_value());
+  __ cmpq(obj.reg(), kScratchRegister);
+  destination()->true_target()->Branch(equal);
+
+  __ movq(kScratchRegister, FieldOperand(obj.reg(),  
HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined when tested with typeof.
+  __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
+          Immediate(1 << Map::kIsUndetectable));
+  destination()->false_target()->Branch(not_zero);
+  __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE);
+  destination()->false_target()->Branch(less);
+  __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
+  obj.Unuse();
+  destination()->Split(less_equal);
+}
+
+
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (%_ClassOf(arg) === 'Function')
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result obj = frame_->Pop();
+  obj.ToRegister();
+  Condition is_smi = masm_->CheckSmi(obj.reg());
+  destination()->false_target()->Branch(is_smi);
+  __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, kScratchRegister);
+  obj.Unuse();
+  destination()->Split(equal);
+}


  void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
=======================================
--- /trunk/src/x64/codegen-x64.h        Wed Nov 18 06:12:51 2009
+++ /trunk/src/x64/codegen-x64.h        Fri Nov 20 04:14:52 2009
@@ -510,6 +510,8 @@
    void GenerateIsSmi(ZoneList<Expression*>* args);
    void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
    void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsObject(ZoneList<Expression*>* args);
+  void GenerateIsFunction(ZoneList<Expression*>* args);

    // Support for construct call checks.
    void GenerateIsConstructCall(ZoneList<Expression*>* args);

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to