Revision: 17635
Author:   [email protected]
Date:     Tue Nov 12 10:21:08 2013 UTC
Log:      Add initial hydrogenized NewStringAddStub.

The new stub is enabled via the --new-string-add flag, which is
disabled by default. For now, it's only a stripped down version
of the native StringAddStub, it's still work-in-progress.

BUG=v8:2990
[email protected]

Review URL: https://codereview.chromium.org/61893009
http://code.google.com/p/v8/source/detail?r=17635

Added:
 /branches/bleeding_edge/test/mjsunit/new-string-add.js
Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/arm/lithium-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/code-stubs-hydrogen.cc
 /branches/bleeding_edge/src/code-stubs.cc
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/flag-definitions.h
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.cc
 /branches/bleeding_edge/src/isolate.cc
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.cc

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/new-string-add.js Tue Nov 12 10:21:08 2013 UTC
@@ -0,0 +1,197 @@
+// Copyright 2013 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.
+
+// Flags: --new-string-add
+
+assertEquals("ab", "a" + "b", "ll");
+
+assertEquals("12", "1" + "2", "dd");
+assertEquals("123", "1" + "2" + "3", "ddd");
+assertEquals("123", 1 + "2" + "3", "ndd");
+assertEquals("123", "1" + 2 + "3", "dnd");
+assertEquals("123", "1" + "2" + 3, "ddn");
+
+assertEquals("123", "1" + 2 + 3, "dnn");
+assertEquals("123", 1 + "2" + 3, "ndn");
+assertEquals("33", 1 + 2 + "3", "nnd");
+
+var x = "1";
+assertEquals("12", x + 2, "vn");
+assertEquals("12", x + "2", "vd");
+assertEquals("21", 2 + x, "nv");
+assertEquals("21", "2" + x, "dv");
+
+var y = "2";
+assertEquals("12", x + y, "vdvd");
+
+x = 1;
+assertEquals("12", x + y, "vnvd");
+
+y = 2;
+assertEquals(3, x + y, "vnvn");
+
+x = "1";
+assertEquals("12", x + y, "vdvn");
+
+y = "2";
+assertEquals("12", x + y, "vdvd2");
+
+(function(x, y) {
+  var z = "3";
+  var w = "4";
+
+  assertEquals("11", x + x, "xx");
+  assertEquals("12", x + y, "xy");
+  assertEquals("13", x + z, "xz");
+  assertEquals("14", x + w, "xw");
+
+  assertEquals("21", y + x, "yx");
+  assertEquals("22", y + y, "yy");
+  assertEquals("23", y + z, "yz");
+  assertEquals("24", y + w, "yw");
+
+  assertEquals("31", z + x, "zx");
+  assertEquals("32", z + y, "zy");
+  assertEquals("33", z + z, "zz");
+  assertEquals("34", z + w, "zw");
+
+  assertEquals("41", w + x, "wx");
+  assertEquals("42", w + y, "wy");
+  assertEquals("43", w + z, "wz");
+  assertEquals("44", w + w, "ww");
+
+  (function(){x = 1; z = 3;})();
+
+  assertEquals(2, x + x, "x'x");
+  assertEquals("12", x + y, "x'y");
+  assertEquals(4, x + z, "x'z'");
+  assertEquals("14", x + w, "x'w");
+
+  assertEquals("21", y + x, "yx'");
+  assertEquals("22", y + y, "yy");
+  assertEquals("23", y + z, "yz'");
+  assertEquals("24", y + w, "yw");
+
+  assertEquals(4, z + x, "z'x'");
+  assertEquals("32", z + y, "z'y");
+  assertEquals(6, z + z, "z'z'");
+  assertEquals("34", z + w, "z'w");
+
+  assertEquals("41", w + x, "wx'");
+  assertEquals("42", w + y, "wy");
+  assertEquals("43", w + z, "wz'");
+  assertEquals("44", w + w, "ww");
+})("1", "2");
+
+assertEquals("142", "1" + new Number(42), "sN");
+assertEquals("421", new Number(42) + "1", "Ns");
+assertEquals(84, new Number(42) + new Number(42), "NN");
+
+assertEquals("142", "1" + new String("42"), "sS");
+assertEquals("421", new String("42") + "1", "Ss");
+assertEquals("142", "1" + new String("42"), "sS");
+assertEquals("4242", new String("42") + new String("42"), "SS");
+
+assertEquals("1true", "1" + true, "sb");
+assertEquals("true1", true + "1", "bs");
+assertEquals(2, true + true, "bs");
+
+assertEquals("1true", "1" + new Boolean(true), "sB");
+assertEquals("true1", new Boolean(true) + "1", "Bs");
+assertEquals(2, new Boolean(true) + new Boolean(true), "Bs");
+
+assertEquals("1undefined", "1" + void 0, "sv");
+assertEquals("undefined1", (void 0)  + "1", "vs");
+assertTrue(isNaN(void 0 + void 0), "vv");
+
+assertEquals("1null", "1" + null, "su");
+assertEquals("null1", null + "1", "us");
+assertEquals(0, null + null, "uu");
+
+(function (i) {
+  // Check that incoming frames are merged correctly.
+  var x;
+  var y;
+  var z;
+  var w;
+  switch (i) {
+  case 1: x = 42; y = "stry"; z = "strz"; w = 42; break;
+  default: x = "strx", y = 42; z = "strz"; w = 42; break;
+  }
+  var resxx = x + x;
+  var resxy = x + y;
+  var resxz = x + z;
+  var resxw = x + w;
+  var resyx = y + x;
+  var resyy = y + y;
+  var resyz = y + z;
+  var resyw = y + w;
+  var reszx = z + x;
+  var reszy = z + y;
+  var reszz = z + z;
+  var reszw = z + w;
+  var reswx = w + x;
+  var reswy = w + y;
+  var reswz = w + z;
+  var resww = w + w;
+  assertEquals(84, resxx, "swxx");
+  assertEquals("42stry", resxy, "swxy");
+  assertEquals("42strz", resxz, "swxz");
+  assertEquals(84, resxw, "swxw");
+  assertEquals("stry42", resyx, "swyx");
+  assertEquals("strystry", resyy, "swyy");
+  assertEquals("strystrz", resyz, "swyz");
+  assertEquals("stry42", resyw, "swyw");
+  assertEquals("strz42", reszx, "swzx");
+  assertEquals("strzstry", reszy, "swzy");
+  assertEquals("strzstrz", reszz, "swzz");
+  assertEquals("strz42", reszw, "swzw");
+  assertEquals(84, reswx, "swwx");
+  assertEquals("42stry", reswy, "swwy");
+  assertEquals("42strz", reswz, "swwz");
+  assertEquals(84, resww, "swww");
+})(1);
+
+// Generate ascii and non ascii strings from length 0 to 20.
+var ascii = 'aaaaaaaaaaaaaaaaaaaa';
+var non_ascii = '\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234';
+assertEquals(20, ascii.length);
+assertEquals(20, non_ascii.length);
+var a = Array(21);
+var b = Array(21);
+for (var i = 0; i <= 20; i++) {
+  a[i] = ascii.substring(0, i);
+  b[i] = non_ascii.substring(0, i);
+}
+
+// Add ascii and non-ascii strings generating strings with length from 0 to 20.
+for (var i = 0; i <= 20; i++) {
+  for (var j = 0; j < i; j++) {
+    assertEquals(a[i], a[j] + a[i - j])
+    assertEquals(b[i], b[j] + b[i - j])
+  }
+}
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Nov 5 09:54:59 2013 UTC +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Nov 12 10:21:08 2013 UTC
@@ -300,6 +300,17 @@
   descriptor->deoptimization_handler_ =
       FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
 }
