Version 3.0.10

Fixed External::Wrap for 64-bit addresses (issue 1037).

Fixed incorrect .arguments variable proxy handling in the full code generator (issue 1060).

Introduced partial strict mode support.

Changed formatting of recursive error messages to match Firefox and Safari (issue http://crbug.com/70334).

Fixed incorrect rounding for float-to-integer conversions for external array types, which implement the Typed Array spec (issue http://crbug.com/50972).

Performance improvements on the IA32 platform.


git-svn-id: http://v8.googlecode.com/svn/trunk@6439 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 2d3eac1..3bfb10f 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -1285,11 +1285,11 @@
 
   NearLabel done;
   Condition cc = TokenToCondition(instr->op(), instr->is_double());
-  __ mov(ToRegister(result), Handle<Object>(Heap::true_value()));
+  __ mov(ToRegister(result), Factory::true_value());
   __ j(cc, &done);
 
   __ bind(&unordered);
-  __ mov(ToRegister(result), Handle<Object>(Heap::false_value()));
+  __ mov(ToRegister(result), Factory::false_value());
   __ bind(&done);
 }
 
@@ -1320,10 +1320,10 @@
   Register result = ToRegister(instr->result());
 
   __ cmp(left, Operand(right));
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   NearLabel done;
   __ j(equal, &done);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }
 
@@ -1348,10 +1348,10 @@
 
   __ cmp(reg, Factory::null_value());
   if (instr->is_strict()) {
-    __ mov(result, Handle<Object>(Heap::true_value()));
+    __ mov(result, Factory::true_value());
     NearLabel done;
     __ j(equal, &done);
-    __ mov(result, Handle<Object>(Heap::false_value()));
+    __ mov(result, Factory::false_value());
     __ bind(&done);
   } else {
     NearLabel true_value, false_value, done;
@@ -1368,10 +1368,10 @@
     __ test(scratch, Immediate(1 << Map::kIsUndetectable));
     __ j(not_zero, &true_value);
     __ bind(&false_value);
-    __ mov(result, Handle<Object>(Heap::false_value()));
+    __ mov(result, Factory::false_value());
     __ jmp(&done);
     __ bind(&true_value);
-    __ mov(result, Handle<Object>(Heap::true_value()));
+    __ mov(result, Factory::true_value());
     __ bind(&done);
   }
 }
@@ -1447,11 +1447,11 @@
   __ j(true_cond, &is_true);
 
   __ bind(&is_false);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ jmp(&done);
 
   __ bind(&is_true);
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
 
   __ bind(&done);
 }
@@ -1479,10 +1479,10 @@
 
   ASSERT(instr->hydrogen()->value()->representation().IsTagged());
   __ test(input, Immediate(kSmiTagMask));
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   NearLabel done;
   __ j(zero, &done);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }
 
@@ -1507,7 +1507,6 @@
 }
 
 
-
 static Condition BranchCondition(HHasInstanceType* instr) {
   InstanceType from = instr->from();
   InstanceType to = instr->to();
@@ -1529,10 +1528,10 @@
   __ j(zero, &is_false);
   __ CmpObjectType(input, TestType(instr->hydrogen()), result);
   __ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false);
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   __ jmp(&done);
   __ bind(&is_false);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }
 
@@ -1559,12 +1558,12 @@
   Register result = ToRegister(instr->result());
 
   ASSERT(instr->hydrogen()->value()->representation().IsTagged());
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   __ test(FieldOperand(input, String::kHashFieldOffset),
           Immediate(String::kContainsCachedArrayIndexMask));
   NearLabel done;
   __ j(not_zero, &done);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }
 
@@ -1653,11 +1652,11 @@
   __ j(not_equal, &is_false);
 
   __ bind(&is_true);
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   __ jmp(&done);
 
   __ bind(&is_false);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }
 
@@ -2221,11 +2220,12 @@
 
   Label negative;
   __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
-  // Check the sign of the argument. If the argument is positive,
-  // just return it.
+  // Check the sign of the argument. If the argument is positive, just
+  // return it. We do not need to patch the stack since |input| and
+  // |result| are the same register and |input| will be restored
+  // unchanged by popping safepoint registers.
   __ test(tmp, Immediate(HeapNumber::kSignMask));
   __ j(not_zero, &negative);