+
+
+void NewStringAddStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { r1, r0 };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kStringAdd)->entry;
+}


 #define __ ACCESS_MASM(masm)
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Nov 8 13:44:27 2013 UTC +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue Nov 12 10:21:08 2013 UTC
@@ -3705,11 +3705,21 @@
 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(2, args->length());
-  VisitForStackValue(args->at(0));
-  VisitForStackValue(args->at(1));

-  StringAddStub stub(STRING_ADD_CHECK_BOTH);
-  __ CallStub(&stub);
+  if (FLAG_new_string_add) {
+    VisitForStackValue(args->at(0));
+    VisitForAccumulatorValue(args->at(1));
+
+    __ pop(r1);
+    NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
+    __ CallStub(&stub);
+  } else {
+    VisitForStackValue(args->at(0));
+    VisitForStackValue(args->at(1));
+
+    StringAddStub stub(STRING_ADD_CHECK_BOTH);
+    __ CallStub(&stub);
+  }
   context()->Plug(r0);
 }

=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Fri Nov 8 14:16:34 2013 UTC +++ /branches/bleeding_edge/src/arm/lithium-arm.cc Tue Nov 12 10:21:08 2013 UTC
@@ -2413,8 +2413,12 @@

 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
   LOperand* context = UseFixed(instr->context(), cp);
-  LOperand* left = UseRegisterAtStart(instr->left());
-  LOperand* right = UseRegisterAtStart(instr->right());
+  LOperand* left = FLAG_new_string_add
+      ? UseFixed(instr->left(), r1)
+      : UseRegisterAtStart(instr->left());
+  LOperand* right = FLAG_new_string_add
+      ? UseFixed(instr->right(), r0)
+      : UseRegisterAtStart(instr->right());
   return MarkAsCall(
       DefineFixed(new(zone()) LStringAdd(context, left, right), r0),
       instr);
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Nov 8 17:35:58 2013 UTC +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Nov 12 10:21:08 2013 UTC
@@ -4562,10 +4562,18 @@

 void LCodeGen::DoStringAdd(LStringAdd* instr) {
   ASSERT(ToRegister(instr->context()).is(cp));
-  __ push(ToRegister(instr->left()));
-  __ push(ToRegister(instr->right()));
-  StringAddStub stub(instr->hydrogen()->flags());
-  CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  if (FLAG_new_string_add) {
+    ASSERT(ToRegister(instr->left()).is(r1));
+    ASSERT(ToRegister(instr->right()).is(r0));
+    NewStringAddStub stub(instr->hydrogen()->flags(),
+                          isolate()->heap()->GetPretenureMode());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  } else {
+    __ push(ToRegister(instr->left()));
+    __ push(ToRegister(instr->right()));
+    StringAddStub stub(instr->hydrogen()->flags());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  }
 }


=======================================
--- /branches/bleeding_edge/src/code-stubs-hydrogen.cc Wed Nov 6 15:47:05 2013 UTC +++ /branches/bleeding_edge/src/code-stubs-hydrogen.cc Tue Nov 12 10:21:08 2013 UTC
@@ -969,6 +969,38 @@
 Handle<Code> BinaryOpStub::GenerateCode(Isolate* isolate) {
   return DoGenerateCode(isolate, this);
 }
+
+
+template <>
+HValue* CodeStubGraphBuilder<NewStringAddStub>::BuildCodeInitializedStub() {
+  NewStringAddStub* stub = casted_stub();
+  StringAddFlags flags = stub->flags();
+  PretenureFlag pretenure_flag = stub->pretenure_flag();
+
+  HValue* left = GetParameter(NewStringAddStub::kLeft);
+  HValue* right = GetParameter(NewStringAddStub::kRight);
+
+  // Make sure that both arguments are strings if not known in advance.
+  if ((flags & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
+    IfBuilder if_leftnotstring(this);
+    if_leftnotstring.IfNot<HIsStringAndBranch>(left);
+    if_leftnotstring.Then();
+    if_leftnotstring.Deopt("Expected string for LHS of string addition");
+  }
+  if ((flags & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
+    IfBuilder if_rightnotstring(this);
+    if_rightnotstring.IfNot<HIsStringAndBranch>(right);
+    if_rightnotstring.Then();
+    if_rightnotstring.Deopt("Expected string for RHS of string addition");
+  }
+
+  return BuildStringAdd(left, right, pretenure_flag);
+}
+
+
+Handle<Code> NewStringAddStub::GenerateCode(Isolate* isolate) {
+  return DoGenerateCode(isolate, this);
+}


 template <>
=======================================
--- /branches/bleeding_edge/src/code-stubs.cc   Thu Nov  7 16:35:27 2013 UTC
+++ /branches/bleeding_edge/src/code-stubs.cc   Tue Nov 12 10:21:08 2013 UTC
@@ -680,6 +680,21 @@
   }
   return StateToType(result_state_, isolate);
 }
+
+
+void NewStringAddStub::PrintBaseName(StringStream* stream) {
+  stream->Add("NewStringAddStub");
+  if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
+    stream->Add("_CheckBoth");
+  } else if ((flags() & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
+    stream->Add("_CheckLeft");
+ } else if ((flags() & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
+    stream->Add("_CheckRight");
+  }
+  if (pretenure_flag() == TENURED) {
+    stream->Add("_Tenured");
+  }
+}


 InlineCacheState ICCompareStub::GetICState() {
@@ -1132,6 +1147,13 @@
   FastNewClosureStub stub(STRICT_MODE, false);
   InstallDescriptor(isolate, &stub);
 }
+
+
+// static
+void NewStringAddStub::InstallDescriptors(Isolate* isolate) {
+  NewStringAddStub stub(STRING_ADD_CHECK_NONE, NOT_TENURED);
+  InstallDescriptor(isolate, &stub);
+}


 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Thu Nov  7 10:17:13 2013 UTC
+++ /branches/bleeding_edge/src/code-stubs.h    Tue Nov 12 10:21:08 2013 UTC
@@ -43,6 +43,7 @@
   V(CallConstruct)                       \
   V(BinaryOp)                            \
   V(StringAdd)                           \
+  V(NewStringAdd)                        \
   V(SubString)                           \
   V(StringCompare)                       \
   V(Compare)                             \
@@ -1179,6 +1180,47 @@
 };