-  __ mov(tmp, input_reg);
   __ jmp(&done);
 
   __ bind(&negative);
@@ -2252,14 +2252,25 @@
   __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
   __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
   __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
-
-  __ bind(&done);
   __ mov(Operand(esp, EspIndexForPushAll(input_reg) * kPointerSize), tmp);
 
+  __ bind(&done);
   __ PopSafepointRegisters();
 }
 
 
+void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
+  Register input_reg = ToRegister(instr->InputAt(0));
+  __ test(input_reg, Operand(input_reg));
+  Label is_positive;
+  __ j(not_sign, &is_positive);
+  __ neg(input_reg);
+  __ test(input_reg, Operand(input_reg));
+  DeoptimizeIf(negative, instr->environment());
+  __ bind(&is_positive);
+}
+
+
 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
   // Class for deferred case.
   class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
@@ -2284,31 +2295,15 @@
     __ subsd(scratch, input_reg);
     __ pand(input_reg, scratch);
   } else if (r.IsInteger32()) {
-    Register input_reg = ToRegister(instr->InputAt(0));
-    __ test(input_reg, Operand(input_reg));
-    Label is_positive;
-    __ j(not_sign, &is_positive);
-    __ neg(input_reg);
-    __ test(input_reg, Operand(input_reg));
-    DeoptimizeIf(negative, instr->environment());
-    __ bind(&is_positive);
+    EmitIntegerMathAbs(instr);
   } else {  // Tagged case.
     DeferredMathAbsTaggedHeapNumber* deferred =
         new DeferredMathAbsTaggedHeapNumber(this, instr);
-    Label not_smi;
     Register input_reg = ToRegister(instr->InputAt(0));
     // Smi check.
     __ test(input_reg, Immediate(kSmiTagMask));
     __ j(not_zero, deferred->entry());
-    __ test(input_reg, Operand(input_reg));
-    Label is_positive;
-    __ j(not_sign, &is_positive);
-    __ neg(input_reg);
-
-    __ test(input_reg, Operand(input_reg));
-    DeoptimizeIf(negative, instr->environment());
-
-    __ bind(&is_positive);
+    EmitIntegerMathAbs(instr);
     __ bind(deferred->exit());
   }
 }
@@ -2651,6 +2646,151 @@
 }
 
 