+// TODO(bmeurer): Rename to StringAddStub once we dropped the old StringAddStub.
+class NewStringAddStub V8_FINAL : public HydrogenCodeStub {
+ public:
+  NewStringAddStub(StringAddFlags flags, PretenureFlag pretenure_flag)
+      : bit_field_(StringAddFlagsBits::encode(flags) |
+                   PretenureFlagBits::encode(pretenure_flag)) {}
+
+  StringAddFlags flags() const {
+    return StringAddFlagsBits::decode(bit_field_);
+  }
+
+  PretenureFlag pretenure_flag() const {
+    return PretenureFlagBits::decode(bit_field_);
+  }
+
+  virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
+
+  virtual void InitializeInterfaceDescriptor(
+      Isolate* isolate,
+      CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE;
+
+  static void InstallDescriptors(Isolate* isolate);
+
+  // Parameters accessed via CodeStubGraphBuilder::GetParameter()
+  static const int kLeft = 0;
+  static const int kRight = 1;
+
+ private:
+  class StringAddFlagsBits: public BitField<StringAddFlags, 0, 2> {};
+  class PretenureFlagBits: public BitField<PretenureFlag, 2, 1> {};
+  uint32_t bit_field_;
+
+  virtual Major MajorKey() V8_OVERRIDE { return NewStringAdd; }
+  virtual int NotMissMinorKey() V8_OVERRIDE { return bit_field_; }
+
+  virtual void PrintBaseName(StringStream* stream) V8_OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(NewStringAddStub);
+};
+
+
 class ICCompareStub: public PlatformCodeStub {
  public:
   ICCompareStub(Token::Value op,
=======================================
--- /branches/bleeding_edge/src/flag-definitions.h Thu Nov 7 16:35:27 2013 UTC +++ /branches/bleeding_edge/src/flag-definitions.h Tue Nov 12 10:21:08 2013 UTC
@@ -338,6 +338,8 @@
"do not emit check maps for constant values that have a leaf map, " "deoptimize the optimized code if the layout of the maps changes.")

+DEFINE_bool(new_string_add, false, "enable new string addition")
+
 // Experimental profiler changes.
 DEFINE_bool(experimental_profiler, true, "enable all profiler experiments")
 DEFINE_bool(watch_ic_patching, false, "profiler considers IC stability")
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Fri Nov 8 17:35:58 2013 UTC +++ /branches/bleeding_edge/src/hydrogen-instructions.h Tue Nov 12 10:21:08 2013 UTC
@@ -5807,6 +5807,12 @@
         FixedArray::kLengthOffset,
FLAG_track_fields ? Representation::Smi() : Representation::Tagged());
   }
+
+  static HObjectAccess ForStringHashField() {
+    return HObjectAccess(kInobject,
+                         String::kHashFieldOffset,
+                         Representation::Integer32());
+  }

   static HObjectAccess ForStringLength() {
     STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
@@ -5815,6 +5821,14 @@
         String::kLengthOffset,
FLAG_track_fields ? Representation::Smi() : Representation::Tagged());
   }
+
+  static HObjectAccess ForConsStringFirst() {
+    return HObjectAccess(kInobject, ConsString::kFirstOffset);
+  }
+
+  static HObjectAccess ForConsStringSecond() {
+    return HObjectAccess(kInobject, ConsString::kSecondOffset);
+  }

   static HObjectAccess ForPropertiesPointer() {
     return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
@@ -5862,6 +5876,12 @@
                          Map::kInstanceSizeOffset,
                          Representation::UInteger8());
   }
+
+  static HObjectAccess ForMapInstanceType() {
+    return HObjectAccess(kInobject,
+                         Map::kInstanceTypeOffset,
+                         Representation::UInteger8());
+  }

   static HObjectAccess ForPropertyCellValue() {
     return HObjectAccess(kInobject, PropertyCell::kValueOffset);
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Fri Nov  8 14:16:34 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc     Tue Nov 12 10:21:08 2013 UTC
@@ -1467,6 +1467,342 @@

   return Pop();
 }
+
+
+HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length,
+                                             String::Encoding encoding) {
+  STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
+  HValue* size = length;
+  if (encoding == String::TWO_BYTE_ENCODING) {
+    size = Add<HShl>(length, graph()->GetConstant1());
+    size->ClearFlag(HValue::kCanOverflow);
+    size->SetFlag(HValue::kUint32);
+  }
+  size = Add<HAdd>(size, Add<HConstant>(static_cast<int32_t>(
+              SeqString::kHeaderSize + kObjectAlignmentMask)));
+  size->ClearFlag(HValue::kCanOverflow);
+  size = Add<HBitwise>(
+      Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
+              ~kObjectAlignmentMask)));
+  return size;
+}
+
+
+void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
+                                            HValue* src_offset,
+                                            String::Encoding src_encoding,
+                                            HValue* dst,
+                                            HValue* dst_offset,
+                                            String::Encoding dst_encoding,
+                                            HValue* length) {
+  ASSERT(dst_encoding != String::ONE_BYTE_ENCODING ||
+         src_encoding == String::ONE_BYTE_ENCODING);
+  LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
+ HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
+  {
+    HValue* src_index = Add<HAdd>(src_offset, index);
+    HValue* value = Add<HSeqStringGetChar>(src_encoding, src, src_index);
+    HValue* dst_index = Add<HAdd>(dst_offset, index);
+    Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value);
+  }
+  loop.EndBody();
+}
+
+
+HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left,
+                                               HValue* right,
+ PretenureFlag pretenure_flag) {
+  // Determine the string lengths.
+  HValue* left_length = Add<HLoadNamedField>(
+      left, HObjectAccess::ForStringLength());
+  HValue* right_length = Add<HLoadNamedField>(
+      right, HObjectAccess::ForStringLength());
+
+ // Check if we concatenated the strings here, or if we have to resort to the
+  // runtime function.
+  HIfContinuation handled(graph()->CreateBasicBlock(),
+                          graph()->CreateBasicBlock());
+
+ // Check if both parameters do not exceed half the max string length, because + // exceptionally long strings should be handled in the runtime. Unfortunately
+  // we cannot actually check whether the combined length of both strings
+  // exceeds String::kMaxLength (because of unclear results from the
+  // representation inference phase), so we use a pessimistic approach here
+ // instead, checking that the length of either substring does not exceed half
+  // of String::kMaxLength.
+  HConstant* max_length = Add<HConstant>(String::kMaxLength / 2);
+  IfBuilder if_nooverflow(this);
+  if_nooverflow.If<HCompareNumericAndBranch>(
+      left_length, max_length, Token::LTE);
+  if_nooverflow.AndIf<HCompareNumericAndBranch>(
+      right_length, max_length, Token::LTE);
+  if_nooverflow.Then();
+  {
+    // Determine the string instance types.
+    HLoadNamedField* left_instance_type = Add<HLoadNamedField>(
+        Add<HLoadNamedField>(left, HObjectAccess::ForMap()),
+        HObjectAccess::ForMapInstanceType());
+    HLoadNamedField* right_instance_type = Add<HLoadNamedField>(
+        Add<HLoadNamedField>(right, HObjectAccess::ForMap()),
+        HObjectAccess::ForMapInstanceType());
+
+    // Compute difference of instance types.
+    HValue* xored_instance_types = Add<HBitwise>(
+        Token::BIT_XOR, left_instance_type, right_instance_type);
+
+    // Compute the length of the resulting string.
+    HValue* length = Add<HAdd>(left_length, right_length);
+
+    // Check if we should create a cons string.
+    IfBuilder if_createcons(this);
+    if_createcons.If<HCompareNumericAndBranch>(
+        length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
+    if_createcons.Then();
+    {
+ // Allocate the cons string object. HAllocate does not care whether we + // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use
+      // CONS_STRING_TYPE here. Below we decide whether the cons string is
+      // one-byte or two-byte and set the appropriate map.
+      HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize),
+                                         HType::String(), pretenure_flag,
+                                         CONS_STRING_TYPE);
+
+      // Compute the intersection of instance types.
+      HValue* anded_instance_types = Add<HBitwise>(
+          Token::BIT_AND, left_instance_type, right_instance_type);
+
+      // We create a one-byte cons string if
+      // 1. both strings are one-byte, or
+ // 2. at least one of the strings is two-byte, but happens to contain only
+      //    one-byte characters.
+      // To do this, we check
+ // 1. if both strings are one-byte, or if the one-byte data hint is set in
+      //    both strings, or
+ // 2. if one of the strings has the one-byte data hint set and the other
+      //    string is one-byte.
+      IfBuilder if_onebyte(this);
+      STATIC_ASSERT(kOneByteStringTag != 0);
+      STATIC_ASSERT(kOneByteDataHintMask != 0);
+      if_onebyte.If<HCompareNumericAndBranch>(
+          Add<HBitwise>(
+              Token::BIT_AND, anded_instance_types,
+              Add<HConstant>(static_cast<int32_t>(
+                      kStringEncodingMask | kOneByteDataHintMask))),
+          graph()->GetConstant0(), Token::NE);
+      if_onebyte.Or();
+      STATIC_ASSERT(kOneByteStringTag != 0 &&
+                    kOneByteDataHintTag != 0 &&
+                    kOneByteDataHintTag != kOneByteStringTag);
+      if_onebyte.If<HCompareNumericAndBranch>(
+          Add<HBitwise>(
+              Token::BIT_AND, xored_instance_types,
+              Add<HConstant>(static_cast<int32_t>(
+                      kOneByteStringTag | kOneByteDataHintTag))),
+          Add<HConstant>(static_cast<int32_t>(
+                  kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
+      if_onebyte.Then();
+      {
+        // We can safely skip the write barrier for storing the map here.
+        Handle<Map> map = isolate()->factory()->cons_ascii_string_map();
+        AddStoreMapConstantNoWriteBarrier(string, map);
+      }
+      if_onebyte.Else();
+      {
+        // We can safely skip the write barrier for storing the map here.
+        Handle<Map> map = isolate()->factory()->cons_string_map();
+        AddStoreMapConstantNoWriteBarrier(string, map);
+      }
+      if_onebyte.End();
+
+      // Initialize the cons string fields.
+      Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
+                            Add<HConstant>(String::kEmptyHashField));
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length); + Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left);
+      Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(),
+                            right);
+
+      // Cons string is result.
+      Push(string);
+    }
+    if_createcons.Else();
+    {
+      // Compute union of instance types.
+      HValue* ored_instance_types = Add<HBitwise>(
+          Token::BIT_OR, left_instance_type, right_instance_type);
+
+      // Check if both strings have the same encoding and both are
+      // sequential.
+      IfBuilder if_sameencodingandsequential(this);
+      if_sameencodingandsequential.If<HCompareNumericAndBranch>(
+          Add<HBitwise>(
+              Token::BIT_AND, xored_instance_types,
+              Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
+          graph()->GetConstant0(), Token::EQ);
+      if_sameencodingandsequential.And();
+      STATIC_ASSERT(kSeqStringTag == 0);
+      if_sameencodingandsequential.If<HCompareNumericAndBranch>(
+          Add<HBitwise>(
+              Token::BIT_AND, ored_instance_types,
+ Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))),
+          graph()->GetConstant0(), Token::EQ);
+      if_sameencodingandsequential.Then();
+      {
+        // Check if the result is a one-byte string.
+        IfBuilder if_onebyte(this);
+        STATIC_ASSERT(kOneByteStringTag != 0);
+        if_onebyte.If<HCompareNumericAndBranch>(
+            Add<HBitwise>(
+                Token::BIT_AND, ored_instance_types,
+                Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
+            graph()->GetConstant0(), Token::NE);
+        if_onebyte.Then();
+        {
+          // Calculate the number of bytes needed for the characters in the
+          // string while observing object alignment.
+          HValue* size = BuildSeqStringSizeFor(
+              length, String::ONE_BYTE_ENCODING);
+
+          // Allocate the ASCII string object.
+          Handle<Map> map = isolate()->factory()->ascii_string_map();
+          HAllocate* string = Add<HAllocate>(size, HType::String(),
+ pretenure_flag, ASCII_STRING_TYPE);
+          string->set_known_initial_map(map);
+
+          // We can safely skip the write barrier for storing map here.
+          AddStoreMapConstantNoWriteBarrier(string, map);
+
+          // Copy bytes from the left string.
+          BuildCopySeqStringChars(
+              left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+              string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+              left_length);
+
+          // Copy bytes from the right string.
+          BuildCopySeqStringChars(
+              right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+              string, left_length, String::ONE_BYTE_ENCODING,
+              right_length);
+
+          // Return the string.
+          Push(string);
+        }
+        if_onebyte.Else();
+        {
+          // Calculate the number of bytes needed for the characters in the
+          // string while observing object alignment.
+          HValue* size = BuildSeqStringSizeFor(
+              length, String::TWO_BYTE_ENCODING);
+
+          // Allocate the two-byte string object.
+          Handle<Map> map = isolate()->factory()->string_map();
+          HAllocate* string = Add<HAllocate>(size, HType::String(),
+                                             pretenure_flag, STRING_TYPE);
+          string->set_known_initial_map(map);
+
+          // We can safely skip the write barrier for storing map here.
+          AddStoreMapConstantNoWriteBarrier(string, map);
+
+          // Copy bytes from the left string.
+          BuildCopySeqStringChars(
+              left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+              string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+              left_length);
+
+          // Copy bytes from the right string.
+          BuildCopySeqStringChars(
+              right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+              string, left_length, String::TWO_BYTE_ENCODING,
+              right_length);
+
+          // Return the string.
+          Push(string);
+        }
+        if_onebyte.End();
+
+        // Initialize the (common) string fields.
+        HValue* string = Pop();
+        Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
+                              Add<HConstant>(String::kEmptyHashField));
+        Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+                              length);
+        Push(string);
+      }
+      if_sameencodingandsequential.JoinContinuation(&handled);
+    }
+    if_createcons.JoinContinuation(&handled);
+  }
+  if_nooverflow.JoinContinuation(&handled);
+
+ // Check if the strings were concatenated successfully, otherwise fallback to
+  // add the strings in the runtime.
+  IfBuilder if_handled(this, &handled);
+  if_handled.Then();
+  {
+    // Count the native string addition.
+    AddIncrementCounter(isolate()->counters()->string_add_native());
+  }
+  if_handled.Else();
+  {
+    // Fallback to the runtime to add the two strings.
+    Add<HPushArgument>(left);
+    Add<HPushArgument>(right);
+    Push(Add<HCallRuntime>(isolate()->factory()->empty_string(),
+                           Runtime::FunctionForId(Runtime::kStringAdd),
+                           2));
+  }
+  if_handled.End();
+
+  return Pop();
+}
+
+
+HValue* HGraphBuilder::BuildStringAdd(HValue* left,
+                                      HValue* right,
+                                      PretenureFlag pretenure_flag) {
+  // Determine the string lengths.
+  HValue* left_length = Add<HLoadNamedField>(
+      left, HObjectAccess::ForStringLength());
+  HValue* right_length = Add<HLoadNamedField>(
+      right, HObjectAccess::ForStringLength());
+
+  // Check if left string is empty.
+  IfBuilder if_leftisempty(this);
+  if_leftisempty.If<HCompareNumericAndBranch>(
+      left_length, graph()->GetConstant0(), Token::EQ);
+  if_leftisempty.Then();
+  {
+    // Count the native string addition.
+    AddIncrementCounter(isolate()->counters()->string_add_native());
+
+    // Just return the right string.
+    Push(right);
+  }
+  if_leftisempty.Else();
+  {
+    // Check if right string is empty.
+    IfBuilder if_rightisempty(this);
+    if_rightisempty.If<HCompareNumericAndBranch>(
+        right_length, graph()->GetConstant0(), Token::EQ);
+    if_rightisempty.Then();
+    {
+      // Count the native string addition.
+      AddIncrementCounter(isolate()->counters()->string_add_native());
+
+      // Just return the left string.
+      Push(left);
+    }
+    if_rightisempty.Else();
+    {
+      // Concatenate the two non-empty strings.
+      Push(BuildUncheckedStringAdd(left, right, pretenure_flag));
+    }
+    if_rightisempty.End();
+  }
+  if_leftisempty.End();
+
+  return Pop();
+}


 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Fri Nov  8 14:16:34 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.h      Tue Nov 12 10:21:08 2013 UTC