+void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
+  class DeferredStringCharCodeAt: public LDeferredCode {
+   public:
+    DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
+   private:
+    LStringCharCodeAt* instr_;
+  };
+
+  Register string = ToRegister(instr->string());
+  Register index = no_reg;
+  int const_index = -1;
+  if (instr->index()->IsConstantOperand()) {
+    const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+    STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
+    if (!Smi::IsValid(const_index)) {
+      // Guaranteed to be out of bounds because of the assert above.
+      // So the bounds check that must dominate this instruction must
+      // have deoptimized already.
+      if (FLAG_debug_code) {
+        __ Abort("StringCharCodeAt: out of bounds index.");
+      }
+      // No code needs to be generated.
+      return;
+    }
+  } else {
+    index = ToRegister(instr->index());
+  }
+  Register result = ToRegister(instr->result());
+
+  DeferredStringCharCodeAt* deferred =
+      new DeferredStringCharCodeAt(this, instr);
+
+  NearLabel flat_string, ascii_string, done;
+
+  // Fetch the instance type of the receiver into result register.
+  __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
+  __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
+
+  // We need special handling for non-flat strings.
+  STATIC_ASSERT(kSeqStringTag == 0);
+  __ test(result, Immediate(kStringRepresentationMask));
+  __ j(zero, &flat_string);
+
+  // Handle non-flat strings.
+  __ test(result, Immediate(kIsConsStringMask));
+  __ j(zero, deferred->entry());
+
+  // ConsString.
+  // Check whether the right hand side is the empty string (i.e. if
+  // this is really a flat string in a cons string). If that is not
+  // the case we would rather go to the runtime system now to flatten
+  // the string.
+  __ cmp(FieldOperand(string, ConsString::kSecondOffset),
+         Immediate(Factory::empty_string()));
+  __ j(not_equal, deferred->entry());
+  // Get the first of the two strings and load its instance type.
+  __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
+  __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
+  __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
+  // If the first cons component is also non-flat, then go to runtime.
+  STATIC_ASSERT(kSeqStringTag == 0);
+  __ test(result, Immediate(kStringRepresentationMask));
+  __ j(not_zero, deferred->entry());
+
+  // Check for 1-byte or 2-byte string.
+  __ bind(&flat_string);
+  STATIC_ASSERT(kAsciiStringTag != 0);
+  __ test(result, Immediate(kStringEncodingMask));
+  __ j(not_zero, &ascii_string);
+
+  // 2-byte string.
+  // Load the 2-byte character code into the result register.
+  STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
+  if (instr->index()->IsConstantOperand()) {
+    __ movzx_w(result,
+               FieldOperand(string,
+                            SeqTwoByteString::kHeaderSize + 2 * const_index));
+  } else {
+    __ movzx_w(result, FieldOperand(string,
+                                    index,
+                                    times_2,
+                                    SeqTwoByteString::kHeaderSize));
+  }
+  __ jmp(&done);
+
+  // ASCII string.
+  // Load the byte into the result register.
+  __ bind(&ascii_string);
+  if (instr->index()->IsConstantOperand()) {
+    __ movzx_b(result, FieldOperand(string,
+                                    SeqAsciiString::kHeaderSize + const_index));
+  } else {
+    __ movzx_b(result, FieldOperand(string,
+                                    index,
+                                    times_1,
+                                    SeqAsciiString::kHeaderSize));
+  }
+  __ bind(&done);
+  __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
+  Register string = ToRegister(instr->string());
+  Register result = ToRegister(instr->result());
+
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  __ Set(result, Immediate(0));
+
+  __ PushSafepointRegisters();
+  __ push(string);
+  // Push the index as a smi. This is safe because of the checks in
+  // DoStringCharCodeAt above.
+  STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
+  if (instr->index()->IsConstantOperand()) {
+    int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+    __ push(Immediate(Smi::FromInt(const_index)));
+  } else {
+    Register index = ToRegister(instr->index());
+    __ SmiTag(index);
+    __ push(index);
+  }
+  __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt);
+  RecordSafepointWithRegisters(
+      instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex);
+  if (FLAG_debug_code) {
+    __ AbortIfNotSmi(eax);
+  }
+  __ SmiUntag(eax);
+  __ mov(Operand(esp, EspIndexForPushAll(result) * kPointerSize), eax);
+  __ PopSafepointRegisters();
+}
+
+
+void LCodeGen::DoStringLength(LStringLength* instr) {
+  Register string = ToRegister(instr->string());
+  Register result = ToRegister(instr->result());
+  __ mov(result, FieldOperand(string, String::kLengthOffset));
+}
+
+
 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
   LOperand* input = instr->InputAt(0);
   ASSERT(input->IsRegister() || input->IsStackSlot());
@@ -3077,13 +3217,19 @@
   InstanceType last = instr->hydrogen()->last();
 
   __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
-  __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
-          static_cast<int8_t>(first));
 
   // If there is only one type in the interval check for equality.
   if (first == last) {
+    __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
+            static_cast<int8_t>(first));
     DeoptimizeIf(not_equal, instr->environment());
-  } else {
+  } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) {
+    // String has a dedicated bit in instance type.
+    __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), kIsNotStringMask);
+    DeoptimizeIf(not_zero, instr->environment());
+  } else  {
+    __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
+            static_cast<int8_t>(first));
     DeoptimizeIf(below, instr->environment());
     // Omit check for the last type.
     if (last != LAST_TYPE) {
@@ -3292,11 +3438,11 @@
                                                   instr->type_literal());
   __ j(final_branch_condition, &true_label);
   __ bind(&false_label);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ jmp(&done);
 
   __ bind(&true_label);
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
 
   __ bind(&done);
 }
@@ -3341,9 +3487,9 @@
     final_branch_condition = below;
 
   } else if (type_name->Equals(Heap::boolean_symbol())) {
-    __ cmp(input, Handle<Object>(Heap::true_value()));
+    __ cmp(input, Factory::true_value());
     __ j(equal, true_label);
-    __ cmp(input, Handle<Object>(Heap::false_value()));
+    __ cmp(input, Factory::false_value());
     final_branch_condition = equal;
 
   } else if (type_name->Equals(Heap::undefined_symbol())) {