@@ -1276,6 +1276,26 @@

   HValue* BuildNumberToString(HValue* object, Handle<Type> type);

+ // Computes the size for a sequential string of the given length and encoding.
+  HValue* BuildSeqStringSizeFor(HValue* length,
+                                String::Encoding encoding);
+  // Copies characters from one sequential string to another.
+  void BuildCopySeqStringChars(HValue* src,
+                               HValue* src_offset,
+                               String::Encoding src_encoding,
+                               HValue* dst,
+                               HValue* dst_offset,
+                               String::Encoding dst_encoding,
+                               HValue* length);
+  // Both operands are non-empty strings.
+  HValue* BuildUncheckedStringAdd(HValue* left,
+                                  HValue* right,
+                                  PretenureFlag pretenure_flag);
+  // Both operands are strings.
+  HValue* BuildStringAdd(HValue* left,
+                         HValue* right,
+                         PretenureFlag pretenure_flag);
+
   HInstruction* BuildUncheckedMonomorphicElementAccess(
       HValue* checked_object,
       HValue* key,
@@ -1298,7 +1318,13 @@
HLoadNamedField* BuildLoadNamedField(HValue* object, HObjectAccess access);
   HInstruction* AddLoadNamedField(HValue* object, HObjectAccess access);
HInstruction* BuildLoadStringLength(HValue* object, HValue* checked_value);
-  HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map>);
+  HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map);
+  HStoreNamedField* AddStoreMapConstantNoWriteBarrier(HValue* object,
+                                                      Handle<Map> map) {
+    HStoreNamedField* store_map = AddStoreMapConstant(object, map);
+    store_map->SkipWriteBarrier();
+    return store_map;
+  }
   HLoadNamedField* AddLoadElements(HValue* object);

   bool MatchRotateRight(HValue* left,
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Nov 5 09:54:59 2013 UTC +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Nov 12 10:21:08 2013 UTC
@@ -304,6 +304,17 @@
   descriptor->SetMissHandler(
       ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
 }
+
+
+void NewStringAddStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { edx, eax };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kStringAdd)->entry;
+}


 #define __ ACCESS_MASM(masm)
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Nov 8 13:44:27 2013 UTC +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue Nov 12 10:21:08 2013 UTC
@@ -3671,11 +3671,20 @@
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(2, args->length());

-  VisitForStackValue(args->at(0));
-  VisitForStackValue(args->at(1));
+  if (FLAG_new_string_add) {
+    VisitForStackValue(args->at(0));
+    VisitForAccumulatorValue(args->at(1));
+
+    __ pop(edx);
+    NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
+    __ CallStub(&stub);
+  } else {
+    VisitForStackValue(args->at(0));
+    VisitForStackValue(args->at(1));

-  StringAddStub stub(STRING_ADD_CHECK_BOTH);
-  __ CallStub(&stub);
+    StringAddStub stub(STRING_ADD_CHECK_BOTH);
+    __ CallStub(&stub);
+  }
   context()->Plug(eax);
 }

=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Nov 8 17:35:58 2013 UTC +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Nov 12 10:21:08 2013 UTC
@@ -4551,6 +4551,10 @@
     if (operand_value->IsRegister()) {
       Register value = ToRegister(operand_value);
       __ Store(value, operand, representation);
+    } else if (representation.IsInteger32()) {
+      Immediate immediate = ToImmediate(operand_value, representation);
+      ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
+      __ mov(operand, immediate);
     } else {
       Handle<Object> handle_value = ToHandle(operand_value);
       ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
@@ -4997,10 +5001,18 @@

 void LCodeGen::DoStringAdd(LStringAdd* instr) {
   ASSERT(ToRegister(instr->context()).is(esi));
-  EmitPushTaggedOperand(instr->left());
-  EmitPushTaggedOperand(instr->right());
-  StringAddStub stub(instr->hydrogen()->flags());
-  CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  if (FLAG_new_string_add) {
+    ASSERT(ToRegister(instr->left()).is(edx));
+    ASSERT(ToRegister(instr->right()).is(eax));
+    NewStringAddStub stub(instr->hydrogen()->flags(),
+                          isolate()->heap()->GetPretenureMode());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  } else {
+    EmitPushTaggedOperand(instr->left());
+    EmitPushTaggedOperand(instr->right());
+    StringAddStub stub(instr->hydrogen()->flags());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  }
 }


=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Fri Nov 8 17:35:58 2013 UTC +++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Tue Nov 12 10:21:08 2013 UTC
@@ -2485,8 +2485,12 @@

 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
   LOperand* context = UseFixed(instr->context(), esi);
-  LOperand* left = UseOrConstantAtStart(instr->left());
-  LOperand* right = UseOrConstantAtStart(instr->right());
+  LOperand* left = FLAG_new_string_add
+      ? UseFixed(instr->left(), edx)
+      : UseOrConstantAtStart(instr->left());
+  LOperand* right = FLAG_new_string_add
+      ? UseFixed(instr->right(), eax)
+      : UseOrConstantAtStart(instr->right());
   LStringAdd* string_add = new(zone()) LStringAdd(context, left, right);
   return MarkAsCall(DefineFixed(string_add, eax), instr);
 }
=======================================
--- /branches/bleeding_edge/src/isolate.cc      Thu Nov  7 16:35:27 2013 UTC
+++ /branches/bleeding_edge/src/isolate.cc      Tue Nov 12 10:21:08 2013 UTC
@@ -2328,6 +2328,7 @@
     InternalArrayConstructorStubBase::InstallDescriptors(this);
     FastNewClosureStub::InstallDescriptors(this);
     NumberToStringStub::InstallDescriptors(this);
+    NewStringAddStub::InstallDescriptors(this);
   }

   if (FLAG_sweeper_threads > 0) {
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Fri Nov 8 10:58:51 2013 UTC +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Tue Nov 12 10:21:08 2013 UTC
@@ -300,6 +300,17 @@
   descriptor->deoptimization_handler_ =
       FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
 }
+
+
+void NewStringAddStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { rdx, rax };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kStringAdd)->entry;
+}


 #define __ ACCESS_MASM(masm)
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Nov 8 13:44:27 2013 UTC +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Tue Nov 12 10:21:08 2013 UTC
@@ -3628,11 +3628,20 @@
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(2, args->length());

-  VisitForStackValue(args->at(0));
-  VisitForStackValue(args->at(1));
+  if (FLAG_new_string_add) {
+    VisitForStackValue(args->at(0));
+    VisitForAccumulatorValue(args->at(1));
+
+    __ pop(rdx);
+    NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
+    __ CallStub(&stub);
+  } else {
+    VisitForStackValue(args->at(0));
+    VisitForStackValue(args->at(1));

-  StringAddStub stub(STRING_ADD_CHECK_BOTH);
-  __ CallStub(&stub);
+    StringAddStub stub(STRING_ADD_CHECK_BOTH);
+    __ CallStub(&stub);
+  }
   context()->Plug(rax);
 }

=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Nov 8 14:16:34 2013 UTC +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Nov 12 10:21:08 2013 UTC
@@ -4077,6 +4077,10 @@
     if (operand_value->IsRegister()) {
       Register value = ToRegister(operand_value);
__ Store(FieldOperand(write_register, offset), value, representation);
+    } else if (representation.IsInteger32()) {
+      int32_t value = ToInteger32(operand_value);
+      ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
+      __ movl(FieldOperand(write_register, offset), Immediate(value));
     } else {
       Handle<Object> handle_value = ToHandle(operand_value);
       ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
@@ -4400,10 +4404,18 @@

 void LCodeGen::DoStringAdd(LStringAdd* instr) {
   ASSERT(ToRegister(instr->context()).is(rsi));
-  EmitPushTaggedOperand(instr->left());
-  EmitPushTaggedOperand(instr->right());
-  StringAddStub stub(instr->hydrogen()->flags());
-  CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  if (FLAG_new_string_add) {
+    ASSERT(ToRegister(instr->left()).is(rdx));
+    ASSERT(ToRegister(instr->right()).is(rax));
+    NewStringAddStub stub(instr->hydrogen()->flags(),
+                          isolate()->heap()->GetPretenureMode());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  } else {
+    EmitPushTaggedOperand(instr->left());
+    EmitPushTaggedOperand(instr->right());
+    StringAddStub stub(instr->hydrogen()->flags());
+    CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
+  }
 }


=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Fri Nov 8 14:16:34 2013 UTC +++ /branches/bleeding_edge/src/x64/lithium-x64.cc Tue Nov 12 10:21:08 2013 UTC
@@ -2339,8 +2339,12 @@

 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
   LOperand* context = UseFixed(instr->context(), rsi);
-  LOperand* left = UseOrConstantAtStart(instr->left());
-  LOperand* right = UseOrConstantAtStart(instr->right());
+  LOperand* left = FLAG_new_string_add
+      ? UseFixed(instr->left(), rdx)
+      : UseOrConstantAtStart(instr->left());
+  LOperand* right = FLAG_new_string_add
+      ? UseFixed(instr->right(), rax)
+      : UseOrConstantAtStart(instr->right());
   return MarkAsCall(
DefineFixed(new(zone()) LStringAdd(context, left, right), rax), instr);
 }

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to